基于TCP与UDP网络编程

 一.什么是TCP与UDP

 TCP与UDP是计算机网络中五层模型的运输层协议。

TCP 协议:是传输控制协议,它是面向连接的协议,支持可靠传输和双向通信。它在传输数据之前需要先建立连接,建立连接后才能传输数据,传输完后还需要断开连接。TCP协议之所以能保证数据的可靠传输,是通过接收确认、超时重传这些机制实现的。并且,TCP协议允许双向通信,即通信双方可以同时发送和接收数据。

UDP协议:(User Datagram Protocol)是一-种数据报文协议,它是无连接协议,不保证可 靠传输。 因为UDP协议在通信前不需要建立连接,因此它的传输效率比TCP高,而且UDP 协议比TCP协议要简 单得多

二.什么是Socket

        在我们进行网络编程时,都会接触到一个名叫scoket的概念,应用程序通过Scoket来建立远程连接,Socket通过内部封装好的协议把数据传输到网络。

        为什么需要Socket 进行网络通信?因为仅仅通过IP地址进行通信是不够的,同一台计算机同- -时间会运行多个网络应用程序,例如浏览器、QQ、邮件客户端等。当操作系统接收到一个数据包的时候,如果 只有IP地址,它没法判断应该发给哪个应用程序,所以,操作系统抽象出Socket 接口,每个应用程序需 要各自对应到不同的Socket,数据包才能根据 Socket正确地发到对应的应用程序。

        使用Socket进行网络编程时,本质上就是两个进程之间的网络通信。其中一个进程必须充当服务器端,它会主动监听某个指定的端口,另一个进程必须充当客户端,它必须主动连接服务器的IP地址和指定端口,如果连接成功,服务器端和客户端就成功地建立了一个TCP连接,双方后续就可以随时发送和接收,因此,当Socket 连接成功地在服务器端和客户端之间建立后:对服务器端来说,它的Socket是指定的IP地址和指定的端口号。


三.TCP网络编程简单实现

        TCP的编程实现客户端与服务器端交互,是通过建立连接,从而利用“流”来进行数据交换的,即使用字节输入/输出流,把要发送的数据,存储到字节数组,通过“流”来实现发送与接收。

接下来我们以客户端向服务器端上传图片的简单例子来说明TCP编程。

1.建立服务器端

第一步:建立socket,服务器端使用java提供的ServerSocket创建于客户端交互的对象,并且监听指定端口。

第二步:建立与客户端的连接,创建一个Scoket,调用accept()方法,与客户端建立连接,并且获取客户端的IP地址

第三步:创建输入流,来读取客户端上传的照片使用:getInputStream()

第四步:创建输出流,对客户端上传的图片,写入到本地,我们这里使用BufferedInputStream来实现建立字节字节数组对传过来的数据进行批量写入。

第六步:当我们成功接收到客户端上传的图片以后,要给客户端发送一个反馈,这时,我们需要创建一个输出流,向客户端进行反馈。

完整的实例代码如下:

try {
			//ServerSocket:服务器端进行通信的对象
			ServerSocket server = new ServerSocket(8848);
			
			//死循环:不断接收客户端的连接
			while(true) {
				
				//服务器进入“等待”状态
				//如果有客户端连接时,该方法1返回客户端的Socket
				Socket cilent = server.accept();
				InetAddress clientNetAddress = cilent.getInetAddress();
				System.out.println("客户端" +clientNetAddress + "正在连接.......");
			
				// 接收来自客户端上传的图片
				// 输入流:读取来自客户端发送的图片文件流
				// 输出流:写入本地图片
				String imgName = clientNetAddress.getHostAddress().replaceAll("\\.", "\\-") + ".jpg";

				try(InputStream in = cilent.getInputStream();
					BufferedInputStream bis = new BufferedInputStream(in);
					BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\test\\aaa\\" + imgName))){
				
					// 每次读取来自客户端的图片文件流
					// 写入本地
				    byte[] buff = new byte[1024];
						
				    int len = -1;
				
					while((len = bis.read(buff)) != -1) {
							
						bos.write(buff,0,len);
					 }
					
					System.out.println("图片读取完毕!");
					
					// 输出提示信息 => 客户端
					try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(cilent.getOutputStream()));){
					
						writer.write("上传完毕!");
						writer.newLine();
			    	}	
				}
		  }
			
	  } catch (IOException e) {
	 						
		e.printStackTrace();
	}

我们这里用到了一个死循环,是为了保证服务器端可以持续不断地接收来自客户端上传的图片。

2.建立客户端

相比服务器端,客户端就简单很多

第一步:创建Socket,用于和服务器端进行连接的组件,传入服务器端的IP地址与端口号。

第二步:创建一个输出流,将要上传的图片发送至服务器端。

第三步:创建输入流,来获取将要发送的本地的图片的路径,我们这里也使用BufferedInputStream来对本地图片进行一个批量读取,将读取到的内容发送至服务器端。

这里值得注意的是:使用cilent.shutdownOutput(),输出暂时结束(Socket没有关闭)

第四步:我们等待服务器端接收成功后,发生给我们一个反馈,我们需要创建一个Socket的输入流,来接收服务器端对我们的反馈。

基本实现代码如下:

//Socket:客户端进行通讯的组件
		//本地图片获取 = > 通过输出流,发送(输出)至服务器
		//OutputStream:输出流,读取到本地图片文件流,发送(输出)至服务器
		//BufferedInputStream:输入流,读取本地文件
		
		try (
		 Socket cilent = new Socket("192.168.254.188",8848);
				OutputStream out = cilent.getOutputStream();
				BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\数据分析\\2017年第一季度各产业生产总值占比饼图.png"))) {
			
			//每次读取到1024字节
			byte[] buff = new byte[1024];
			int len = -1;
			
			while((len = bis.read(buff)) != -1) {
				//将读取到的内容,通过输出流发送至服务器
				out.write(buff);	
			}
			
			//输出暂时结束(Socket没有关闭)
			cilent.shutdownOutput();
			
			//读取来自服务器的反馈
			try(BufferedReader reader = new BufferedReader(new InputStreamReader(cilent.getInputStream()));){
				String  reply = reader.readLine();
				System.out.println("服务器的反馈:" + reply);
			}
			
		} catch (IOException e) {
			
			e.printStackTrace();
		}

四.UDP网络编程简单实现

UDP和TCP相比,就简单的多,因为UDP不需要建立连接,也就没有区分哪一个是客户端哪一个是服务器端,是依靠数据包来进行实现的,数据包也是收一个发一个,不存在使用流的概念。

UDP也是需要使用Socket来监听端口的的,不过它使用的是java提供的DatagramSocket。

我们以一个简易的聊天室的案例,来实现简单的UDP编程:

第一步:创建Scanner 来进行对话的输入

第二步:创建Socket,来监听端口。

第三步:创建两个数据包来实现对话的发送与接收。

1.发送:

这里使用的是DatagramPacket,传入一个字节数组,并且传入将要发送的IP地址与端口号

使用socket.send(sendPacket),来进行发送

	try (DatagramSocket socket = new DatagramSocket(6666);) {
		
			//提前创建两个Packet数据包,分别用于发送和接收
			DatagramPacket sendPacket = 
					new DatagramPacket(
						new byte[1024],1024, //数据
						new InetSocketAddress("192.168.254.153",7788)  //目的地
										);
			
			while(true) {
				//发送
				System.out.print("你说:");
				String sendContent = input.nextLine();
				
				sendPacket.setData(sendContent.getBytes());
				socket.send(sendPacket1);

				if(sendContent.equals("滚")) {
				    System.out.println("我不想跟你讲话");
					return;
				}
				socket.send(sendPacket);

sendPacket.setData(sendContent.getBytes())

是将输入的数据存入数据包中

2.接收

首先建立一个接收的数据包,传入一个自定义的字节数组,用来接收数据

DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);

使用socket.receive(receivePacket),方法来进行数据包的接收

由于接收到的是一个数据包,我们如果想正常显示,就要把它变成字符串

//packet.getData():获取数据包中的“数据”(字节数组)
//packet.getOffset():获取数据包中的“读取位置”
//packet.getLength():获取数据包中的“长度”

String receiveContent = new String(receivePacket.getData(),receivePacket.getOffset(),receivePacket.getLength());

当我们想要不停地与对方进行聊天时,就可以写一个死循环while(true){},来一直输入内容,直到输入关键字,程序才会退出。

代码实现:

//接收
socket.receive(receivePacket);
String receiveContent = new String(receivePacket.getData(),receivePacket.getOffset(),receivePacket.getLength());
if(receiveContent.equals("滚")) {
        System.out.println("他不想跟你说话!");
		break;
		}
	system.out.println("他说:" + receiveContent);
			}

运行结果:

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值