上篇:网络编程基础与UDP套接字编程

上篇:网络编程基础与UDP套接字编程

一、为什么需要网络编程?

平时我们在浏览器里打开优酷看视频,本质上是通过网络获取到了远端的视频资源。和打开本地视频文件类似,区别只在于资源的来源------一个是本地磁盘,一个是网络。

网络资源包括视频、图片、文本等各种数据,而这些资源的传输,都离不开网络编程。

二、什么是网络编程?

网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(网络数据传输)。

只要满足"不同进程"这个条件,即使是在同一台主机上,基于网络协议传输数据,也属于网络编程。当然,实际开发中,我们最终目的是实现不同主机之间的数据传输。

三、网络编程中的基本概念

1. 发送端和接收端

  • 发送端:数据的发送方进程,对应源主机。
  • 接收端:数据的接收方进程,对应目的主机。
  • 两者是相对概念,一次数据传输中角色可能互换。

2. 请求和响应

获取一个网络资源通常涉及两次传输:

  1. 请求:客户端发送请求数据。
  2. 响应:服务端返回响应数据。

就像点外卖:先下单(请求),商家再送餐(响应)。

3. 客户端和服务端

  • 服务端:提供服务的一方,对外提供服务。
  • 客户端:获取服务的一方。

服务端常见的两种服务模式:

  • 客户端获取服务端资源(如看视频)。
  • 客户端保存资源到服务端(如上传文件)。

4. 常见的客户端服务端模型

  1. 客户端发送请求到服务端。
  2. 服务端处理业务。
  3. 服务端返回响应。
  4. 客户端展示处理结果。

四、Socket套接字

Socket套接字是由系统提供的、用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。

按传输层协议分为三类:

  • 流套接字:使用TCP协议,有连接、可靠传输、面向字节流。
  • 数据报套接字:使用UDP协议,无连接、不可靠、面向数据报、大小受限(64K)。
  • 原始套接字:用于自定义传输层协议,简单了解即可。

五、Java数据报套接字(UDP)通信模型

UDP通信基于DatagramSocket和DatagramPacket。

一次完整的UDP通信流程:

  1. 发送端创建DatagramSocket。
  2. 构造DatagramPacket(包含数据、目标IP、端口)。
  3. 调用socket.send(packet)发送。
  4. 接收端创建DatagramSocket并绑定端口。
  5. 调用socket.receive(packet)接收数据。
  6. 解析数据,处理业务,再构造响应包发回。

六、UDP编程核心API

DatagramSocket

方法 说明
DatagramSocket() 绑定任意随机端口(客户端常用)
DatagramSocket(int port) 绑定指定端口(服务端常用)
receive(DatagramPacket p) 接收数据报,阻塞等待
send(DatagramPacket p) 发送数据报,不阻塞
close() 关闭套接字

DatagramPacket

方法 说明
DatagramPacket(byte[] buf, int length) 用于接收数据报
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 用于发送数据报
getAddress() 获取IP地址
getPort() 获取端口号

InetSocketAddress

方法 说明
InetSocketAddress(InetAddress addr, int port) 创建包含IP和端口的Socket地址

七、UDP Echo Server 代码示例

java 复制代码
public class UdpEchoServer {
    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 requestPacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(requestPacket);
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
            // 2. 计算响应
            String response = process(request);
            // 3. 返回响应
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
                    response.getBytes().length, requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s:%d] req: %s, resp: %s\n",
                    requestPacket.getAddress(), 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();
    }
}

八、UDP Echo Client 代码示例

java 复制代码
public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;

    public UdpEchoClient(String ip, int port) throws SocketException {
        serverIp = ip;
        serverPort = port;
        socket = new DatagramSocket();
    }

    public void start() throws IOException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("客户端启动!!");
        while (true) {
            System.out.print("-> ");
            String request = scanner.next();
            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();
    }
}

九、UDP字典服务器(继承Echo服务器)

java 复制代码
public class UdpDictServer extends UdpEchoServer {
    private Map<String, String> dict = new HashMap<>();

    public UdpDictServer(int port) throws SocketException {
        super(port);
        dict.put("cat", "小猫");
        dict.put("dog", "小狗");
        dict.put("fuck", "卧槽");
    }

    @Override
    public String process(String request) {
        return dict.getOrDefault(request, "该词没有查询到!");
    }

    public static void main(String[] args) throws IOException {
        UdpDictServer server = new UdpDictServer(9090);
        server.start();
    }
}

十、端口被占用怎么办?

如果启动时出现java.net.BindException: Address already in use,说明端口已被占用。

排查方式:

bash 复制代码
netstat -ano | findstr 端口号

找到PID后,在任务管理器"详细信息"中按PID查找进程,决定关闭或更换端口。

小结

UDP编程简单直接:无连接、面向数据报、一次收发一整块数据。适合对实时性要求高、但允许少量丢包的场景。掌握DatagramSocket和DatagramPacket即可完成基本的UDP通信。

相关推荐
BLUcoding3 小时前
接口服务公网超时排查记录:SecureRandom 阻塞问题分析与解决
java·linux·springboot·aes·securerandom
AIgorithmGEEK3 小时前
[Linux]从手写报头到内核套路:序列化、反序列化与自定义协议全链路
linux·运维·服务器·网络·序列化·反序列化
yuniko-n3 小时前
【JUC】Lock 和 synchronzied 锁
java
西柚小萌新3 小时前
【LLM&&AI应用开发 八股文】--4.3.Agent智能体(下)
java·开发语言·数据库
北极有牛3 小时前
cpp学习笔记--常量指针
java·开发语言·算法
java资料站4 小时前
二、Spring AI Alibaba · ChatModel
java·windows·spring
十年Java程序媛4 小时前
Java 接口和抽象类对比|Java8 新特性,抛弃老旧八股,正确选型
java·spring boot·后端
caoerzhong4 小时前
JeeWMS 开源 WMS 部署避坑指南:Java 仓库管理系统的环境基线、四类根因与可复现交付
java·开发语言·开源
用户3721574261354 小时前
Java 合并 PDF 文件:完整合并、指定页面合并与流合并
java