Java网络通信实践:UDP协议下的套接字编程指南

网络通信基础

在网络应用开发中,主要涉及两个关键角色:请求方(客户端)和服务提供方(服务器)。请求方向服务端发起操作指令,服务端接收并处理这些指令后,将处理结果返回给请求方。
开发人员通常关注应用层和传输层的实现。我们编写的程序属于应用层范畴,需要借助传输层提供的接口完成数据传输。Java语言为开发者提供了两套网络通信接口:基于UDP协议的和基于TCP协议的。本文将重点探讨UDP协议下的数据报套接字编程技术。
Socket套接字是操作系统提供的网络通信技术,作为TCP/IP协议网络通信的基础单元。基于Socket的网络应用开发就是我们常说的网络编程。

UDP数据报通信

数据报套接字(DatagramSocket)

DatagramSocket的主要作用是确定通信端点位置,负责数据报的收发操作。
创建方法:
方法名称 | 功能说明
-------|--------
DatagramSocket() | 自动分配可用端口
DatagramSocket(int port) | 手动指定特定端口
数据收发方法:
方法名称 | 功能说明
-------|--------
send(DatagramPacket p) | 发送数据报文
receive(DatagramPacket p) | 接收数据报文(参数会被方法内部修改)
关于输出型参数:
这类参数在方法执行过程中会被修改,且修改结果会反映到方法外部的实际参数上。
资源释放方法:
方法名称 | 功能说明
-------|--------
close() | 释放套接字资源
重要提示:网络编程使用的Socket与文件、内存等资源一样,都需要及时释放。

数据报文(DatagramPacket)

DatagramPacket即传输的数据单元,包含实际传输内容。
创建方法:
Java网络通信实践:UDP协议下的套接字编程指南
字节数组用于存储数据内容(属于输出型参数)
offset参数指定数据起始位置
length参数确定数据长度
address参数包含目标地址信息(SocketAddress包含完整地址,InetAddress仅含IP,port为端口号)
常用方法:
方法名称 | 功能说明 | 返回类型
-------|--------|--------
getAddress() | 获取IP地址 | InetAddress
getPort() | 获取端口号 | int
getSocketAddress() | 获取完整地址 | SocketAddress
getData() | 获取数据内容 | byte[]
getLength() | 获取数据长度 | int

套接字地址(InetSocketAddress)

创建方法:
方法名称 | 功能说明
-------|--------
InetSocketAddress(InetAddress addr, int port) | 创建包含IP和端口的地址对象
实用方法:
方法名称 | 功能说明 | 备注
-------|--------|--------
getByName(String host) | 主机名转IP地址 | 静态方法
该方法作用:
人类可读的IP地址格式(如"xxx.xxx.xxx.xxx")需要转换为机器可识别的二进制格式,此方法完成这一转换。

实现回声服务器

回声服务器的功能是将接收到的数据原样返回。下面演示如何构建这样的服务器。
首先创建服务器类UdpEchoServer,定义核心字段DatagramSocket:

private DatagramSocket socket;
// 指定服务端口
public UdpEchoServer(int port) throws SocketException {
socket = new DatagramSocket(port);
}

固定端口号确保客户端能够准确定位服务位置。

服务启动流程

服务器需要持续运行,使用无限循环处理请求:
创建接收缓冲区:

// 准备接收缓冲区
DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);

接收客户端数据:

// 等待客户端请求
socket.receive(requestPacket);

若无数据到达,程序会在此处阻塞等待。
数据处理逻辑:

// 解析请求内容
String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
// 生成响应内容
String response = process(request);
// 核心业务处理
private String process(String request) {
return request;
}

构建并发送响应:

// 准备响应报文
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
response.getBytes().length, requestPacket.getSocketAddress());
// 发送响应
socket.send(responsePacket);

注意:UDP协议不保存通信对端信息,因此需要从请求报文中获取客户端地址。
记录操作日志:

// 输出处理日志
System.out.printf("[%s : %d] 请求: %s 响应: %sn",
requestPacket.getAddress().toString(),
requestPacket.getPort(),request,response);

完整实现

import java.io.IOException;
import java.net.*;
public class UdpEchoServer {
private DatagramSocket socket;
public UdpEchoServer(int port) throws SocketException {
socket = new DatagramSocket(port);
}
public void start() throws IOException {
System.out.println("服务启动中...");
while(true) {
DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
socket.receive(requestPacket);
String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
String response = process(request);
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
response.getBytes().length, requestPacket.getSocketAddress());
socket.send(responsePacket);
System.out.printf("[%s : %d] 请求: %s 响应: %sn",
requestPacket.getAddress().toString(),
requestPacket.getPort(),request,response);
}
}
private String process(String request) {
return request;
}
public static void main(String[] args) throws IOException {
UdpEchoServer server = new UdpEchoServer(9090);
server.start();
}
}

客户端实现

客户端需要预先知道服务端地址信息:

private DatagramSocket socket;
private String serverIP;
private int serverPort;

初始化配置:

public UdpEchoClient(String serverIP, int serverPort) throws SocketException {
this.serverPort = serverPort;
this.serverIP = serverIP;
socket = new DatagramSocket(); // 自动分配客户端端口
}

客户端工作流程

接收用户输入并发送请求:

// 准备请求报文
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
request.getBytes().length, InetAddress.getByName(serverIP),serverPort);
// 发送请求
socket.send(requestPacket);

接收服务端响应:

// 准备接收缓冲区
DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
socket.receive(responsePacket);

显示处理结果:

// 显示响应内容
String response = new String(responsePacket.getData(),0,responsePacket.getLength());
System.out.println("收到响应:" + response);

完整实现

import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class UdpEchoClient {
private DatagramSocket socket;
private String serverIP;
private int serverPort;
public UdpEchoClient(String serverIP, int serverPort) throws SocketException {
this.serverPort = serverPort;
this.serverIP = serverIP;
socket = new DatagramSocket();
}
public void start() throws IOException {
System.out.println("客户端就绪...");
Scanner scan = new Scanner(System.in);
while(true) {
System.out.println("请输入请求内容:");
String request = scan.nextLine();
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
request.getBytes().length, InetAddress.getByName(serverIP),serverPort);
socket.send(requestPacket);
DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
socket.receive(responsePacket);
String response = new String(responsePacket.getData(),0,responsePacket.getLength());
System.out.println("收到响应:" + response);
}
}
public static void main(String[] args) throws IOException {
UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);
client.start();
}
}

演示效果:
服务端运行效果
客户端运行效果

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/9610.html

(0)
LomuLomu
上一篇 2025 年 5 月 13 日 下午4:11
下一篇 2025 年 5 月 13 日 下午5:12

相关推荐

  • Python 潮流周刊#85:让 AI 帮你写出更好的代码(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章、教程、开源项目、软件工具、播客和视频、热门话题等内容。愿景:帮助所有读者精进 Python 技术,并增长职业和副业的收入。 分享了 12 篇文章,12 个开源项目,1 则音视频,全文 2300 字。 以下是本期摘要: 🦄文章&教程 ① 如果一直要求 LLM “写出更…

    未分类 2025 年 1 月 13 日
    30600
  • 10个案例告诉你mysql不使用子查询的原因

    大家好,我是 V 哥,上周跟一个哥们吃饭,技术人在一起,你知道的,没聊上一会儿,就转到技术问题探讨上了,其中聊到数据库子查询的问题印象深刻,回来整理了以下10个案例说明不使用子查询的问题,分享给大家。 首先,来说一下在MySQL中,不推荐使用子查询和JOIN的原因,主要有以下几点: 性能问题 :子查询在执行时,MySQL需要创建临时表来存储内层查询的结果,查…

    未分类 2024 年 12 月 30 日
    22300
  • manim边学边做–旋转

    本篇文章将深入探讨Manim库中的两种旋转动画类:Rotate和Rotating,它们虽然名称相似,但在功能和应用场景上各有千秋。 Rotate类专注于对图形对象进行精确的旋转操作,它允许用户指定旋转的角度、轴心点等,非常适合于几何图形的演示、物理模拟以及机械运动的展示等场合。 相对而言,Rotating类则致力于创建一个持续旋转的效果,使对象围绕一个轴或点…

    2024 年 12 月 26 日
    28100
  • 全网最适合入门的面向对象编程教程:60 Python面向对象综合实例-传感器数据实时绘图器

    全网最适合入门的面向对象编程教程:60 Python 面向对象综合实例-传感器数据实时绘图器 摘要: 本文将结合之前内容实现模拟一个传感器系统软件,包括三个线程:传感器线程生成数据并通过串口发送给主机进程;主机进程通过串口接收指令,进行数据滤波和处理后,将处理结果发送给绘图线程;绘图线程负责接收数据并绘制更新数据曲线。 原文链接: FreakStudio的博…

    2024 年 12 月 24 日
    19300
  • Redis 爆高危漏洞,请速度修复。。

    大家好,我是R哥。 今天一早收到了腾讯云给我的【主机安全 】漏洞通知: 好家伙,大名鼎鼎的 Redis 爆高危漏洞了,R哥的题库「Java面试库」也用到了 Redis 来缓存面试题内容,所以这一下子就引起了我的警惕,赶紧看看什么鬼。 漏洞描述 下面是漏洞描述和修复说明: https://github.com/redis/redis/security/advi…

    2025 年 1 月 6 日
    29700

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信