Java之TCP与UDP

小结:

 UDP程序交互的流程

                发送端

                        1,创建DatagramSocket对象

                        2,创建DatagramPacket对象,并封装数据

                        3,发送数据

                        4,释放流资源

                接收端

                         1,创建DatagramSocket对象(绑定端口号)

                         2,创建DatagramPacket对象

                         3,接收数据存储到DatagramPacket对象中

                         4,获取DatagramPacket对象的内容

                         5,释放流资源

 TCP程序交互的流程

               客户端

                         1,创建客户端的Socket对象

                         2,获取Socket的输出流对象

                         3,写数据给服务器

                         4,获取Socket的输入流对象

                         5,使用输入流,读反馈信息

                         6,关闭流资源

              服务器端

                         1,创建服务器端ServerSocket对象,指定服务器端端口号

                         2,开启服务器,等待着客户端Socket对象的连接,如有客户端连接,返回客户端的Socket对象

                         3,通过客户端的Socket对象,获取客户端的输入流,为了实现获取客户端发来的数据

                         4,通过客户端的输入流,获取流中的数据

                         5,通过客户端的Socket对象,获取客户端的输出流,为了实现给客户端反馈信息

                         6,通过客户端的输出流,写数据到流中

                         7,关闭流资源

UDP协议

     UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。

     由于使用UDP协议消耗资源小通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。

     但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。

TCP协议

    TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。第一次握手,客户端向服务器端发出连接请求,等待服务器确认,第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求,第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示。

由于TCP协议的面向连接特性,它可以保证传输数据的安全性,所以是一个被广泛采用的协议,例如在下载文件时,如果数据接收不完整,将会导致文件数据丢失而不能被打开,因此,下载文件时必须采用TCP协议。

UDP聊天案例

1:UDP完成数据的发送

/*
* 发送端
 * 1,创建DatagramSocket对象
 * 2,创建DatagramPacket对象,并封装数据
 * 3,发送数据
 * 4,释放流资源
 */
public class UDPSend {
	public static void main(String[] args) throws IOException {
		//1,创建DatagramSocket对象
		DatagramSocket sendSocket = new DatagramSocket();
		//2,创建DatagramPacket对象,并封装数据
		//public DatagramPacket(byte[] buf, int length, InetAddress address,  int port)
		//构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
		byte[] buffer = "hello,UDP".getBytes();
		DatagramPacket dp = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("192.168.75.58"), 12306);
		//3,发送数据
		//public void send(DatagramPacket p) 从此套接字发送数据报包
		sendSocket.send(dp);
		//4,释放流资源
		sendSocket.close();
	}
}

2:UDP完成数据的接收

/*
 * UDP接收端
 * 
 * 1,创建DatagramSocket对象
 * 2,创建DatagramPacket对象
 * 3,接收数据存储到DatagramPacket对象中
 * 4,获取DatagramPacket对象的内容
 * 5,释放流资源
 */
public class UDPReceive {
	public static void main(String[] args) throws IOException {
		//1,创建DatagramSocket对象,并指定端口号
		DatagramSocket receiveSocket = new DatagramSocket(12306);
		//2,创建DatagramPacket对象, 创建一个空的仓库
		byte[] buffer = new byte[1024];
		DatagramPacket dp = new DatagramPacket(buffer, 1024);
		//3,接收数据存储到DatagramPacket对象中
		receiveSocket.receive(dp);
		//4,获取DatagramPacket对象的内容
		//谁发来的数据  getAddress()
		InetAddress ipAddress = dp.getAddress();
		String ip = ipAddress.getHostAddress();//获取到了IP地址
		//发来了什么数据  getData()
		byte[] data = dp.getData();
		//发来了多少数据 getLenth()
		int length = dp.getLength();
		//显示收到的数据
		String dataStr = new String(data,0,length);
		System.out.println("IP地址:"+ip+ "数据是"+ dataStr);
		//5,释放流资源
		receiveSocket.close();
	}
}

TCP聊天案例

1:服务器端

/*
 * TCP 服务器端
 * 
 * 1,创建服务器ServerSocket对象(指定服务器端口号)
 * 2,开启服务器了,等待客户端的连接,当客户端连接后,可以获取到连接服务器的客户端Socket对象
 * 3,给客户端反馈信息
 * 4,关闭流资源
 */
public class TCPServer {
	public static void main(String[] args) throws IOException {
		//1,创建服务器ServerSocket对象(指定服务器端口号)
		ServerSocket ss = new ServerSocket(8888);
		//2,开启服务器了,等待客户端的连接,当客户端连接后,可以获取到连接服务器的客户端Socket对象
		Socket s = ss.accept();
		//3,给客户端反馈信息
		/*
		 * a,获取客户端的输出流
		 * b,在服务端端,通过客户端的输出流写数据给客户端
		 */
		//a,获取客户端的输出流
		OutputStream out = s.getOutputStream();
		//b,在服务端端,通过客户端的输出流写数据给客户端
		out.write("你已经连接上了服务器".getBytes());
		//4,关闭流资源
		out.close();
		s.close();
		//ss.close();  服务器流 通常都是不关闭的
	}
}
2:客户端
/*
 * TCP 客户端
 * 
 * 1,创建客户端Socket对象,(指定要连接的服务器地址与端口号)
 * 2,获取服务器端的反馈回来的信息
 * 3,关闭流资源
 */
public class TCPClient {
	public static void main(String[] args) throws IOException {
		//1,创建客户端Socket对象,(指定要连接的服务器地址与端口号)
		Socket s = new Socket("192.168.74.58", 8888);
		//2,获取服务器端的反馈回来的信息
		InputStream in = s.getInputStream();
		//获取获取流中的数据
		byte[] buffer = new byte[1024];
		//把流中的数据存储到数组中,并记录读取字节的个数
		int length = in.read(buffer);
		//显示数据
		System.out.println( new String(buffer, 0 , length) );
		//3,关闭流资源
		in.close();
		s.close();
	}
}
TCP文件上传案例

1:服务器端

/*
 * 文件上传  服务器端
 *
 */
public class TCPServer {
	public static void main(String[] args) throws IOException {
		//1,创建服务器,等待客户端连接
		ServerSocket serverSocket = new ServerSocket(8888);
		Socket clientSocket = serverSocket.accept();
		//显示哪个客户端Socket连接上了服务器
		InetAddress ipObject = clientSocket.getInetAddress();//得到IP地址对象
		String ip = ipObject.getHostAddress(); //得到IP地址字符串
		System.out.println("小样,抓到你了,连接我!!" + "IP:" + ip);
		
		//7,获取Socket的输入流
		InputStream in = clientSocket.getInputStream();
		//8,创建目的地的字节输出流   D:\\upload\\192.168.74.58(1).jpg
		BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\\upload\\192.168.74.58(1).jpg"));
		//9,把Socket输入流中的数据,写入目的地的字节输出流中
		byte[] buffer = new byte[1024];
		int len = -1;
		while((len = in.read(buffer)) != -1){
			//写入目的地的字节输出流中
			fileOut.write(buffer, 0, len);
		}
		
		//-----------------反馈信息---------------------
		//10,获取Socket的输出流, 作用:写反馈信息给客户端
		OutputStream out = clientSocket.getOutputStream();
		//11,写反馈信息给客户端
		out.write("图片上传成功".getBytes());
		
		out.close();
		fileOut.close();
		in.close();
		clientSocket.close();
		//serverSocket.close();
	}
}

(服务器端优化,采用多线程)

/*
 * 文件上传多线程版本, 服务器端
 */
public class TCPServer {
	public static void main(String[] args) throws IOException {
		//1,创建服务器,等待客户端连接
		ServerSocket serverSocket = new ServerSocket(6666);
		
		//实现多个客户端连接服务器的操作
		while(true){
			final Socket clientSocket = serverSocket.accept();
			//启动线程,完成与当前客户端的数据交互过程
			new Thread(){
				public void run() {
					try{
						//显示哪个客户端Socket连接上了服务器
						InetAddress ipObject = clientSocket.getInetAddress();//得到IP地址对象
						String ip = ipObject.getHostAddress(); //得到IP地址字符串
						System.out.println("小样,抓到你了,连接我!!" + "IP:" + ip);
						
						//7,获取Socket的输入流
						InputStream in = clientSocket.getInputStream();
						//8,创建目的地的字节输出流   D:\\upload\\192.168.74.58(1).jpg
						BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\\upload\\"+ip+"("+System.currentTimeMillis()+").jpg"));
						//9,把Socket输入流中的数据,写入目的地的字节输出流中
						byte[] buffer = new byte[1024];
						int len = -1;
						while((len = in.read(buffer)) != -1){
							//写入目的地的字节输出流中
							fileOut.write(buffer, 0, len);
						}
						
						//-----------------反馈信息---------------------
						//10,获取Socket的输出流, 作用:写反馈信息给客户端
						OutputStream out = clientSocket.getOutputStream();
						//11,写反馈信息给客户端
						out.write("图片上传成功".getBytes());
						
						out.close();
						fileOut.close();
						in.close();
						clientSocket.close();
					} catch(IOException e){
						e.printStackTrace();
					}
				};
			}.start();
		}

		//serverSocket.close();
	}
}

2:客户端

/*
 * 文件上传 客户端
 * 
 * public void shutdownOutput()  禁用此Socket的输出流,间接的相当于告知了服务器数据写入完毕
 */
public class TCPClient {
	public static void main(String[] args) throws IOException {
		//2,创建客户端Socket,连接服务器
		Socket socket = new Socket("192.168.74.58", 8888);
		//3,获取Socket流中的输出流,功能:用来把数据写到服务器
		OutputStream out = socket.getOutputStream();
		//4,创建字节输入流,功能:用来读取数据源(图片)的字节
		BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream("D:\\NoDir\\test.jpg"));
		//5,把图片数据写到Socket的输出流中(把数据传给服务器)
		byte[] buffer = new byte[1024];
		int len = -1;
		while ((len = fileIn.read(buffer)) != -1){
			//把数据写到Socket的输出流中
			out.write(buffer, 0, len);
		}
		//6,客户端发送数据完毕,结束Socket输出流的写入操作,告知服务器端
		socket.shutdownOutput();

		//-----------------反馈信息---------------------
		//12,获取Socket的输入流  作用: 读反馈信息
		InputStream in = socket.getInputStream();
		//13,读反馈信息
		byte[] info = new byte[1024];
		//把反馈信息存储到info数组中,并记录字节个数
		int length = in.read(info);
		//显示反馈结果
		System.out.println( new String(info, 0, length) );
		
		//关闭流
		in.close();
		fileIn.close();
		out.close();
		socket.close();
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值