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

相关推荐

  • spring的三级缓存

    spring的三级缓存: Spring 容器的“三级缓存” Spring 容器的整个生命周期中,单例Bean对象是唯一的。即可以使用缓存来加速访问 Spring 源码中使用了大量的 Cache 手段,其中在循环依赖问题的解决过程中就使用了“三级缓存” 三级缓存的意义 singletonObject:一级缓存,存放完全实例化且属性赋值完成的 Bean ,可以直…

    未分类 2025 年 1 月 6 日
    25000
  • 掌握Java对象本质:从打工者到技术专家的飞跃

    1.1 从机器视角到问题视角的演变 在计算机科学的发展历程中,我们见证了从机器视角到问题视角的深刻转变。这一转变不仅体现了编程语言和技术的进步,更反映了我们对问题解决方式理解的深化。 起初,计算机编程主要依赖于机器视角。汇编语言作为最初的编程语言,要求我们按照计算机的硬件结构来编写代码。以下是一个简单的汇编语言例子,用于在x86 架构的计算机上将两个数相加:…

    2024 年 12 月 28 日
    32900
  • manim边做边学–动画联动

    今天介绍Manim中的动画联动的技巧,在数学动画中,动画联动是常用的功能, 比如讲解平面几何中三角形与圆的位置关系变化,通过动画联动可以让圆沿着三角形的边滚动,或者让三角形的顶点在圆上移动,从而直观地展示内切、外接等几何关系。 总之,通过动画联动,可以将复杂的概念、关系或变化过程以动态的方式展示出来。 这种动态展示比静态的图像或文字描述更具吸引力,能让观众更…

    2025 年 1 月 16 日
    37800
  • Markdown学习

    Markdown学习 (使用软件Typora) 标题 “#”个数加空格,最多支持到六级标题,其中一级标题是最大的 字体 粗体,两边都加**,然后空格 例如粗体 斜体,两边都加*,然后空格 例如 斜体 (思考?斜体加粗怎么实现呢?——三个星号然后空格就行,例如 斜体加粗 ) 删除线,两边都加~~,然后空格 例如~~删除线~~ 引用 一个>加上一个空格,效果如下…

    2025 年 1 月 11 日
    46300
  • 从零开始的Python世界生活——语法基础先导篇(Python小白零基础光速入门上手)

    从零开始的Python世界生活——语法基础先导篇(Python小白零基础光速入门上手) 1. 准备阶段 1.1 下载并安装Python 1.1.1 下载步骤: 访问Python官方网站:点击这里下载Python 在页面上,选择适合你操作系统的Python版本(Windows、macOS或Linux)。 点击下载按钮,开始下载安装程序。 1.1.2 安装步骤:…

    未分类 2025 年 1 月 1 日
    44500

发表回复

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

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

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

关注微信