网络编程——UDP编程

2022-10-05 08:50:04 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

一、网络编程基础

计算机网络是指两台或更多的计算机组成的网络,在同一个网络中,任意两台计算机都可以直接通信,因为所有计算机都需要遵循同一种网络协议。因此,为了把计算机网络接入互联网,就必须使用TCP/IP协议。

1.常用协议

IP协议只负责发数据包,不保证顺序和正确性,而TCP协议负责控制数据包传输,它在传输数据之前需要先建立连接,建立连接后才能传输数据,传输完后还需要断开连接。

UDP协议(User Datagram Protocol)是一种数据报文协议,它是无连接协议,不保证可靠传输。因为UDP协议在通信前不需要建立连接,因此它的传输效率比TCP高,而且UDP协议比TCP协议要简单得多。选择UDP协议时,传输的数据通常是能容忍丢失的,例如,一些语音视频通信的应用会选择UDP协议。

2.什么是Socket?

Socket是一个抽象概念,一个应用程序通过一个Socket来建立一个远程连接,而Socket内部通过TCP/IP协议把数据传输到网络。可以把Socket简单理解为IP地址加端口号。端口号总是由操作系统分配,它是一个0~65535之间的数字,其中,小于1024的端口属于特权端口,需要管理员权限,大于1024的端口可以由任意用户的应用程序打开。

因此,当Socket连接成功地在服务器端和客户端之间建立后:对服务器端来说,它的Socket是指定的IP地址和指定的端口号;对客户端来说,它的Socket是它所在计算机的IP地址和一个由操作系统分配的随机端口号。

UDP端口和TCP端口虽然都使用0~65535,但他们是两套独立的端口,即一个应用程序用TCP占用了端口1234,不影响另一个应用程序用UDP占用端口1234

二、服务器端

要使用Socket编程,我们首先要编写服务器端程序。Java标准库提供了ServerSocket来实现对指定IP和指定端口的监听。ServerSocket的典型实现代码如下:

代码语言:javascript复制
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.HashMap;
import java.util.Map;

public class WorkDisctServer {
	public static void main(String[] args) {
		
		Map<String, String> wordMap = new HashMap<String, String>(){
			{
				put("one", "壹");
				put("two", "贰");
				put("three", "叁");
				put("four", "肆");
				put("five", "伍");
				put("six", "陆");
				put("serven", "柒");
			}
		};
	
		try (DatagramSocket serverSocket = new DatagramSocket(7788)) {
			while(true) {
				// 准备"空"数据包
				byte[] buff = new byte[1024];// 原始的字节数组
				DatagramPacket packet = new DatagramPacket(buff, buff.length);
				
				// 读取(客户端发送的英文单词)
				// 接收数据包
				serverSocket.receive(packet);
				
				// 获取数据包中的"数据"(字节数组) 
				// 获取数据包中的“读取位置”(int类型)
				// 获取数据包中的“长度”
				String word = new String(
						packet.getData(),
						packet.getOffset(),
						packet.getLength());
				System.out.println("【服务器】:获取来自客服端的单词" word);
				
				String chinese = wordMap.get(word);
				if(chinese == null) {
					chinese = "未知结果";
				}
				
				//发送(向客户端发送中文释义)
				byte[] resultbuff = chinese.getBytes();
				packet.setData(resultbuff);
				serverSocket.send(packet);
			
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	
	}

}

三、客户端

和服务器端相比,客户端使用UDP时,只需要直接向服务器端发送UDP包,然后接收返回的UDP包:

代码语言:javascript复制
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;

public class WorkDictClient {
	public static void main(String[] args) {

		Scanner input = new Scanner(System.in);

		while (true) {
			String word = input.nextLine();
			if (word.equals("end")) {
				break;
			}

			// 创建基于UDP协议的DatagramSocket对象
			try (DatagramSocket clientSocket = new DatagramSocket()) {
				// timeout超时
				clientSocket.setSoTimeout(2000);

				// 连接服务器(服务器IP和端口)
				clientSocket.connect(new InetSocketAddress("192.168.254.178", 7788));

				// 发送(向服务发送一个英文单词)
				// String word = "one";
				byte[] wordbuff = word.getBytes();// 获取英文单词字符串的字节数组

				// 封装成DatagramPacket对象(数据包)
				DatagramPacket packet = new DatagramPacket(wordbuff, wordbuff.length);

				// 发送数据包
				clientSocket.send(packet);

				// 读取
				byte[] resultbuff = new byte[1024];
				DatagramPacket resultPacket = new DatagramPacket(resultbuff, resultbuff.length);
				clientSocket.receive(resultPacket);

				String result = new String(resultPacket.getData(), resultPacket.getOffset(), resultPacket.getLength());
				System.out.println("来自服务器的中文释义"   result);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

区别:

1.客户端创建DatagramSocket实例时并不需要指定端口,而是由操作系统自动指定一个当前未使用的端口。紧接着,调用setSoTimeout(1000)设定超时1秒,意思是后续接收UDP包时,等待时间最多不会超过1秒,否则在没有收到UDP包时,客户端会无限等待下去。这一点和服务器端不一样,服务器端可以无限等待,因为它本来就被设计成长时间运行。

2.如果客户端希望向两个不同的服务器发送UDP包,那么它必须创建两个DatagramSocket实例。后续的收发数据和服务器端是一致的。通常来说,客户端必须先发UDP包,因为客户端不发UDP包,服务器端就根本不知道客户端的地址和端口号。

易混淆知识点:

1.注意到客户端的DatagramSocket还调用了一个connect()方法“连接”到指定的服务器端。不是说UDP是无连接的协议吗?为啥这里需要connect()?

这个connect()方法不是真连接,它是为了在客户端的DatagramSocket实例中保存服务器端的IP和端口号,确保这个DatagramSocket实例只能往指定的地址和端口发送UDP包,不能往其他地址和端口发送。这么做不是UDP的限制,而是Java内置了安全检查。

2.如果客户端认为通信结束,就可以调用disconnect()断开连接。

disconnect()也不是真正地断开连接,它只是清除了客户端DatagramSocket实例记录的远程服务器地址和端口号.这样,DatagramSocket实例就可以连接另一个服务器端。

四、实现结果:


知识小结:

  • 使用UDP协议通信时,服务器和客户端双方无需建立连接;
  • 服务器端用DatagramSocket(port)监听端口;
  • 客户端使用DatagramSocket.connect()指定远程地址和端口;
  • 双方通过receive()和send()读写数据;
  • DatagramSocket没有IO流接口,数据被直接写入byte[]缓冲区;

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

0 人点赞