socket.send 和 socket.sendall() 之间的区别

Difference between socket.send and socket.sendall()

我写了两个程序来测试服务器端 p23_server.py 和客户端 p23_client.py :

p23_server.py

#p23_server.py
import socket

HOST = '10.0.2.15'
PORT = 12345

server = socket.socket()
server.bind((HOST,PORT))
server.listen(1)
(client,addr) = server.accept()
while True:
    data = client.recv(32)
    if not data:
        break
    print(data.decode('utf-8'))
server.close()

p23_client.py

#p23_client.py
import socket
import sys

HOST = '10.0.2.15'
PORT = 12345

string = sys.argv[1]
data_to_send = string.encode('utf-8')


s = socket.socket()
s.connect((HOST,PORT))
#s.sendall(data_to_send)
s.send(data_to_send)
s.close()

I 运行 p23_server.py 然后执行命令:

wahalez@wahalez:~/dev/python$pythonp23_client.py$(python-c'for i in range(1024): print("a",end="")')

到运行 客户端并查看服务器输出的内容。

我用 socket.send() 执行了一次,用 socket.sendall() 函数执行了一次。 结果是一样的。问题是为什么? 不应该只发送一次数据,服务器收到 32 个字节,仅此而已?

Unlike send(), this method continues to send data from bytes until either all data has been sent or an error occurs. None is returned on success. On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent.

为什么这两个函数产生相同的结果?

Why both of the functions produce the same result ?

因为您发送的数据太少,它要么总是完全工作,要么完全失败。

sendall 所做的只是循环和 send 有效负载,直到所有内容都已发送。如果一切都符合第一个 send,那么就没有区别。

只是因为 99% 的时间 send() 会一次性发送所有数据。 理论上,当您使用 send() 时,您可能看不到服务器上的所有数据。

为了强调区别,sendall 的伪实现示例:

def sendall(data):
    already_sent = 0
    while already_sent < len(data):
        already_sent += send(data[already_sent:])

文档清晰:

socket.send(bytes[, flags])
Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Returns the number of bytes sent. Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data. For further information on this topic, consult the Socket Programming HOWTO.

Changed in version 3.5: If the system call is interrupted and the signal handler does not raise an exception, the method now retries the system call instead of raising an InterruptedError exception (see PEP 475 for the rationale).

socket.sendall(bytes[, flags])
Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Unlike send(), this method continues to send data from bytes until either all data has been sent or an error occurs. None is returned on success. On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent.

TL;DRsend returns 发送的字节数 可能 少于请求的数量。 sendall returns None 成功传输 所有 数据,并在出错时引发异常。