java编程基础之网络编程(代码片段)

Ocean:) Ocean:)     2022-12-18     294

关键词:

网络编程

概述

C/S和B/S

网络通信协议

协议:protocol

网络通信协议市要求双方传递数据的计算机必须遵守的,按照对应的网络传输协议,才可以进入数据的交互和传递

常见协议:

  • UDP

    面向无连接,不可靠数据传输存在丢包

    传输速度快

    没有客户端和服务器区别,都可以作为发送端和接收端

    使用场景:直播,网络游戏

  • TCP/IP

    面向连接

    可靠数据传输,稳定

    有明确服务器和客户端概念

    使用场景:数据下载,文件传输

网络编程要素

  1. 协议

    两个计算机之间数据传输,需要对应的协议来完成

  2. IP地址

    Internet Protocol Address

    当前计算机在网络中的一个地址编号,类似于手机号码

    IP地址有IPv4和IPv6两种格式

  3. 端口号

    端口号是当前应用程序在计算机中的一个编号,是计算机明确,当前的数据是给予哪一个程序使用,或者数据从哪一个程序发出

    端口号是一个short类型数据,范围0-65535

    0-1024属于特定的系统端口号,不能自定义使用

IP类

InetAddress

常用方法:

  • InetAddress getLocalhost();

    获取本机IP地址类对象

  • InetAddress getByName(String str);

    根据指定的主机名获取对应的IP地址对象

  • InetAddress[] getAllByName(String str);

    获取指定主机名,或者域名对应的所有IP地址类对象

package cn.ocean888;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Demo1 
	public static void main(String[] args) throws UnknownHostException 
		InetAddress localHost = InetAddress.getLocalHost();
		System.out.println(localHost);
		
		
		InetAddress byNameAddress = InetAddress.getByName("秦的机械革命");
		System.out.println(byNameAddress);
		
		
		InetAddress byNameAddress2 = InetAddress.getByName("www.ocean888.cn");
		System.out.println(byNameAddress2);
		
		
		InetAddress[] byNameAddress3 = InetAddress.getAllByName("www.baidu.com");
		for (InetAddress inetAddress : byNameAddress3) 
			System.out.println(inetAddress);
		
	

UDP协议数据传输

用户数据报协议:User Datagram Protocol

数据传递采用数据包方式传递,所有的数据要进行打包操作,并且没有对应的客户端服务器概念,有且只有发送端和接收端

Socket 套接字

数据在需要进行传递操作时,在数据传递的两台计算机当中必须有对应的Socket,这里采用UDP协议,则必须有一个UDP协议的Socket

DatagramSocket();
	创建一个发送端UDP协议Socket对象
        
DatagramSocket(int port);
	创建一个接收端UDP协议的Socket对象,这里需要监听指定端口     

数据包的打包方法

发送端数据打包方式

DatagramPacket DatagramPacket(byte[] buf, int length, InetAddress address, int port);

/* 	
	buf:需要传递数据的字节数组
	length:当前字节数组中数据容量字节数
	address:接收端IP地址对象
	port:接收端对应的端口号
*/

接收端数据接收方式

需要准备一个空的数据包
DatagramPacket DatagramPacket(byte[] buf, int length);

/*
	buf:字节缓冲数组,通常是1024的整数倍
	length:当前字节缓冲数组的容量
*/	

发送端

步骤:

  1. 创建UDP服务器对应的发送端Socket
  2. 准备对应的数据包,需要带有指定数据
  3. 发送数据 send
  4. 发送 udp 发送端
package cn.ocean888;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class SenderDemo1 
	public static void main(String[] args) throws IOException 
		System.out.println("udp发送端");
		
		// 创建对应的Socket
		DatagramSocket socket = new DatagramSocket();
		
		// 准备数据包
		byte[] bytes = "ocean".getBytes();
		DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 8848);
				
		// 发送数据包
		socket.send(packet);
		
		// 关闭udp发送端
		socket.close();
	

接收端

步骤:

  1. 打开UDP服务,监听指定端口
  2. 创建新的空数据包
  3. 通过Socket接受数据 receive
  4. 关闭 UDP 接收端
package cn.ocean888;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class ReceiveDemo1 
	public static void main(String[] args) throws IOException
		System.out.println("接收端启动");
		// 创建socket监听端口
		DatagramSocket socket = new DatagramSocket(8848);
		
		// 准备空数据包
		byte[] buf = new byte[1024];
		DatagramPacket packet = new DatagramPacket(buf, buf.length);
		
		// 接收数据
		socket.receive(packet);
		
		// 确定接受到的字节长度
		int length = packet.getLength();
		
		System.out.println(new String(buf, 0, length));
		
		// 关闭socket
		socket.close();
	

需要先启动接收端,监听端口

udp数据传输丢失问题

  1. 网络不好,传输不稳定,带宽不够,数据包丢失
  2. 电脑性能问题

TCP概述

TCP是相对于UDP比较稳定的传输协议,存在三次握手,保证连接状态,同时明确区分客户端和服务端之分

TCP服务中需要服务器端先启动,需要监听指定端口,等待客户端连接

TCP操作:Java中提供了两个Socket

  1. 服务端Socket

    java.net.ServerSocket;

    创建对应的ServerSocket开启服务器,等待客户端连接

  2. 客户端Socket

    java.net.Socket

    创建客户端Socket,并且连接服务器,同时将Socket发送给服务器绑定注册

tcp 三次握手四次挥手流程图

Socket客户端

给客户端提供的数据传输符合TCP/IP要求的Socket对象

构造方法Constructor
Socket(String host, int port);
	host是服务器IP地址,port对应服务器程序的端口号
        
成员方法Method
InputStream getInputStream();
	获取Socket对象输入字节流,可以从服务器获取对应的数据
    InputStream是一个资源,需要在程序退出时关闭
        
OutputStream getOutputStream();
	获取Socket对象输出字节流,可以发送数据到服务器
	OutputStream是一个资源,需要在程序退出时关闭
        
void close();
	关闭客户端Socket

void shutdownOutput();
	禁止当前Socket发送数据
        
TCP/IP协议对应的Socket是给予IO流实现的        

ServerSocket服务端Socket

在服务器开启Socket服务器

构造方法 Constructor
    ServerSocket(int port);
		开启ServerSocket服务器,并且明确服务端口

成员方法 Method:
	Socket accept();
		监听并且连接,得到一个Socket对象,同时该方法是一个阻塞方法,会始终处于一个监听状态
		返回的是Socket,即客户端Socket对象,获取到当前Socket对象,相当于获取到客户端连接,同时使用Socket和客户端一致

TCP客户端服务端输入输出关系

服务器代码

流程:

  1. 创建ServerSocket服务器,同时监听指定端口
  2. 通过accept方法获取Socket连接,得到客户端Socket对象
  3. 通过Socket对象,获取InputStream,读取客户端发送数据
  4. 通过Socket对象,获取OutputStream,发送数据给客户端
  5. 关闭服务
package cn.ocean888_tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo 
	public static void main(String[] args) throws IOException 
		System.out.println("服务端启动");
		
		
		// 1.创建ServerSocket服务器,同时监听指定端口
		ServerSocket serverSocket = new ServerSocket(8888);
		
		
		// 2.通过accept方法获取Socket连接,得到客户端Socket对象
		Socket socket = serverSocket.accept();
		
		
		// 3.通过Socket对象,获取InputStream,读取客户端发送的数据
		InputStream inputStream = socket.getInputStream();
		
		
		// IO流操作
		byte[] buf = new byte[1024];
		int length = inputStream.read(buf);
		System.out.println(new String(buf, 0, length));
		
		
		// 4.通过Socket对象,获取OutputStream,发送数据给客户端
		OutputStream outputStream = socket.getOutputStream();
		String str = "ocean";
		outputStream.write(str.getBytes());
		
		
		// 5.关闭Socket服务同时关闭当前Socket使用的输入字节流和输出字节流
		// Closing this socket will also close the socket's InputStream and OutputStream
		socket.close();
	

客户端代码

流程:

  1. 创建Socket服务,同时明确连接服务器的IP地址和对应端口号
  2. 通过Socket对象,获取对应的OutputStream,发送数据给服务器
  3. 通过Socket对象,获取对应的InputStream,接收服务器发送数据
  4. 关闭连接
package cn.ocean888_tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class ClientDemo 
	public static void main(String[] args) throws UnknownHostException, IOException 
		System.out.println("客户端启动");
		
		
		// 1.创建Socket服务,同时明确连接服务器的IP地址和对应端口号
		Socket socket = new Socket("169.254.252.105", 8888);
		
		
		// 2.通过Socket对象,获取对应的OutputStream对象,发送数据给服务器
		OutputStream outputStream = socket.getOutputStream();
		outputStream.write("client connect".getBytes());
		
		// 3.通过Socket对象,获取对应的InputStream对象,接收服务器发送数据
		InputStream inputStream = socket.getInputStream();
		
		
		byte[] buf = new byte[1024];
		int length = inputStream.read(buf);
		System.out.println(new String(buf, 0, length));
		
		
		// 4.关闭服务
		socket.close();
	

需要首先启动服务端

文件上传实现

客户端

流程:

  1. 创建对应的文件输入字节流操作,可以使用缓存
  2. 启动Socket
  3. 获取Socket输出OutputStream对象,发送数据给服务器
  4. 边读边发
  5. 文件读取结束,发送完毕,关闭客户端
package cn.ocean888_tcp;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class FileClient 
	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException 
		// 1.创建缓冲流
		BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(new File("D:\\\\JavaCode\\\\test\\\\test.jpg")));
		
		// 2.创建socket
		Socket socket = new Socket(InetAddress.getLocalHost(), 8848);
		
		// 3.获取socket输出流
		OutputStream outputStream = socket.getOutputStream();
		
		int length = -1;
		byte[] buf = new byte[1024 * 8];
		
		// 4.读取数据,发送输出,边读边发
		while ((length = bufferedInputStream.read(buf)) != -1) 
			outputStream.write(buf, 0, length);
		
		
		// 5.关闭连接
		socket.close();
	

服务端

流程:

  1. 开启服务端,创建ServerSocket服务
  2. 明确文件保存位置,创建对应文件夹的输出缓冲字节流
  3. 读取数据,写入文件
  4. 关闭服务端
package cn.ocean888_tcp;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class FileServer 
	public static void main(String[] args) throws IOException 
		// 1.开启服务端,创建ServerSocket对象
		ServerSocket serverSocket = new ServerSocket(8848);
		
		Socket socket = serverSocket.accept();
		
		// 2.明确保存文件位置,创建对应文件夹缓冲字节流
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("D:\\\\JavaCode\\\\test\\\\copy.jpg")));
		
		// 3.获取Socket对应的输入流
		InputStream inputStream = socket.getInputStream();
		
		// 4.边读边写
		int length = -1;
		byte[] buf = new byte[1024 * 8];
		
		while((length = inputStream.read(buf)) != -1) 
			bos.write(buf, 0, length);
		
		
		// 5.关闭资源
		bos.close();
		socket.close();
	

运行后

多线程版

解决单线程代码问题:

  1. 保存的文件名是一致的,无法保存多个文件

    使用uuid解决

  2. 服务器代码需要执行多个功能在结束

  3. 服务端代码不可能只有一个上传文件功能

    使用多线程

package cn.ocean888_tcp;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpGoodServer 
	public static void main(String[] args) throws IOException 
		System.out.println("服务器代码启动");
		
		// 1.启动TCP服务端服务
		ServerSocket serverSocket = new ServerSocket(8848);
		
		// 2.使用线程池
		ExecutorService tp = Executors.newFixedThreadPool(5);
		
		// 3.循环
		while (true) 
			// 连接客户端
			Socket socket = serverSocket.accept();
			
			tp.submit(() -> 
				try 
					System.out.println(Thread.currentThread().getName());
					InputStream inputStream = socket.getInputStream();
					String fileName = UUID.randomUUID().toString();
					BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("D:\\\\JavaCode\\\\test\\\\" + fileName + ".jpg")));
					
					int length = -1;
					byte[] buf = new byte[1024 * 8];
					
					while ((length = inputStream.read(buf)) != -1) 
						bos.write(buf, 0, length);
					
					
					bos.close();
					socket.close();
				 catch (IOException e) 
					e.printStackTrace();
				
			);
		
	

运行:先启动服务端在启动多个客户

java编程基础之io流(代码片段)

IO流IO流基类InputStream输入流基类readOutputStream输出流基类writeIO流分类流向分类输入输出文件操作处理单元分类字节流和字符流FileInputStream文件操作输入字节流FileOutputStream文件操作输出字节流FileReader文件操作输入字符流FileWriter文... 查看详情

java网络编程编程之tcp编程和udp编程(代码片段)

网络编程基础1.TCP编程1.1网络相关基础概念1.2TCP协议介绍1.3TCP编程案例2.UDP编程2.1UDP协议介绍2.2UDP编程案例1.TCP编程1.1网络相关基础概念我们在学习网络编程前先来复习一下IP地址端口号协议,套接字的相关概念。IP地址:用来... 查看详情

网络编程基础:网络基础之网络协议socket模块(代码片段)

操作系统(简称OS)基础:应用软件不能直接操作硬件,能直接操作硬件的只有操作系统;所以,应用软件可以通过操作系统来间接操作硬件 网络基础之网络协议:网络通讯原理:   连接两台计算机之间的Internet实际... 查看详情

网络编程基础之粘包现象(代码片段)

一、粘包现象原理分析  1、我们先来看几行代码,从现象来分析:    测试程序分为两部分,分别是服务端和客户端    服务端.py 1#!/usr/bin/envpython32#-*-coding:utf-8-*-3#writebycongcong456importsocket78server=socket.socket(family=sock... 查看详情

编程基础之编程语言的区别(代码片段)

...要把高级语言翻译成机器语言。根据翻译的时机,我们将编程语言分为编译型和解释型。编译型语言程序在运行前需要一个专门的编译过程,将程序编译为机器需要的文件,比如说exe文件,以后运行的话就不必再次翻译了例子:... 查看详情

go编程基础之四(代码片段)

 1.数组Array:---定义数组的格式:var <varName> [n] <type> ,n>=0---数组长度也是类型的一部分,因此具有不同长度的数组为不同类型---注意区分指向数组的指针和指针数组---数组在Go中为值类型---数组之间... 查看详情

原创编程基础之ruby(代码片段)

ruby2.6.2官方:https://www.ruby-lang.org/en/ 一简介Adynamic,opensourceprogramminglanguagewithafocusonsimplicityandproductivity.Ithasanelegantsyntaxthatisnaturaltoreadandeasytowrite. Rubyisalanguageofcarefulbalance.Itscreator,Yukihiro“Matz”Matsumoto,blendedpartsofhisfavori... 查看详情

openjudge1.1编程基础之输入输出(代码片段)

01:1#include<iostream>2usingnamespacestd;3intmain()45cout<<"Hello,World!"<<endl;6return0;7ViewCode 02:1#include<iostream>2usingnamespacestd;3intmain()4inta,b,c;5cin> 查看详情

区块链开发之solidity编程基础(代码片段)

Solidy是当前编写智能合约的主流语言概要sol文件结构编译开发引入其他文件注释代码注释文档注释合约状态变量类型值类型1、布尔类型2、整型3、地址4、定长字节数组5、有理数和整型字面量6、枚举类型7、函数类型引用类型1、... 查看详情

go基础之单元测试反射网络编程操作redis操作mysql(代码片段)

Go基础(四)之单元测试、反射、网络编程、操作Redis、操作MySQL一、单元测试二、反射2.1两个重要函数和类型2.2类型(Type)与种类(Kind)2.3通过反射获取值信息2.3.1从反射值对象获取值2.3.2通过反射访问结... 查看详情

java之函数编程(代码片段)

前言    本系列文章为在《告别996,开启Java高效编程之门》学习过程中的学习笔记和课外资料补充,希望可以方便自己和其他需要的同学查阅。Lambda表达式简介    ①Java8引入的函数式编程风格;    ②可以理解... 查看详情

网络编程基础之七层协议及tcpudphttpnio解析(代码片段)

前言本篇博客主要介绍的网络编程基础,包括七层协议,TCP和UDP对比特性,Http协议,以及何为Nio编程,有何优缺点,应用场景等,都有一个比较大介绍。OSI网络七层模型为了不同的厂家的计算机可以通... 查看详情

并发编程系列之线程基础知识回顾(代码片段)

...础的知识点,帮忙读者入门,注意只是学习并发编程的一些基础点,要系统学习的是需要多看看书籍还是花不少时间整理的。本博客是在参加培训后做的笔记,仅供学习参考问题1、使用多线程的目的是什么?... 查看详情

python基础知识1(代码片段)

 阅读目录一编程与编程语言二编程语言分类三主流编程语言介绍四python介绍五安装python解释器六第一个python程序七变量八用户与程序交互九基本数据类型十格式化输出十一基本运算符十二流程控制之if...else十三流程控制之whi... 查看详情

区块链开发之solidity编程基础合约语句及函数修饰符(代码片段)

Solidity编程基础二概要语句条件语句循环语句修饰符修饰符说明修饰符区别自定义修饰符自定义修饰符扩展public状态变量的getter函数概要本文延续专栏的编程基础一进行学习,本文主要内容讲解Solidity的语句以及修饰符等内容语句... 查看详情

java修炼之道--并发编程(代码片段)

...thub.com/frank-lam/2019_campus_apply前言在本文将总结多线程并发编程中的常见面试题,主要核心线程生命周期、线程通信、并发包部分。主要分成“并发编程”和“面试指南”两部分,在面试指南中将讨论并发相关面经。参考资料:《... 查看详情

go基础之文件操作命令行参数序列化并发编程(代码片段)

...(三)之文件操作、命令行参数、序列化、并发编程一、文件操作1.1打开和关闭文件1.2读取文件1.2.1按字节读取:file.Read()1.2.2bufio按行读取文件1.2.3ioutil读取整个文件1.3文件写入1.3.1Write和WriteString1.3.2bufio.NewWriter1.3.3iout... 查看详情

juc并发编程之completablefuture基础用法(代码片段)

目录实现多线程的四种方式方式一:继承Thread类方式二:实现Runnable接口方式三:实现Callable接口方式四:线程池创建异步对象回调方法handle方法 线程串行化 任务组合组合任务单任务完成及执行实现多线程的四... 查看详情