3

I've wrote two programs to test this p23_server.py for the server side and p23_client.py for the client side :

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 run the p23_server.py and then executed the command :

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

to run the client side and look at what the server outputs.

I executed it once with the socket.send() and once with the socket.sendall() function. The results are the same. The question is why ? shouldn't send just send the data once and the server receive the 32 bytes and that's it ?

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 ?

  • While ``send`` doesn't *guarantee* to send all data, it still *can* send all data given the right circumstances. Refusing to send all data *even when that is possible* would be wasteful. – MisterMiyagi Mar 30 '20 at 11:52
  • Can you clarify what you mean by "shouldn't send just send the data once and the server receive the 32 bytes and that's it"? The size of data for ``send`` and ``recv`` are not strictly related, e.g. you can ``send`` 64 bytes at once and twice ``recv`` 32 bytes. – MisterMiyagi Mar 30 '20 at 11:56
  • this is exactly what I meant. Then what's the differences ? I'm trying to send all sorts of lengths and the results are still the same ... –  Mar 30 '20 at 11:57
  • Then what "sorts of lengths" do you send? The message in your example is 1024 bytes, which comfortably fits into a standard 4096 buffer. Note that the message size may depend on your OS and hardware. – MisterMiyagi Mar 30 '20 at 11:59
  • send 20000 bytes and null terminator for example. trying to send 200000 but it says argument list too long. Using ubuntu 18.04 –  Mar 30 '20 at 12:00
  • How about you generate the messages inside your program instead of passing them in via stdin? Or just passing in the desired *size*, but generating the message content in the program? – MisterMiyagi Mar 30 '20 at 12:01
  • @MisterMiyagi The message in your example is 1024 bytes, which comfortably fits into a standard 4096 buffer." send buffers are way larger than that too, on my machine getting SO_SNDBUF defaults to 16k. – Masklinn Mar 30 '20 at 12:02
  • 1
    @Masklinn I did not want to imply that they cannot be larger (I know they often are). Since their actual size is system dependent, I only wanted to give some (old) default that is a lower bound for all systems the OP is likely to use. The critical part is that 1024 is *way too small* for such a test. – MisterMiyagi Mar 30 '20 at 12:06
  • Does this answer your question? [What is the difference between socket.send() and socket.sendall()?](https://stackoverflow.com/questions/34252273/what-is-the-difference-between-socket-send-and-socket-sendall) – 一二三 Jan 01 '22 at 03:44

3 Answers3

4

just because 99% of the time send() will manage to send all the data in 1 go. Theoretically, when you use send(), you might not see all the data on the server.

To emphasize the difference, a sample pseudo implementation of sendall:

def sendall(data):
    already_sent = 0
    while already_sent < len(data):
        already_sent += send(data[already_sent:])
NadavS
  • 779
  • 3
  • 12
  • to clarify, this has nothing to do with packet size – NadavS Mar 30 '20 at 11:53
  • So it's just theoretically ? Then I should just use send all instead of send to make sure I send the data in its entirety ? –  Mar 30 '20 at 11:59
  • 1
    True, I use sendall by default, and otherwise check the return value of send. – NadavS Mar 30 '20 at 12:15
1

The documentation is clear:

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 the number of bytes sent which may be less than the amount requested. sendall returns None on successfully transmitting all data, and raise an exception on error.

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • I also checked the documentation, but I'm still a bit confused. It seems that what `.sendall( )` can do is just a subset of what `.send( )` can do, if there is no way to determine how much data was successfully sent. What's the point of using `socket.sendall( )`, then? – Paw in Data Apr 02 '20 at 15:40
  • 1
    @Paw .sendall()` loops internally until all the data is sent and you can't tell how many bytes were sent if it fails. In general, use `.sendall()` if you want to ensure the entire buffer is sent and don't want to check the return value and transmit the remaining part of the buffer like `.send()` (see [NadavS's answer](https://stackoverflow.com/a/60929914/235698)). It's a convenience function. – Mark Tolonen Apr 02 '20 at 15:45
0

Why both of the functions produce the same result ?

Because you're sending so little data it will either always work completely or fail completely.

What sendall does is simply loop and send the payload until everything has been sent. If everything fits into the first send, then there is no difference.

Masklinn
  • 34,759
  • 3
  • 38
  • 57