从Socket到UDP回显服务器:Java网络编程完整指南
摘要:本文讲解 UDP 协议与 Java 数据报套接字编程:Socket 概念与分类、UDP 四大特点、
DatagramSocket与DatagramPacket核心 API,并完整实现一个 UDP 回显服务器与客户端。
目录
1.socket套接字
2.UDP协议的特点
3.UDP数据报套接字编程
4.基于UDP实现一个回显服务器
正文
1.socket套接字
Socket(套接字)是操作系统提供给应用程序的一组网络编程接口,它把「传输层协议 + IP 地址 + 端口号」抽象成一个可读写的文件描述符,让程序可以像读写文件一样收发网络数据。
1.1分类
Socket套接字主要针对传输层协议划分为如下三类:
- 1.流套接字:使用传输层TCP协议.
- 2.数据报套接字:使用传输层UDP协议.
- 3.原始套接字:使用传输层自定义协议.
这篇文章我们展开学习数据报套接字:使用传输层UDP协议.
2.UDP协议的特点
UDP协议,即User Datagram Protocol(用户数据报协议),传输层协议.
- **1.无连接:**对UDP来说,UDP协议本身不保存对方的信息,就是无连接.
- **2.不可靠传输:**只是把数据发送了就不管了.
- **3.面向数据报:**读取数据的时候以一个数据报为单位.
- **4.全双工:**通信链路支持双向通信.(可写可读)
3.UDP数据报套接字编程
3.1API介绍
DatagramSocket
DatagramSocket是UDP Socket,用于发送和接受数据报.
DatagramSocket构造方法:

DatagramSocket方法:

3.2DatagramPacket
DatagramPacket是UDP Socket发送和接受的数据报,表示一个完整的数据报.
DatagramPacket构造方法:

Datagrampacket方法:

==注意:==构造UDP发送的数据报时,需要传入SocketAddress.
4.基于UDP实现一个回显服务器
基于上述内容,我们来实现一个回显服务器.
首先我们先了解一般服务器的工作流程:
- 客户端向服务器发起请求,服务器根据客户端请求返回响应结果.例如,我在浏览器搜索关键词"服务器图片’',点击搜索就会呈现一些结果给我们.这就是响应.
- 回显服务器比较一般的服务器比较特殊的是:它不做任何业务处理,收到什么就原样返回什么.一般服务器需要根据请求内容去查数据库、算逻辑、拼页面,而回显服务器的"计算响应"这一步可以省略,直接把请求当作响应发回去.正因为逻辑极简,它常被用来验证网络连通性、测试客户端收发流程是否正确.
客户端发送请求时,数据报的源地址是客户端 ip + 客户端端口,目的地址是服务器 ip + 服务器端口。服务器收到请求后,从数据报中取出源 ip 和源端口(即客户端地址),在构造响应时把它们作为目的 ip 和目的端口发回去。这正是 UDP 无连接、每个数据报都携带完整地址信息的体现。

服务器端代码:
package network;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class UdpEchoServer {
//DatagramSocket负责收发数据
private DatagramSocket socket=null;
//指定一个端口号,让服务器使用
public UdpEchoServer(int port) throws SocketException {
socket=new DatagramSocket(port);
}
public void start() throws IOException {
//启动服务器
System.out.println("启动服务器");
while(true){
//循环一次就相当于处理一次请求
//处理请求的过程中,典型的服务器一般分三个步骤
//1.读取请求并解析
//DatagramPacket就是一个UDP数据报,此处此处构造一个空的缓冲区(大小为4096字节 ),用来保存UDP的载荷内容,此时这个数据报还是空的,什么都没有
DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
//经过receive代码行之后,requestPacket 中会被填入请求的数据包信息,此时的数据包已经有数据:有源IP,源端口号,载荷
socket.receive(requestPacket);
//把读取到的二进制数据,转成字符串.
String request=new String(requestPacket.getData(),0,requestPacket.getLength());
//2.根据请求计算响应(但是此处是回显服务器,这个环节就省略了,请求是什么,响应就是什么)
String response=process(request);
//3把响应返回给客服端\
//根据response构造DatagramPacket,发送给用户
//此时客户端的ip,端口号变成了目的ip和目的端口号
DatagramPacket responsePacket=new DatagramPacket(
response.getBytes(),
response.getBytes().length,
requestPacket.getSocketAddress()
);
socket.send(responsePacket);
//4.打印日志
System.out.printf("[%s:%d] req:%s,resp:%s\n",
requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);
}
}
//后续需要只需写别的服务器,只需要修改这个地方即可
public String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
UdpEchoServer server=new UdpEchoServer(9090);//固定端口号,若此时此端口号已经被其他应用占用,就有可能导致程序启动失败
server.start();
}
}
客户端代码:
package network;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class UdpEchoClient {
//socket是用来收发数据报的
private DatagramSocket socket=null;
//Udp本身不保存对端的信息(IP,端口号),自己的代码保存一下
private String serverIp;
private int serverPort;
//和服务器不同,此处的构造方法需要指定访问的服务器的地址
public UdpEchoClient(String serverIp,int serverPort) throws SocketException {
this.serverIp=serverIp;
this.serverPort= serverPort;
socket=new DatagramSocket();
}
public void start() throws IOException {
Scanner scanner=new Scanner(System.in);
//1.从控制台中读取用户输入的内容
while(true){
System.out.println("请输入要发送的内容");
if(!scanner.hasNext()){
break;
}
String request= scanner.next();
//2.把请求打包成一个数据包发送给服务器,需要构造DataGramPacket对象
DatagramPacket requestPacket=new DatagramPacket(
request.getBytes(),
request.getBytes().length,
InetAddress.getByName(serverIp),
serverPort);
//3.send方法发送数据
socket.send(requestPacket);
//4.接收服务器的响应
//接收响应时要重新new一个数据包来存放,此处构造一个空的缓冲区(大小为4096字节) 包的大小
DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
//经过receive方法,responsePacket 中会被填入服务器返回的数据,responsePacket不再为空
socket.receive(responsePacket);
//5.对从服务器读取出来的数据进行解析,打印出来
String response=new String(responsePacket.getData(),0,responsePacket.getLength());
System.out.println(response);
}
}
public static void main(String[] args) throws IOException {
//127.0.0.1指代本机ip,9090端口号
UdpEchoClient client=new UdpEchoClient("127.0.0.1",9090);
client.start();
}
}
运行结果展示:


本文结束~欢迎一起来交流技术!!!

转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/2502_92960941/article/details/169557837




