On 4-5-2013 4:13, Pedro wrote:
> SERVER:
> 
> import socket               # Import socket module
> 
> s = socket.socket()         # Create a socket object
> host = socket.gethostname() # Get local machine name
> port = 12345                # Reserve a port for your service.
> s.bind((host, port))        # Bind to the port

This won't always work as expected, particularly on machines with multiple 
network
interfaces. Depending on what your situation requires, a simpler

s.bind(('', port))

can be more suitable. (empty string means INADDR_ANY)

> 
> s.listen(5)                 # Now wait for client connection.
> while True:
>    c, addr = s.accept()     # Establish connection with client.
>    print 'Got connection from', addr
>    c.send('Thank you for connecting')

The send() call returns the number of bytes actually sent. This number can be 
LESS than
the length of the buffer you wanted to send! So you will need a loop here to 
make sure
all data is actually transmitted.

The easiest way out is to use this instead:

c.sendall('Thank you for connecting')

However, this might fail due to some I/O error and then it leaves your socket 
in an
undetermined state because you can't tell how much of the data was actually 
transmitted.
(Recovering from errors is problematic if not impossible with sendall, as far 
as I know
the only thing you can do is just close the bad socket and create a new one)


>    c.close()                # Close the connection
> 
> CLIENT:
> import socket               # Import socket module
> 
> s = socket.socket()         # Create a socket object
> host = socket.gethostname() # Get local machine name
> port = 12345                # Reserve a port for your service.
> 
> s.connect((host, port))
> print s.recv(1024)

While this usually seems to work (especially with small buffer sizes) it has 
the same
problem as pointed out above with send(): recv() might not retrieve all data at 
once. It
returns the amount of data actually received in that call.

[warning, hairy details below]

You HAVE to make a loop here to get all chunks of data until they add up to the 
total
data size that you expected. (There's a flag MSG_WAITALL you can pass to recv 
to get
around this. But it is not available on all systems, and on some systems where 
it is
provided, it doesn't work correctly.) Also you need to be careful with the 
buffer size
passed to recv, too large and it causes problems on some systems. Around 60kb 
seems a
good upper bound here.

This usually also means you need to somehow tell the receiving end of the 
socket how
much data is to be expected, and only then send that actual data. One way to do 
this is
to send the length first as a struct-packed integer (4 bytes), and the data 
after that.
Note that even reading the 4 bytes on the receiving side to determine the 
expected
length might be broken up in multiple chunks: you can't even expect recv(4) to 
always
return those 4 bytes. So even that needs to be in a loop...

Other ways to know on the receiving end when to stop reading from the socket is 
to
standardize on some sort of termination character (such as '\0' or perhaps 
'\n'), fixed
length buffers, or to always close the socket after every single message (but 
that is
hugely inefficient if you need to send multiple messages).


> s.close                     # Close the socket when done
> 

Oh, you forgot the parentheses here:

s.close()


Bottom line:
Socket programming on this level is hugely complicated. It doesn't seem too bad 
if you
start of with these simple example programs, but that's false hope. If at all 
possible,
avoid direct socket programming, and use a high-level protocol or library 
instead
(ftp/http/some IPC library/Twisted). Let them deal with the complexity of the 
socket layer.


Regards

Irmen de Jong

-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to