[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

network programming: how does s.accept() work?

7stud --

2/25/2008 8:51:00 AM

I have the following two identical clients

#test1.py:-----------
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

host = 'localhost'
port = 5052 #server port

s.connect((host, port))
print s.getsockname()

response = []
while 1:
piece = s.recv(1024)
if piece == '':
break

response.append(piece)


#test3.py:----------------
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

host = 'localhost'
port = 5052 #server port

s.connect((host, port))
print s.getsockname()

response = []
while 1:
piece = s.recv(1024)
if piece == '':
break

response.append(piece)


and this basic server:

#test2.py:--------------
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

host = ''
port = 5052

s.bind((host, port))
s.listen(5)


while 1:
newsock, client_addr = s.accept()
print "orignal socket:", s.getsockname()

print "new socket:", newsock.getsockname()
print "new socket:", newsock.getpeername()
print


I started the server, and then I started the clients one by one. I
expected both clients to hang since they don't get notified that the
server is done sending data, and I expected the server output to show
that accept() created two new sockets. But this is the output I got
from the server:

original socket: ('0.0.0.0', 5052)
new socket, self: ('127.0.0.1', 5052)
new socket, peer: ('127.0.0.1', 50816)

original socket: ('0.0.0.0', 5052)
new socket, self: ('127.0.0.1', 5052)
new socket, peer: ('127.0.0.1', 50818)

The first client I started generated this output:

('127.0.0.1', 50816)

And when I ran the second client, the first client disconnected, and
the second client produced this output:

('127.0.0.1', 50818)

and then the second client hung. I expected the server output to be
something like this:

original socket: ('127.0.0.1', 5052)
new socket, self: ('127.0.0.1', 5053)
new socket, peer: ('127.0.0.1', 50816)

original socket: ('0.0.0.0', 5052)
new socket, self: ('127.0.0.1', 5054)
new socket, peer: ('127.0.0.1', 50818)

And I expected both clients to hang. Can someone explain how accept()
works?
27 Answers

Francesco Bochicchio

2/25/2008 9:43:00 AM

0

On 25 Feb, 09:51, 7stud <bbxx789_0...@yahoo.com> wrote:
> I have the following two identical clients
>
> #test1.py:-----------
> import socket
>
> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>
> host = 'localhost'
> port = 5052  #server port
>
> s.connect((host, port))
> print s.getsockname()
>
> response = []
> while 1:
>     piece = s.recv(1024)
>     if piece == '':
>         break
>
>     response.append(piece)
>
> #test3.py:----------------
> import socket
>
> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>
> host = 'localhost'
> port = 5052  #server port
>
> s.connect((host, port))
> print s.getsockname()
>
> response = []
> while 1:
>     piece = s.recv(1024)
>     if piece == '':
>         break
>
>     response.append(piece)
>
> and this basic server:
>
> #test2.py:--------------
> import socket
>
> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>
> host = ''
> port = 5052
>
> s.bind((host, port))
> s.listen(5)
>
> while 1:
>     newsock, client_addr = s.accept()
>     print "orignal socket:", s.getsockname()
>
>     print "new socket:", newsock.getsockname()
>     print "new socket:", newsock.getpeername()
>     print
>
> I started the server, and then I started the clients one by one.  I
> expected both clients to hang since they don't get notified that the
> server is done sending data, and I expected the server output to show
> that accept() created two new sockets.  But this is the output I got
> from the server:
>
> original socket: ('0.0.0.0', 5052)
> new socket, self: ('127.0.0.1', 5052)
> new socket, peer: ('127.0.0.1', 50816)
>
> original socket: ('0.0.0.0', 5052)
> new socket, self: ('127.0.0.1', 5052)
> new socket, peer: ('127.0.0.1', 50818)
>
> The first client I started generated this output:
>
> ('127.0.0.1', 50816)
>
> And when I ran the second client, the first client disconnected, and
> the second client produced this output:
>
> ('127.0.0.1', 50818)
>
> and then the second client hung.  I expected the server output to be
> something like this:
>
> original socket: ('127.0.0.1', 5052)
> new socket, self: ('127.0.0.1', 5053)
> new socket, peer: ('127.0.0.1', 50816)
>
> original socket: ('0.0.0.0', 5052)
> new socket, self: ('127.0.0.1', 5054)
> new socket, peer: ('127.0.0.1', 50818)
>
> And I expected both clients to hang.  Can someone explain how accept()
> works?

I guess (but I did not try it) that the problem is not accept(), that
should work as you expect,
but the fact that at the second connection your code actually throws
away the first connection
by reusing the same variables without storing the previous values.
This could make the Python
garbage collector to attempt freeing the socket object created with
the first connection, therefore
closing the connection.

If I'm right, your program should work as you expect if you for
instance collect in a list the sockets
returned by accept.

Ciao
----
FB


7stud --

2/25/2008 11:08:00 AM

0

On Feb 25, 2:43 am, bock...@virgilio.it wrote:
> On 25 Feb, 09:51, 7stud <bbxx789_0...@yahoo.com> wrote:
>
>
>
> > I have the following two identical clients
>
> > #test1.py:-----------
> > import socket
>
> > s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>
> > host = 'localhost'
> > port = 5052  #server port
>
> > s.connect((host, port))
> > print s.getsockname()
>
> > response = []
> > while 1:
> >     piece = s.recv(1024)
> >     if piece == '':
> >         break
>
> >     response.append(piece)
>
> > #test3.py:----------------
> > import socket
>
> > s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>
> > host = 'localhost'
> > port = 5052  #server port
>
> > s.connect((host, port))
> > print s.getsockname()
>
> > response = []
> > while 1:
> >     piece = s.recv(1024)
> >     if piece == '':
> >         break
>
> >     response.append(piece)
>
> > and this basic server:
>
> > #test2.py:--------------
> > import socket
>
> > s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>
> > host = ''
> > port = 5052
>
> > s.bind((host, port))
> > s.listen(5)
>
> > while 1:
> >     newsock, client_addr = s.accept()
> >     print "orignal socket:", s.getsockname()
>
> >     print "new socket:", newsock.getsockname()
> >     print "new socket:", newsock.getpeername()
> >     print
>
> > I started the server, and then I started the clients one by one.  I
> > expected both clients to hang since they don't get notified that the
> > server is done sending data, and I expected the server output to show
> > that accept() created two new sockets.  But this is the output I got
> > from the server:
>
> > original socket: ('0.0.0.0', 5052)
> > new socket, self: ('127.0.0.1', 5052)
> > new socket, peer: ('127.0.0.1', 50816)
>
> > original socket: ('0.0.0.0', 5052)
> > new socket, self: ('127.0.0.1', 5052)
> > new socket, peer: ('127.0.0.1', 50818)
>
> > The first client I started generated this output:
>
> > ('127.0.0.1', 50816)
>
> > And when I ran the second client, the first client disconnected, and
> > the second client produced this output:
>
> > ('127.0.0.1', 50818)
>
> > and then the second client hung.  I expected the server output to be
> > something like this:
>
> > original socket: ('127.0.0.1', 5052)
> > new socket, self: ('127.0.0.1', 5053)
> > new socket, peer: ('127.0.0.1', 50816)
>
> > original socket: ('0.0.0.0', 5052)
> > new socket, self: ('127.0.0.1', 5054)
> > new socket, peer: ('127.0.0.1', 50818)
>
> > And I expected both clients to hang.  Can someone explain how accept()
> > works?
>
> I guess (but I did not try it) that the problem is not accept(), that
> should work as you expect,
> but the fact that at the second connection your code actually throws
> away the first connection
> by reusing the same variables without storing the previous values.
> This could make the Python
> garbage collector to attempt freeing the socket object created with
> the first connection, therefore
> closing the connection.
>
> If I'm right, your program should work as you expect if you for
> instance collect in a list the sockets
> returned by accept.
>
> Ciao
> ----
> FB

The question I'm really trying to answer is: if a client connects to a
host at a specific port, but the server changes the port when it
creates a new socket with accept(), how does data sent by the client
arrive at the correct port? Won't the client be sending data to the
original port e.g. port 5052 in the client code above?

7stud --

2/25/2008 11:21:00 AM

0

On Feb 25, 2:43 am, bock...@virgilio.it wrote:
>
> by reusing the same variables without storing the previous values.
> This could make the Python
> garbage collector to attempt freeing the socket object created with
> the first connection, therefore
> closing the connection.
>
> If I'm right, your program should work as you expect if you for
> instance collect in a list the sockets
> returned by accept.
>

Yes, you are right about that. This code prevents the first client
from disconnecting:

newsocks = []
client_addys = []

while 1:
newsock, client_addr = s.accept()
newsocks.append(newsock)
client_addys.append(client_addr)

print "original socket:", s.getsockname()

print "new socket, self:", newsock.getsockname()
print "new socket, peer:", newsock.getpeername()
print

7stud --

2/25/2008 12:17:00 PM

0

On Feb 25, 4:08 am, 7stud <bbxx789_0...@yahoo.com> wrote:
>
> The question I'm really trying to answer is: if a client connects to a
> host at a specific port, but the server changes the port when it
> creates a new socket with accept(), how does data sent by the client
> arrive at the correct port?  Won't the client be sending data to the
> original port e.g. port 5052 in the client code above?
>

If I change the clients to this:


import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

host = 'localhost'
port = 5052 #server port

print s.getsockname() #<------------NEW LINE
s.connect((host, port))
print s.getsockname()

response = []
while 1:
piece = s.recv(1024)
if piece == '':
break

response.append(piece)


Then I get output from the clients like this:

('0.0.0.0', 0)
('127.0.0.1', 51439)

('0.0.0.0', 0)
('127.0.0.1', 51440)


The server port 5052(i.e. the one used in connect()) is not listed
there. That output indicates that the client socket is initially
created with some place holder values, i.e. 0.0.0.0, 0. Then accept()
apparently sends a message back to the client that in effect says,
"Hey, in the future send me data on port 51439." Then the client
fills in that port along with the ip address in its socket object.
Thereafter, any data sent using that socket is sent to that port and
that ip address.





Francesco Bochicchio

2/25/2008 12:19:00 PM

0


>
> The question I'm really trying to answer is: if a client connects to a
> host at a specific port, but the server changes the port when it
> creates a new socket with accept(), how does data sent by the client
> arrive at the correct port?  Won't the client be sending data to the
> original port e.g. port 5052 in the client code above?
>

I'm not an expert, never used TCP/IP below the socket abstraction
level, but I imagine
that after accept, the client side of the connection is someow
'rewired' with the new
socket created on the server side.

Anyhow, this is not python-related, since the socket C library behaves
exactly in the same way.

Ciao
-----
FB

7stud --

2/25/2008 12:29:00 PM

0

On Feb 25, 5:17 am, 7stud <bbxx789_0...@yahoo.com> wrote:
> On Feb 25, 4:08 am, 7stud <bbxx789_0...@yahoo.com> wrote:
>
>
>
> > The question I'm really trying to answer is: if a client connects to a
> > host at a specific port, but the server changes the port when it
> > creates a new socket with accept(), how does data sent by the client
> > arrive at the correct port?  Won't the client be sending data to the
> > original port e.g. port 5052 in the client code above?
>
> If I change the clients to this:
>
> import socket
> import time
> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>
> host = 'localhost'
> port = 5052  #server port
>
> print s.getsockname()  #<------------NEW LINE
> s.connect((host, port))
> print s.getsockname()
>
> response = []
> while 1:
>     piece = s.recv(1024)
>     if piece == '':
>         break
>
>     response.append(piece)
>
> Then I get output from the clients like this:
>
> ('0.0.0.0', 0)
> ('127.0.0.1', 51439)
>
> ('0.0.0.0', 0)
> ('127.0.0.1', 51440)
>
> The server port 5052(i.e. the one used in connect()) is not listed
> there. That output indicates that the client socket is initially
> created with some place holder values, i.e. 0.0.0.0, 0.  Then accept()
> apparently sends a message back to the client that in effect says,
> "Hey, in the future send me data on port 51439."  Then the client
> fills in that port along with the ip address in its socket object.
> Thereafter, any data sent using that socket is sent to that port and
> that ip address.

Implicit in that description is that the client must get assigned a
port number before the call to connect(), or maybe the call to
connect() assigns a port number to the client. In any case, the
server has to receive both the client's ip address and port number as
part of the client's request for a connection in order for the server
to know where to send the response. The server then uses that ip
address and port number to send back a message to the client that
tells the client what port number future communications need to be
sent to.

Thomas Bellman

2/25/2008 5:56:00 PM

0

7stud <bbxx789_05ss@yahoo.com> wrote:

> The question I'm really trying to answer is: if a client connects to a
> host at a specific port, but the server changes the port when it
> creates a new socket with accept(), how does data sent by the client
> arrive at the correct port? Won't the client be sending data to the
> original port e.g. port 5052 in the client code above?

The answer is that the server *doesn't* change its port. As you
could see in the output of your server, the socket that accept()
returned also had local port 5052. Each *client* will however
get a unique local port at *its* end.

A TCP connection is identified by a four-tuple:

( localaddr, localport, remoteaddr, remoteport )

Note that what is local and what is remote is relative to which
process you are looking from. If the four-tuple for a specific
TCP connection is ( 127.0.0.1, 5052, 127.0.0.1, 50816 ) in your
server, it will be ( 127.0.0.1, 50816, 127.0.0.1, 5052 ) in the
client for the very same TCP connection.

Since your client hasn't bound its socket to a specific port, the
kernel will chose a local port for you when you do a connect().
The chosen port will be more or less random, but it will make
sure that the four-tuple identifying the TCP connection will be
unique.


--
Thomas Bellman, Lysator Computer Club, Linköping University, Sweden
"There are many causes worth dying for, but ! bellman @ lysator.liu.se
none worth killing for." -- Gandhi ! Make Love -- Nicht Wahr!

7stud --

2/25/2008 10:03:00 PM

0

On Feb 25, 10:56 am, Thomas Bellman <bell...@lysator.liu.se> wrote:
> 7stud <bbxx789_0...@yahoo.com> wrote:
> > The question I'm really trying to answer is: if a client connects to a
> > host at a specific port, but the server changes the port when it
> > creates a new socket with accept(), how does data sent by the client
> > arrive at the correct port?  Won't the client be sending data to the
> > original port e.g. port 5052 in the client code above?
>
> The answer is that the server *doesn't* change its port.  As you
> could see in the output of your server, the socket that accept()
> returned also had local port 5052.  Each *client* will however
> get a unique local port at *its* end.
>
> A TCP connection is identified by a four-tuple:
>
>     ( localaddr, localport, remoteaddr, remoteport )
>
> Note that what is local and what is remote is relative to which
> process you are looking from.  If the four-tuple for a specific
> TCP connection is ( 127.0.0.1, 5052, 127.0.0.1, 50816 ) in your
> server, it will be ( 127.0.0.1, 50816, 127.0.0.1, 5052 ) in the
> client for the very same TCP connection.
>
> Since your client hasn't bound its socket to a specific port, the
> kernel will chose a local port for you when you do a connect().
> The chosen port will be more or less random, but it will make
> sure that the four-tuple identifying the TCP connection will be
> unique.
>

You seem to be describing what I see:

----server output-----
original socket: ('0.0.0.0', 5053)
new socket, self: ('127.0.0.1', 5053)
new socket, peer: ('127.0.0.1', 49302)

original socket: ('0.0.0.0', 5053)
new socket, self: ('127.0.0.1', 5053)
new socket, peer: ('127.0.0.1', 49303)

---client1 output-----
('0.0.0.0', 0)
('127.0.0.1', 49302)

---client2 output-----
('0.0.0.0', 0)
('127.0.0.1', 49303)


But your claim that the server doesn't change its port flies in the
face of every description I've read about TCP connections and
accept(). The articles and books I've read all claim that the server
port 5053 is a 'listening' port only. Thereafter, when a client sends
a request for a connection to the listening port, the accept() call on
the server creates a new socket for communication between the client
and server, and then the server goes back to listening on the original
socket. Here are two sources for that claim:

Socket Programming How To:
http://www.amk.ca/python/howt...

Tutorial on Network Programming with Python:
http://heather.cs.ucdavis.edu/~matloff/Python...

In either case, there are still some things about the output that
don't make sense to me. Why does the server initially report that its
ip address is 0.0.0.0:

original socket: ('0.0.0.0', 5053)

I would expect the reported ip address to be '127.0.0.1'. Also, since
a socket is uniquely identified by an ip address and port number, then
the ('0.0.0.0', 5053) socket is not the same as this socket:

new socket, self: ('127.0.0.1', 5053)

Grant Edwards

2/25/2008 10:32:00 PM

0

On 2008-02-25, 7stud <bbxx789_05ss@yahoo.com> wrote:
> On Feb 25, 10:56 am, Thomas Bellman <bell...@lysator.liu.se> wrote:
>> 7stud <bbxx789_0...@yahoo.com> wrote:
>> > The question I'm really trying to answer is: if a client connects to a
>> > host at a specific port, but the server changes the port when it
>> > creates a new socket with accept(), how does data sent by the client
>> > arrive at the correct port?  Won't the client be sending data to the
>> > original port e.g. port 5052 in the client code above?
>>
>> The answer is that the server *doesn't* change its port.  As you
>> could see in the output of your server, the socket that accept()
>> returned also had local port 5052.  Each *client* will however
>> get a unique local port at *its* end.
>>
>> A TCP connection is identified by a four-tuple:
>>
>>     ( localaddr, localport, remoteaddr, remoteport )
>>
>> Note that what is local and what is remote is relative to which
>> process you are looking from.  If the four-tuple for a specific
>> TCP connection is ( 127.0.0.1, 5052, 127.0.0.1, 50816 ) in your
>> server, it will be ( 127.0.0.1, 50816, 127.0.0.1, 5052 ) in the
>> client for the very same TCP connection.
>>
>> Since your client hasn't bound its socket to a specific port, the
>> kernel will chose a local port for you when you do a connect().
>> The chosen port will be more or less random, but it will make
>> sure that the four-tuple identifying the TCP connection will be
>> unique.


> But your claim that the server doesn't change its port flies in the
> face of every description I've read about TCP connections and
> accept().

Then the descriptions are wrong.

> The articles and books I've read all claim that the server
> port 5053 is a 'listening' port only.

Not true.

> Thereafter, when a client sends a request for a connection to
> the listening port, the accept() call on the server creates a
> new socket for communication between the client and server,

True. But, it doesn't change the local port number.

Both the listing socket and the connected socket are using
local port number 5053.

> and then the server goes back to listening on the original
> socket.

That's true.

> I would expect the reported ip address to be '127.0.0.1'.
> Also, since a socket is uniquely identified by an ip address
> and port number,

It isn't.

1) You seem to be conflating sockets and TCP connections. A
socket is a kernel-space data structure used to provide a
user-space API to the network stack. In user-space it's
identified by an integer index into a per-process table of
file-like-objects. That socket may or may not have a TCP
connection associated with it. It may or may not be bound
to an IP address and/or port. It is not uniquely identified
by an IP address and port number.

2) A tcp connection is a _different_ thing (though it also
corresponds to a kernel-space data structure), and as Thomas
said, it is uniquely identified by the a four-tuple:

    (localaddr, localport, remoteaddr, remoteport)

[Technically, it's probably a 5-tuple with the above
elements along with a 'connection type' element, but since
we're only discussing TCP in this thread, we can ignore the
connection type axis and only consider the 4-axis space of
TCP connections.]

When a second client connects to the server on port 5053,
the first two elements in the tuple will be the same. One
or both of the last two elements will be different.

> then the ('0.0.0.0', 5053) socket is not the same as this
> socket:
>
> new socket, self: ('127.0.0.1', 5053)

Referring to sockets using that notation doesn't really make
sense. There can be more than one socket associated with the
local address ('127.0.0.1', 5053) or to any other ip/port tuple
you'd like to pick.

--
Grant Edwards grante Yow! YOU PICKED KARL
at MALDEN'S NOSE!!
visi.com

Gabriel Genellina

2/26/2008 4:17:00 AM

0

En Mon, 25 Feb 2008 20:03:02 -0200, 7stud <bbxx789_05ss@yahoo.com>
escribió:
> On Feb 25, 10:56 am, Thomas Bellman <bell...@lysator.liu.se> wrote:
>> 7stud <bbxx789_0...@yahoo.com> wrote:

> In either case, there are still some things about the output that
> don't make sense to me. Why does the server initially report that its
> ip address is 0.0.0.0:
>
> original socket: ('0.0.0.0', 5053)

Because you called "bind" with None (or '' ?) as its first argument; that
means: "listen on any available interface"

> I would expect the reported ip address to be '127.0.0.1'. Also, since
> a socket is uniquely identified by an ip address and port number, then
> the ('0.0.0.0', 5053) socket is not the same as this socket:
>
> new socket, self: ('127.0.0.1', 5053)

You got this *after* a connection was made, coming from your own PC.
127.0.0.1 is your "local" IP; the name "localhost" should resolve to that
number. If you have a LAN, try running the client on another PC. Or
connect to Internet and run the "netstat" command to see the connected
pairs.

--
Gabriel Genellina