UDP协议

158 阅读5分钟

UDP示例

UDP(User Datagram Protocol)是一种无连接的、面向数据报的传输协议,它提供了简单的数据包交换服务。相比于TCP,UDP不保证数据的可靠性和顺序性,但具有低延迟和更高的性能。

下面是一个简单的UDP客户端和服务端的Python实现,并附有详细的解释。

server.py

import socket

# 创建UDP套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 绑定地址和端口
server_address = ('127.0.0.1', 12345)
server_socket.bind(server_address)

print('UDP Server启动,等待客户端连接...')

while True:
    # 接收数据
    data, client_address = server_socket.recvfrom(1024)

    # 打印接收到的数据和客户端地址
    print(f"Received data: {data.decode('utf-8')} from {client_address}")

    # 发送响应数据给客户端
    response_message = "Hello, Client!"
    server_socket.sendto(response_message.encode('utf-8'), client_address)

client.py

import socket

# 创建UDP套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 服务器地址和端口
server_address = ('127.0.0.1', 12345)

# 发送数据到服务器
message = "Hello, Server!"
client_socket.sendto(message.encode('utf-8'), server_address)

# 接收服务器的响应
response, server_address = client_socket.recvfrom(1024)

# 打印服务器的响应
print(f"Received response: {response.decode('utf-8')} from {server_address}")

# 关闭套接字
client_socket.close()

debug查看端口连接过程

仅服务端启动后

服务端端口情况

客户端启动后

发送了请求给服务端,服务端添加了断点,断点在最后一行(如下),还没有发送给客户端。

server_socket.sendto(response_message.encode('utf-8'), client_address)

此时,客户端阻塞在client_socket.recvfrom(1024),等待读取数据。

服务端端口情况

此时服务端端口情况,和客户端没连接时候,是一样的。所以UDPServer不需要考虑连接数限制问题。本文后面对此有具体阐述。

客户端端口情况

结论

UDP通行过程中,并没有建立可靠连接。

通信过程解释

  1. 服务器端启动: 服务器创建一个UDP套接字并绑定到指定的地址和端口。

  2. 等待连接: 服务器通过recvfrom方法等待接收来自客户端的数据。该方法会阻塞程序执行,直到有数据到达。

  3. 接收数据: 一旦有数据到达,服务器使用recvfrom方法接收数据,并打印出接收到的数据和客户端的地址。

  4. 发送响应: 服务器可以通过sendto方法向客户端发送响应数据。

  5. 客户端启动: 客户端创建一个UDP套接字。

  6. 发送数据: 客户端使用sendto方法向服务器发送数据。

  7. 等待响应: 客户端可以通过recvfrom方法等待接收服务器的响应。

  8. 接收响应: 一旦有响应到达,客户端可以使用recvfrom方法接收响应,并打印出来。

  9. 关闭连接: 通信结束后,服务器和客户端都应该关闭套接字。

总体来说,UDP通信是无连接的,服务器和客户端通过数据报进行通信,相比TCP,UDP不提供可靠性和有序性,但通信更为简单,适用于一些对实时性要求较高、可以容忍数据丢失的场景。

UDP看起来和TCP socket连接是一模一样的?这是为什么呢?有什么区别吗?

UDP和TCP在使用Socket API时确实有很多相似之处,这是因为它们都是基于套接字(Socket)的网络通信协议。然而,它们之间存在一些关键的区别:

相似之处:

  1. 套接字创建: 在UDP和TCP通信中,都需要创建套接字(socket)对象,通过这个套接字进行数据的发送和接收。

  2. 地址和端口绑定: 无论是UDP还是TCP,服务器都需要绑定到一个特定的地址和端口来监听客户端的连接或数据报的到达。

  3. 数据的发送和接收: 无论是TCP还是UDP,都可以使用sendtorecvfrom等方法进行数据的发送和接收。

关键区别:

  1. 连接性:

    • TCP: 提供面向连接的服务,通过三次握手建立连接,保证可靠性和有序性。
    • UDP: 是一种面向无连接的服务,不需要建立连接,不保证可靠性和有序性。
  2. 数据传输特性:

    • TCP: 提供可靠的、面向字节流的传输,确保数据完整性,适用于对数据准确性要求高的场景。
    • UDP: 提供无连接的、面向数据报的传输,适用于对实时性要求高、可以容忍数据丢失的场景。
  3. 通信过程中的状态:

    • TCP: 在通信过程中有连接建立、数据传输、连接关闭等状态。
    • UDP: 没有连接的概念,每个数据报都是独立的,不会维护连接状态。
  4. 性能开销:

    • TCP: 因为提供了可靠性,连接状态的维护以及拥塞控制等机制,TCP通常会有较大的性能开销。
    • UDP: 由于是无连接的,性能开销较小,适用于对延迟要求较高的场景。

总体来说,选择TCP还是UDP取决于应用程序的需求。如果对数据的完整性和有序性有较高的要求,或者需要长时间的双向通信,那么TCP可能更适合。如果对实时性要求高,可以容忍一些数据丢失,且通信较为简单,那么UDP可能更适合。

为什么UDP的端口不能telnet

UDP的端口不能通过telnet测试的问题主要与telnet命令的工作原理有关,以及UDP协议的特性。

Telnet是一种基于文本的协议,它通常用于测试TCP连接。当你使用telnet命令测试一个端口时,实际上是在尝试建立一个TCP连接。因此,telnet命令对于UDP端口的测试并不适用,因为UDP是一种面向无连接的协议,没有像TCP那样的连接状态。

Telnet通常通过向指定的主机和端口发送TCP连接请求来测试连接。但是,UDP没有连接的概念,因此telnet无法简单地用于测试UDP端口的可用性。

如果你想测试UDP端口是否可用,可以使用其他工具或编写简单的脚本来发送UDP数据包,例如使用nc命令(netcat)或编写一个简单的UDP客户端程序。这样可以模拟实际的UDP通信,验证UDP端口是否正常工作。

以下是一个使用nc命令测试UDP端口的示例:

nc -u -zv 127.0.0.1 12345

这个命令使用UDP (-u选项) 以及 -z-v 选项测试给定主机(127.0.0.1)和端口(12345)是否可用。 -z 选项表示只进行扫描,而不发送数据。 -v 选项用于显示详细的输出。 

在UDP传输过程中,有socket的概念吗

在UDP传输过程中,仍然涉及到套接字(Socket)的概念,因为UDP通信同样使用套接字 API 来完成数据的发送和接收。套接字是用于在网络上进行通信的抽象概念,不仅适用于TCP,也适用于UDP。

UDPServer 需要考虑连接数吗

在UDP通信中,与TCP不同,UDP是一种面向无连接的协议,它不会维护连接状态。因此,UDP服务器不需要考虑连接数的问题,因为在UDP中不存在持久的连接。每个UDP数据包都是独立的,服务器在处理每个数据包时都不需要保持连接状态。 

UDP服务器的并发性通常是通过创建多个独立的进程或线程来处理并发请求的。每个进程或线程负责处理一个特定的UDP数据包,然后继续等待下一个数据包的到达。这种方式可以处理大量并发的UDP请求,而不需要为每个请求维护连接状态。 需要注意的是,在处理UDP数据包时,服务器应该尽可能快速地完成处理,并且不应该依赖于之前或之后的数据包的状态。

由于UDP不保证数据包的有序性,数据包的到达顺序可能会与发送顺序不同。因此,每个UDP数据包应该包含足够的信息,以便服务器能够独立处理每个数据包。 

 总的来说,UDP服务器在设计时主要考虑如何高效处理每个独立的UDP数据包,而不需要考虑连接数的管理。这使得UDP适用于一些对实时性要求高、可以容忍数据丢失的场景。

windwos查看udp端口占用情况

C:\Users>netstat -ano | find "47808"
  UDP    0.0.0.0:47808          *:*                                    25236
  UDP    10.10.10.1:47808     *:*                                    27376

这说明有2个程序,都使用了(UDP)47808端口了吗?

是的。netstat -ano | find "47808" 命令的输出显示有两个UDP连接正在使用端口47808。具体来说:

第一个连接显示 0.0.0.0:47808,这意味着该端口正在本地机器上监听所有可用的IP地址。与之关联的进程ID(PID)是25236。

第二个连接显示 10.10.10.1:47808,这意味着该端口正在本地机器的特定IP地址(10.10.10.1)上监听。与之关联的进程ID(PID)是27376。

为了确定这两个进程ID对应的程序,您可以使用任务管理器或tasklist命令。在命令提示符下,您可以输入以下命令来查找与这些PID对应的进程:

tasklist /FI "PID eq 25236"  
tasklist /FI "PID eq 27376"

这些命令将显示与PID 25236和27376关联的进程的详细信息,包括进程名称和命令行。这样,您就可以知道是哪些程序正在使用端口47808了。请注意,端口47808不是众所周知的或标准的端口,因此它可能是某些应用程序自定义使用的端口。

UDP端口为什么没有出现 port already use 的情况

端口47808没有出现“port already use”(端口已使用)的情况,是因为UDP端口和TCP端口在操作系统中的处理方式是有所不同的。

TCP端口是唯一的,每个TCP端口只能被一个进程使用。如果一个进程尝试绑定到一个已经被其他进程使用的TCP端口,操作系统会返回一个错误,表明端口已经被使用。

然而,UDP端口并不要求唯一性。在UDP中,多个进程可以同时使用同一个端口号。这是因为UDP是无连接的协议,它不保持长时间的活动连接,也不为每个连接分配唯一的端口号。相反,UDP使用端口号来区分不同的应用程序,以便操作系统能够将接收到的UDP数据包正确地路由到相应的应用程序。

因此,当您看到端口47808被两个进程使用时,这意味着这两个进程都是UDP进程,并且它们都可以同时使用同一个端口号。操作系统会根据数据包的源IP地址和端口号,以及目标IP地址和端口号,将UDP数据包正确地路由到相应的进程。

请注意,尽管UDP端口可以共享,但在某些情况下,这可能会导致问题。例如,如果两个进程都尝试监听同一个UDP端口,并且它们都对接收到的数据包进行相同的处理,那么可能会出现冲突或不可预期的行为。因此,在设计UDP应用程序时,需要仔细考虑端口号的使用,以避免潜在的冲突或问题。

192.168.0.1:12345 --> 192.168.0.2:47808 对于这个udp请求,因为是UDP的,服务器不需要维护连接状态,那么192.168.0.2服务器如何能够回复消息给192.168.0.1的12345端口呢?

在UDP通信中,虽然服务器不需要维护连接状态,但它仍然可以回复消息给客户端的特定端口。这是因为UDP数据包的头部包含了源端口和目标端口信息。

让我们看一下这个过程:

192.168.0.1服务器上使用12345端口发送UDP数据包到192.168.0.2的47808端口。

源IP: 192.168.0.1

源端口: 12345

目标IP: 192.168.0.2

目标端口: 47808

当192.168.0.2服务器收到这个UDP数据包后,它知道这个数据包是从192.168.0.1的12345端口发送过来的,因为UDP头部包含了源端口信息。

当192.168.0.2服务器要回复时,它就知道回复应该发送到192.168.0.1的12345端口。它会构建一个UDP数据包,将回复的数据发送到:

源IP: 192.168.0.2

源端口: 47808

目标IP: 192.168.0.1

目标端口: 12345

这样,即使UDP是无连接的,服务器也能够通过查看收到的UDP数据包的源端口,知道回复应该发送到哪个客户端的哪个端口。客户端则会在指定的端口等待接收回复数据。

所以,虽然UDP本身不需要维护连接状态,但在处理数据包时,服务器仍然可以根据数据包的源端口信息来确定回复消息应该发送到哪个客户端的哪个端口。