Java UDP套接字编程:高效实时通信的实战应用与核心类解析

发布于:2025-05-25 ⋅ 阅读:(15) ⋅ 点赞:(0)

一、网络编程

什么是网络编程?

        我们打开视频网站,比如腾讯视频,看仙逆,剑来等动漫,实质上是通过网络,获取到网络上的一个视频资源。

         与在本地打开一个视频文件一样,只是这个视频文件来源于网络,相对于本地,网络提供了更为丰富的网络资源。

1.1、网络编程

        网络编程是指通过编写程序来实现计算机之间的通信和数据交换。它涉及使用网络协议(如 TCP/IP、UDP等)在网络上发送和接收数据。(网络上的主机,通过不同的进程,以编码的方式实现网络通信)

即便是同一个主机,只要进程不同,基于网络来传输数据,也属于网络编程。

1.2、网络编程的核心概念

1.2.1、客户端和服务端

        服务端:在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端。

        客户端:获取服务的一方进程,称为客户端。

1.2.2、Socket套接字

概念:Socket套接字是由系统提供用于网络通信的基本操作单元

基于Socket套接字的网络程序开发就是网络编程。

主要分为以下三类:

(1)流套接字

        使用传输层TCP协议

        TCP(Transmission Control Protocol)传输控制协议

 

        特点

                • 有连接

                • 可靠传输

                • 面向字节流

                • 有接受缓存区,也有发送缓存区

                • 大小不限

字节流基于IO流以字节为单位进行数据传输,数据在流未关闭的情况下可以持续发送和接受.

(2)数据报套接字

        使用传输层UDP协议

        UDP(User Datagram Protocol)用户数据报协议

        特点

                • 无连接

                • 不可靠传输

                • 面向数据报

                • 有接受缓存区,无发送缓存区

                • 大小受限:一次最多传输64K

数据报传输是原子的,发送和接受操作必须一次性完成,发送方需将数据封装成一个数据报,接收方则接受整个数据报。

(3)原始套接字

        原始套接字(Raw Socket)是一种允许应用程序直接访问网络层协议的套接字类型。与常见的流式套接字(如TCP)或数据报套接字(如UDP)不同,原始套接字允许用户自定义网络层协议头,甚至可以直接发送和接收原始数据包。(此知识我们不过多讲解)

1.3、数据报套接字通信模型

        上文UDP,即用户数据报协议是无连接,面向数据报的特征,每次都是没有建立连接,并且一次性发送所有数据报,一次性接受所有数据报

        Java中使用UDP协议通信,主要是基于DatagramPacket类来创建数据报套接字,并使用DatagramPacket作为发送或接受的UDP数据报,对于一次发送及接受UDP数据报的流程如下:

1.4、流套接字通信模型

         TCP,即传输控制协议是有连接的,基于IO流,持续发送和接收的协议

        Java使用TCP协议通信,服务端创建ServerSocket并绑定端口创建Socket连接ServerSocket对象接受客户端的Socket对象调用方法实现通信;在客户端创建Socket对象指定服务端地址和端口。

        不论是客户端和服务端都要在通信完成后关闭流对象,服务端要多关闭一个Socket对象,客户端的Socket对象会随通信完成后进程的结束而自动关闭~~

流程如下

1.5、 Socket编程注意事项

        (1)客户端和服务端:开发时,经常是基于一个主机开启两个进程作为客户端和服务端,但在真实情况下。一般都是不同主机。

        (2)目的IP和端口号,标识了一次数据传输时要发送数据的终点主机和进程。

        (3)Socekt编程是我们使用流套接字和数据报套接字,基于传输层的TCP或UDP协议,但在应用层协议,也需要考虑(后续更新)。

        (4)端口占用,如果一个进程Q已经绑定了一个端口,在启动一个进程P绑定该端口,就会报错,报错信息如下:

        我们可以在 cmd 中输入 netstat  -ano | findstr 端口号,可以显示对应进程的 pid

        然后在任务管理器中,通过 pid 查看进程 :

解决端口被占用的问题

(1)如果占用端口的进程A不需要运行,就可以关闭A后,再启动需要绑定该端口的进程B.

(2)如果需要运行A进程,则可以修改进程B的绑定端口,换为其他没有使用的端口。

二、 UDP数据报套接字编程

2.1、API介绍

DatagramSocket(通信端点)

DatagramSocket是UDP Socket,用于发送和接收UDP数据报

构造方法

DatagramSocket 方法

 DatagramPacket(数据容器)

DatagramPacket是UDP Socket发送和接收UDP数据报

构造方法

 DatagramPacket方法

InetSocketAaddress

 InetSocketAaddress是(SocketAddress的子类)构造方法

 2.2、模拟实现服务器

2.2.1、完整代码
package UdpEcho;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.sql.PreparedStatement;

public class UdpEchoServer {
    private DatagramSocket datagramSocket=null;
    public UdpEchoServer(int port) throws SocketException {
        datagramSocket=new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true){
            DatagramPacket requestPacket=new DatagramPacket(new byte[4048],4048);
            datagramSocket.receive(requestPacket);
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            String response=procsee(request);
            DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            datagramSocket.send(responsePacket);
            System.out.printf("[%s:%d]   req:%s    rep:%s/n",
                    requestPacket.getAddress(),requestPacket.getPort(),request,response);
        }
    }
    public String procsee(String s){
        return s;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer server=new UdpEchoServer(8776);
        server.start();
    }
}
2.2.2、核心组件

2.2.3、服务启动流程

2.2.4、与客户端交互流程图

2.3、模拟实现客户端 

2.2.1、完整代码
package UdpEcho;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpEchoClient {
    private String IP;
    private  int Port;
    private DatagramSocket socket=null;
    public UdpEchoClient(String ip,int port) throws SocketException {
        this.IP=ip;
        this.Port=port;
        socket=new DatagramSocket();
    }
    public void start() throws IOException {
        Scanner sc=new Scanner(System.in);
        while(true) {
            if (!sc.hasNext()){
                break;
            }
            System.out.println("请输入您要发送的内容:");
            String request=sc.next();
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(IP),Port);
            socket.send(requestPacket);
            DatagramPacket responsePacket=new DatagramPacket(new byte[4048],4048);
            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",8776);
        client.start();
    }
}
2.2.2、核心组件

        UDP是无连接的,故要定义IP和端口号,构造方法中Socket未指定本地端口号,由系统自动分配以避免冲突。

    private String IP;
    private  int Port;
    private DatagramSocket socket=null;
    public UdpEchoClient(String ip,int port) throws SocketException {
        this.IP=ip;
        this.POrt=port;
        socket=new DatagramSocket();
    }
2.2.3、通信流程
   public void start() throws IOException {
        Scanner sc=new Scanner(System.in);
        while(true) {
            if (!sc.hasNext()){
                break;
            }
            System.out.println("请输入您要发送的内容:");
            String request=sc.next();
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(IP),POrt);
            socket.send(requestPacket);
            DatagramPacket responsePacket=new DatagramPacket(new byte[4048],4048);
            socket.receive(responsePacket);
            String response=new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);
        }
    }
2.2.4、与服务端交互流程


网站公告

今日签到

点亮在社区的每一天
去签到