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

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • 7stud

    #1

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

    I have the following two identical clients

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

    s = socket.socket(s ocket.AF_INET, socket.SOCK_STR EAM)

    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(s ocket.AF_INET, socket.SOCK_STR EAM)

    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(s ocket.AF_INET, socket.SOCK_STR EAM)

    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.getsock name()
    print "new socket:", newsock.getpeer name()
    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?
  • bockman@virgilio.it

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

    On 25 Feb, 09:51, 7stud <bbxx789_0...@y ahoo.comwrote:
    I have the following two identical clients
    >
    #test1.py:-----------
    import socket
    >
    s = socket.socket(s ocket.AF_INET, socket.SOCK_STR EAM)
    >
    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(s ocket.AF_INET, socket.SOCK_STR EAM)
    >
    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(s ocket.AF_INET, socket.SOCK_STR EAM)
    >
    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.getsock name()
        print "new socket:", newsock.getpeer name()
        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


    Comment

    • 7stud

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

      On Feb 25, 2:43 am, bock...@virgili o.it wrote:
      On 25 Feb, 09:51, 7stud <bbxx789_0...@y ahoo.comwrote:
      >
      >
      >
      I have the following two identical clients
      >
      #test1.py:-----------
      import socket
      >
      s = socket.socket(s ocket.AF_INET, socket.SOCK_STR EAM)
      >
      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(s ocket.AF_INET, socket.SOCK_STR EAM)
      >
      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(s ocket.AF_INET, socket.SOCK_STR EAM)
      >
      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.getsock name()
          print "new socket:", newsock.getpeer name()
          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?

      Comment

      • 7stud

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

        On Feb 25, 2:43 am, bock...@virgili o.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.ap pend(client_add r)

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

        print "new socket, self:", newsock.getsock name()
        print "new socket, peer:", newsock.getpeer name()
        print

        Comment

        • 7stud

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

          On Feb 25, 4:08 am, 7stud <bbxx789_0...@y ahoo.comwrote:
          >
          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(s ocket.AF_INET, socket.SOCK_STR EAM)

          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.





          Comment

          • bockman@virgilio.it

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

            >
            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

            Comment

            • 7stud

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

              On Feb 25, 10:56 am, Thomas Bellman <bell...@lysato r.liu.sewrote:
              7stud <bbxx789_0...@y ahoo.comwrote:
              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:


              Tutorial on Network Programming with 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)

              Comment

              • Gabriel Genellina

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

                En Mon, 25 Feb 2008 20:03:02 -0200, 7stud <bbxx789_05ss@y ahoo.com>
                escribió:
                On Feb 25, 10:56 am, Thomas Bellman <bell...@lysato r.liu.sewrote:
                >7stud <bbxx789_0...@y ahoo.comwrote:
                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

                Comment

                • Roy Smith

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

                  In article <mailman.1255.1 203999457.9267. python-list@python.org >,
                  "Gabriel Genellina" <gagsl-py2@yahoo.com.a rwrote:
                  En Mon, 25 Feb 2008 20:03:02 -0200, 7stud <bbxx789_05ss@y ahoo.com>
                  escribió:
                  On Feb 25, 10:56 am, Thomas Bellman <bell...@lysato r.liu.sewrote:
                  7stud <bbxx789_0...@y ahoo.comwrote:
                  >
                  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"
                  It really means, "Listen on ALL available interfaces".

                  Comment

                  • Steve Holden

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

                    7stud wrote:
                    On Feb 25, 10:56 am, Thomas Bellman <bell...@lysato r.liu.sewrote:
                    >7stud <bbxx789_0...@y ahoo.comwrote:
                    >>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:
                    >
                    There can be many TCP connections to a server all using the same
                    endpoint. Take a look at the traffic coming out of any busy web server:
                    everything that comes out of the same server comes from port 80. That
                    doesn't stop it listening for more connections on port 80.

                    The server disambiguates the packets when it demultiplexes the
                    connection packet streams by using the remote endpoint to differentiate
                    between packets that are part of different connections. TCP guarantees
                    that no two ephemeral port connections from the same client will use the
                    same port.

                    regards
                    Steve
                    --
                    Steve Holden +1 571 484 6266 +1 800 494 3119
                    Holden Web LLC http://www.holdenweb.com/

                    Comment

                    • Roy Smith

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

                      In article <mailman.1257.1 204002544.9267. python-list@python.org >,
                      Steve Holden <steve@holdenwe b.comwrote:
                      TCP guarantees
                      that no two ephemeral port connections from the same client will use the
                      same port.
                      Where "client" is defined as "IP Address". You could certainly have a
                      remote machine that has multiple IP addresses using the same remote port
                      number on different IP addresses for simultaneous connections to the same
                      local port.

                      Comment

                      • Steve Holden

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

                        Roy Smith wrote:
                        In article <mailman.1257.1 204002544.9267. python-list@python.org >,
                        Steve Holden <steve@holdenwe b.comwrote:
                        >
                        > TCP guarantees
                        >that no two ephemeral port connections from the same client will use the
                        >same port.
                        >
                        Where "client" is defined as "IP Address". You could certainly have a
                        remote machine that has multiple IP addresses using the same remote port
                        number on different IP addresses for simultaneous connections to the same
                        local port.
                        Correct.
                        --
                        Steve Holden +1 571 484 6266 +1 800 494 3119
                        Holden Web LLC http://www.holdenweb.com/

                        Comment

                        • Grant Edwards

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

                          On 2008-02-26, Micah Cowan <micah@cowan.na mewrote:
                          7stud, what you seem to be missing, and what I'm not sure if anyone has
                          clarified for you (I have only skimmed the thread), is that in TCP,
                          connections are uniquely identified by a /pair/ of sockets (where
                          "socket" here means an address/port tuple, not a file descriptor).
                          Using the word "socket" as a name for an address/port tuple is
                          precisely what's causing all the confusion. An address/port
                          tuple is simply not a socket from a python/Unix/C point of
                          view, and a socket is not an address/port tuple.
                          It is fine for many, many connections, using the same local
                          port and IP address, so long as the other end has either a
                          different IP address _or_ a different port. There is no issue
                          with lots of processes sharing the same socket for various
                          separate connections, because the /pair/ of sockets is what
                          identifies them. See the "Multiplexi ng" portion of section 1.5
                          of the TCP spec (http://www.ietf.org/rfc/rfc0793.txt).
                          Exactly.
                          Reading some of what you've written elsewhere on this thread,
                          you seem to be confusing this address/port stuff with what
                          accept() returns. This is hardly surprising, as unfortunately,
                          both things are called "sockets": the former is called a
                          socket in the various RFCs,
                          I must admit wasn't familiar with that usage (or had forgotten
                          it).

                          --
                          Grant Edwards grante Yow! Look DEEP into the
                          at OPENINGS!! Do you see any
                          visi.com ELVES or EDSELS ... or a
                          HIGHBALL?? ...

                          Comment

                          • Micah Cowan

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

                            Grant Edwards wrote:
                            On 2008-02-26, Micah Cowan <micah@cowan.na mewrote:
                            >
                            >7stud, what you seem to be missing, and what I'm not sure if anyone has
                            >clarified for you (I have only skimmed the thread), is that in TCP,
                            >connections are uniquely identified by a /pair/ of sockets (where
                            >"socket" here means an address/port tuple, not a file descriptor).
                            >
                            Using the word "socket" as a name for an address/port tuple is
                            precisely what's causing all the confusion. An address/port
                            tuple is simply not a socket from a python/Unix/C point of
                            view, and a socket is not an address/port tuple.
                            FWIW, the word was used to mean the address/port tuple (RFC 793) before
                            there was ever a python/Unix/C concept of "socket".

                            And I totally agree that it's confusing; but I submit that IETF has a
                            stronger claim over the term than Unix/C/Python, which could have just
                            stuck with "network descriptor" or some such. ;)

                            --
                            Micah J. Cowan
                            Programmer, musician, typesetting enthusiast, gamer...

                            Comment

                            Working...