Java中的TCP、UDP通讯

本文深入探讨了TCP和UDP两种网络通信协议的原理及Java编程实践。详细讲解了如何使用Socket和ServerSocket创建TCP服务器与客户端,以及DatagramSocket在UDP通信中的应用。涵盖了连接建立、数据收发及线程处理等关键环节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TCP

TCP 协议提供面向连接的服务,通过它建立的是可靠地连接。Java 为 TCP 协议提供了两个类:Socke 类和 ServerSocket 类。一个 Socket 实例代表了 TCP 连接的一个客户端,而一个 ServerSocket 实例代表了 TCP 连接的一个服务器端,一般在 TCP Socket 编程中,客户端有多个,而服务器端只有一个,客户端 TCP 向服务器端 TCP 发送连接请求,服务器端的 ServerSocket 实例则监听来自客户端的 TCP 连接请求,并为每个请求创建新的 Socket 实例,由于服务端在调用 accept()等待客户端的连接请求时会阻塞,直到收到客户端发送的连接请求才会继续往下执行代码,因此要为每个 Socket 连接开启一个线程。服务器端要同时处理 ServerSocket 实例和 Socket 实例,而客户端只需要使用 Socket 实例。另外,每个 Socket 实例会关联一个 InputStream 和 OutputStream 对象,我们通过将字节写入套接字的 OutputStream 来发送数据,并通过从 InputStream 来接收数据。
From:极客wiki

创建服务器

  1. 通过ServerSocket创建服务套接字,并监听本地端口(以22333端口为例)
//:TCPServer.java

ServerSocket serverSocket = new ServerSocket(22333);
while(true){
	Socket conn = serverSocket.accept();
	onClientArrived(conn);
}
//deal with the request connection
public void abstract onClientArrived(Socket conn);

在新的连接到达前ServerSocket#accept()将处于阻塞状态。当每个连接到达时accept函数都将返回一个Socket实例;
2) 在onClientArrived中处理新连接

@Override
public void onConnArrived(Socket conn) {
	try {
		BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		String tmpLine = null;
		while ((tmpLine = reader.readLine()) != null){
				System.out.println(tmpLine);
			}	
			reader.close();
			conn.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

Reader#readLine()为一个阻塞读取过程,因此需要在客户端使用(启用auto flush)PrintWriterprintln等含有自动newLine的 函数与之配合使用。这里为了简便在读取完成后,直接关闭连接,如果想进行持续会话,则可根据conn的内容来控制时候结束会话,并且需要保证客户端并没有主动关闭连接。另外,通常当ServerSocket#accept()返回新Socket对象后,应该为该对象创建一个任务,并将该任务交由线程池处理。

创建客户端

  1. 客户端套接字
    连接服务22333端口(Dst Port),同时在TCP协议中系统会随机产生一个本地端口(Local Port)供通讯使用。

Socket client = new Socket("127.0.0.1", 22333);
  1. 向套接字中写入数据
//使用PrintWriter向套接字的OutputStream中写入数据
PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(client.getOutputStream()), true);
printWriter.println("hello ! this msg is send by  client");
printWriter.close();
client.close();

此处在写入完成直接关闭连接。若希望持续会话,则可在服务端的连接没有关闭的情况下,此处可以通过对Socket输入流的read操作和输出流的write操作实现持续会话
3) 完整代码

//:TCPTest.java
public class TCPTest {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                TCPServer tcpServer = new TCPServer() {
                    @Override
                    public void onConnArrived(Socket conn) {
                        try {
                            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                            String tmpLine = null;
                            while ((tmpLine = reader.readLine()) != null){
                                System.out.println("receive msg from client" + tmpLine);
                            }
                            reader.close();
                            conn.close();
                            System.out.println("conn shutdown");
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                };
                tcpServer.startServer();
            }
        }).start();

        try {
            Socket socket = new Socket("127.0.0.1",TCPServer.PORT);
            PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
            printWriter.println("hello ! this msg is send by client");
            printWriter.close();
            socket.close();
            System.out.println("client close");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
//:TCPServer.java

public abstract class TCPServer {
    public static final int PORT = 22333;
    private static ServerSocket serverSocket;
    private volatile boolean ifServerIsRunning = false;
    public TCPServer(){
        synchronized (TCPServer.class){
            if (serverSocket == null){
                try {
                    serverSocket = new ServerSocket(PORT);
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
    public void startServer(){
        if (!ifServerIsRunning){
            ifServerIsRunning = true;
            while (true){
                try {
                    Socket conn = serverSocket.accept();
                    onConnArrived(conn);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public abstract void  onConnArrived(Socket conn);
}

由以上的程序可以看出,Socket就是进程与进程之间的一种通信方式,一个位于服务端,一个位于客户端。Socket并不代表运输层,它只是一个网络编程API,当选用Socket时,代表我们希望使用TCP协议通信,当选用DatagramSocket时代表我们希望使用UDP协议进行通信。

UDP

Java 通过 DatagramPacket 类和 DatagramSocket 类来使用 UDP 套接字,客户端和服务器端都通过DatagramSocket 的 send()方法和 receive()方法来发送和接收数据,用 DatagramPacket 来包装需要发送或者接收到的数据。发送信息时,Java 创建一个包含待发送信息的 DatagramPacket 实例,并将其作为参数传递给DatagramSocket实例的send()方法;接收信息时,Java 程序首先创建一个 DatagramPacket 实例,该实例预先分配了一些空间,并将接收到的信息存放在该空间中,然后把该实例作为参数传递给 DatagramSocket 实例的 receive()方法。在创建 DatagramPacket 实例时,要注意:如果该实例用来包装待接收的数据,则不指定数据来源的远程主机和端口,只需指定一个缓存数据的 byte 数组即可(在调用 receive()方法接收到数据后,源地址和端口等信息会自动包含在 DatagramPacket 实例中),而如果该实例用来包装待发送的数据,则要指定要发送到的目的主机和端口。
From:极客wiki

小结

  • 在读取未关闭的socket的过程中,任何的read()readline()操作都是一个阻塞过程直到读取到内容或者socket关闭,可对比new Scanner(System.in)的类next操作。
  • ServerSocketaccept()操作是同样是一个阻塞过程,直到收到一个连接请求,每次客户端成功发起请求后,accept()都返回一个Socket对象,这个Socket对象将负责与发起请求的本次客户端进行通讯。
  • ReaderreadLine()需要使用'\n'作为此次读取结束标记,否则将一直阻塞在读取状态。
  • “一切皆文件”
### RT-DETRv3 网络结构分析 RT-DETRv3 是一种基于 Transformer 的实时端到端目标检测算法,其核心在于通过引入分层密集正监督方法以及一系列创新性的训练策略,解决了传统 DETR 模型收敛慢和解码器训练不足的问题。以下是 RT-DETRv3 的主要网络结构特点: #### 1. **基于 CNN 的辅助分支** 为了增强编码器的特征表示能力,RT-DETRv3 引入了一个基于卷积神经网络 (CNN) 的辅助分支[^3]。这一分支提供了密集的监督信号,能够与原始解码器协同工作,从而提升整体性能。 ```python class AuxiliaryBranch(nn.Module): def __init__(self, in_channels, out_channels): super(AuxiliaryBranch, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1) self.bn = nn.BatchNorm2d(out_channels) def forward(self, x): return F.relu(self.bn(self.conv(x))) ``` 此部分的设计灵感来源于传统的 CNN 架构,例如 YOLO 系列中的 CSPNet 和 PAN 结构[^2],这些技术被用来优化特征提取效率并减少计算开销。 --- #### 2. **自注意力扰动学习策略** 为解决解码器训练不足的问题,RT-DETRv3 提出了一种名为 *self-att 扰动* 的新学习策略。这种策略通过对多个查询组中阳性样本的标签分配进行多样化处理,有效增加了阳例的数量,进而提高了模型的学习能力和泛化性能。 具体实现方式是在训练过程中动态调整注意力权重分布,确保更多的高质量查询可以与真实标注 (Ground Truth) 进行匹配。 --- #### 3. **共享权重解编码器分支** 除了上述改进外,RT-DETRv3 还引入了一个共享权重的解编码器分支,专门用于提供密集的正向监督信号。这一设计不仅简化了模型架构,还显著降低了参数量和推理时间,使其更适合实时应用需求。 ```python class SharedDecoderEncoder(nn.Module): def __init__(self, d_model, nhead, num_layers): super(SharedDecoderEncoder, self).__init__() decoder_layer = nn.TransformerDecoderLayer(d_model=d_model, nhead=nhead) self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=num_layers) def forward(self, tgt, memory): return self.decoder(tgt=tgt, memory=memory) ``` 通过这种方式,RT-DETRv3 实现了高效的目标检测流程,在保持高精度的同时大幅缩短了推理延迟。 --- #### 4. **与其他模型的关系** 值得一提的是,RT-DETRv3 并未完全抛弃经典的 CNN 技术,而是将其与 Transformer 结合起来形成混合架构[^4]。例如,它采用了 YOLO 系列中的 RepNCSP 模块替代冗余的多尺度自注意力层,从而减少了不必要的计算负担。 此外,RT-DETRv3 还借鉴了 DETR 的一对一匹配策略,并在此基础上进行了优化,进一步提升了小目标检测的能力。 --- ### 总结 综上所述,RT-DETRv3 的网络结构主要包括以下几个关键组件:基于 CNN 的辅助分支、自注意力扰动学习策略、共享权重解编码器分支以及混合编码器设计。这些技术创新共同推动了实时目标检测领域的发展,使其在复杂场景下的表现更加出色。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值