【问题标题】:TCP connection and a different buffer size for a client and a server客户端和服务器的 TCP 连接和不同的缓冲区大小
【发布时间】:2026-01-29 14:10:01
【问题描述】:

如果我要在客户端和服务器之间建立连接,并为每个服务器配置不同的缓冲区大小,会发生什么。

这是我客户的代码:

 import socket,sys

TCP_IP = sys.argv[1]
TCP_PORT = int(sys.argv[2])
BUFFER_SIZE = 1024
MESSAGE = "World! Hello, World!"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(MESSAGE)
data = s.recv(BUFFER_SIZE)
s.close()

print "received data:", data

服务器代码:

 import socket,sys

TCP_IP = '0.0.0.0'
TCP_PORT = int(sys.argv[1])
BUFFER_SIZE = 5

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)

while True:
    conn, addr = s.accept()
    print 'New connection from:', addr
    while True:
        data = conn.recv(BUFFER_SIZE)
        if not data: break
        print "received:", data
        conn.send(data.upper()) 
    conn.close()

这意味着我将被限制为只有 5 个字节?这意味着我将无法接收完整的数据包并且会丢失 1024-5 个数据包? 我或者这是否意味着我只能获得 5 个字节的数据包,这意味着当客户端发送它时,我必须将 1024 除以 5 并获得 204.8 个数据包(?),而不是接收一个 1024 字节的数据包。听起来不可能。

该代码中一般发生了什么?

谢谢。

【问题讨论】:

  • (已删除 protocol-buffers - 这是一种特定的序列化格式,不是关于缓冲区的一般内容)

标签: sockets tcp buffer network-protocols


【解决方案1】:

您的论点基于单个send 应该匹配单个recv 的假设。但这种情况并非如此。 TCP 是字节流,而不是基于消息的协议。这意味着所有重要的是传输的字节。而且,如果需要一个或 10 个recv 来读取 50 个字节,这无关紧要。

除此之外,send 也不保证发送完整的缓冲区。它可能只发送缓冲区的一部分,即发送者需要实际检查返回码,以了解现在实际发送了多少给定缓冲区,以及以后需要重试多少发送。

请注意,底层的“数据包”又是另一回事。如果有一个 2000 字节的 send,它通常需要发送多个数据包(取决于底层数据链路层的最大传输单元)。但这并不意味着一个人也需要多个recv。如果所有 2000 字节都已传输到接收方的操作系统级接收缓冲区,那么即使它们以多个数据包传输,也可以一次读取它们。

【讨论】:

  • 那么,发件人如何检查返回码(ACK)?我的意思是在给定的代码中,发件人在哪里检查返回代码?那么这里不同的缓冲区大小呢?究竟会发生什么?根据您的说法,发送者发送消息的速度比接收者接收消息的速度要快得多。但是接收者会收到完整的消息。然后什么?它会以大写形式缓慢发送吗?
  • @DimaCiun:首先,没有“消息”,只有字节。然后,send 将返回在套接字发送缓冲区中放入了多少字节,并且不反映任何 ACK 或对等系统、对等应用程序读取甚至处理的任何内容。是的,发送方可能会在一段时间后自动减速 - 如果发送缓冲区已满,send 将阻塞。并且只有当数据被对端确认时,发送缓冲区才会被清空。参见 TCP Flow Control 了解更多详情。
  • 所以在我的情况下,发送方可以发送最大大小为 1024 字节的段,但服务器只能接收 5 字节。所以发件人会期望一个“1025”的ACK,这意味着收到0-1025,但只会收到5个(0-5)的ACK,所以它会认为1000+字节丢失并再次发送第一个数据包?
  • @DimaCiun:接收方操作系统(不是应用程序)将收到 1024 并为所有这些发送 ACK。这 1024 个字节将被放入与套接字关联的接收缓冲区中 - 这不是应用程序中使用的缓冲区。然后应用程序将从这个接收缓冲区中读取 5 个字节。
【解决方案2】:

您的套接字不会丢失剩余的 1024 - 5 (1019) 个字节。它只是存储在套接字上并准备再次读取!所以,您需要做的就是再次从套接字读取。您要读取的缓冲区大小由您自己决定。而且您不限于 5 个字节,您只是将每次读取的读取缓冲区限制为 5 个字节。因此,要读取 1024 个字节,您必须读取 204 次加上另一次读取,这将是最后一次读取。但请记住,最后一次读取会用 null 填充您的最后一个缓冲区索引。这意味着现在没有更多可用的字节了。

【讨论】:

    最近更新 更多