TCP与UDP套接字延迟基准测试

9

我已经在Python中实现了一个小型的基准测试,用于套接字通过TCP和UDP进行通信。令人惊讶的是,TCP的速度几乎是UDP的两倍。

为避免路由效应,服务器和客户端运行在同一Unix机器上,但在不同的线程中。

也许这段代码很有用。以下是服务器代码:

import socket
import sys

host = 'localhost'  
port = 8888
buffersize = 8
server_address = (host, port) 

def start_UDP_server():
    socket_UDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    socket_UDP.bind(server_address)

    print("UDP server is running...")

    while True:
        data, from_address = socket_UDP.recvfrom(buffersize)
        if not data: break
        socket_UDP.sendto(data, from_address)
    socket_UDP.close()


def start_TCP_server():
    socket_TCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket_TCP.bind(server_address)
    socket_TCP.listen(1)

    print("TCP server is running...")

    while True:    
        client, client_address = socket_TCP.accept()

        while True:
            data = client.recv(buffersize)
            if not data: break
            client.sendall(data)

        client.close()

你可以运行start_TCP_server()或者start_UDP_server()

客户端的代码如下:

import socket
import sys
import time

host = 'localhost'  
port = 8888
buffersize = 8
server_address = (host, port) 
client_address = (host, port+1)
N = 1000000


def benchmark_UDP():
    socket_UDP = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
    socket_UDP.bind(client_address)

    print("Benchmark UDP...")

    duration = 0.0
    for i in range(0, N):
        b = bytes("a"*buffersize, "utf-8")
        start = time.time()
        socket_UDP.sendto(b, server_address)
        data, from_address = socket_UDP.recvfrom(buffersize)
        duration += time.time() - start

        if data != b:
            print("Error: Sent and received data are bot the same")

    print(duration*pow(10, 6)/N, "µs for UDP") 


def benchmark_TCP():
    socket_TCP = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket_TCP.connect(server_address)

    print("Benchmark TCP...")

    duration = 0.0
    for i in range(0, N):
        b = bytes("a"*buffersize, "utf-8")
        start = time.time()
        socket_TCP.sendall(b)
        data = socket_TCP.recv(buffersize)
        duration += time.time() - start

        if data != b:
            print("Error: Sent and received data are bot the same")

    print(duration*pow(10, 6)/N, "µs for TCP")
    socket_TCP.close()

对于服务器,您可以通过benchmark_TCP()benchmark_UDP()来开始基准测试。

结果在Unix上大约为25微秒(TCP),大约为54微秒(UDP),而在Windows上更糟糕(大约30微秒的TCP和200微秒以上的UDP)。为什么?我本来期望UDP会有一些优势。


4
这有点不可比较。对于UDP,每次发送/接收都需要将主机名解析为IP地址等,这意味着每次都发送到套接字。对于TCP,您只需一次设置连接,然后每次通过该连接发送数据。如果将TCP的连接设置/关闭放在循环中,则可能更像柑橘类水果(Tangerines)与塞维利亚(Seville)。但无论如何,您的单个延迟指标仅反映了UDP与TCP的一个方面 - 延迟 - 但还有其他因素,如可靠性和吞吐量也很重要。 - DisappointedByUnaccountableMod
1
关于barny的评论,将缓冲区大小提高到64000,看看TCP和UDP谁赢了。 - Rolf of Saxony
如果我使用更大的缓冲区大小,两者都会稍微变慢,这是因为复制操作更大,这是有道理的。 - Michael Dorner
1
萨克森的罗尔夫 - “获胜” - 如果您只想发送32个字节,那么使用64k来测量性能并用其宣布获胜者有什么意义?Michale Dorner的测试也忽略了UDP可能比TCP不可靠的事实 - 但在单台机器上进行的测试很难暴露出交付可靠性的差异。这就是指标 - 您需要了解测量的情况,然后才能开始比较结果。 - DisappointedByUnaccountableMod
可靠性并不是主要目标。实际上,速度和性能才是关键。 - Michael Dorner
显示剩余4条评论
1个回答

6
您的TCP套接字已连接,但UDP套接字未连接。这意味着在每个发送/接收UDP套接字时需要额外处理。对于UDP套接字,请在每一侧调用connect,就像您在TCP套接字上调用connect/accept一样。
iperf这样的程序使用此方法进行准确测量。

1
iperf不提供TCP的往返测量。 - Michael Dorner
你是完全正确的。虽然UDP是无连接的,但是使用这段代码会导致UDP为24微秒TCP为25微秒 - Michael Dorner
对于buffersize = 8000,与之前的8不同,我们得到了TCP的28微秒和UDP的30微秒。 - Michael Dorner
这是否意味着在没有连接的情况下TCP比UDP更好/更快?能否提供更多相关信息的链接?我在所有阅读过的文档中从未看到过这样的陈述。我只关心速度,所以我的问题是:对于大量发送和接收,全局和每个发送哪种协议更快?(TCP / UDP /“带连接”的UDP / ...) - Waroulolz
1
@Waroulolz 嗯,它们有各种优点和缺点。在未连接套接字上发送UDP数据报的一个缺点是,每个发送的数据报都必须进行本地配置以连接到目标,这需要一定的工作量。 - David Schwartz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接