Subclassing socket

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • groups.20.thebriguy@spamgourmet.com

    #1

    Subclassing socket

    socket objects have a little quirk. If you try to receive 0 bytes on a
    blocking socket, they block. That is, if I call recv(0), it blocks
    (until some data arrives).

    I think that's wrong, but I don't want to argue that. I would like to
    create a subclass of socket that fixes the problem. Ideally, something
    like:

    class new_socket(sock et):
    def recv( self, bufsize, flags=0 ):
    if bufsize == 0:
    return ""
    else:
    return socket.recv( bufsize, flags )

    They only problem is, sockets return socket objects via the accept
    call. And the socket returned is of type socket, of course, not
    new_socket, as I would like. I could override accept() to return a
    new_socket, but I don't know how to convert the old socket to a new
    socket. That is, I'd like to add a method to the class above something
    like:

    def accept( self ):
    conn, addr = socket.accept()
    <convert conn, which is type socket to type new_socket>
    return ( conn, addr )

    Does anyone have any suggestions on how to do the above?

  • Pelmen

    #2
    Re: Subclassing socket

    imho:
    class new_socket(sock et):
    def __init__(self, family=AF_INET, type=SOCK_STREA M, proto=0,
    _sock=None)
    socket.__init__ (self, family=AF_INET, type=SOCK_STREA M, proto=0,
    _sock=None)

    def accept( self ):
    conn, addr = socket.accept()
    return ( new_socket(_soc k=conn), addr )

    but i think your problem have a more simple way then inheritance

    Comment

    • Maksim Kasimov

      #3
      Re: Subclassing socket


      you have to agregate socket and the object must have "fileno" method,
      thats gives a possibility to use instanses of your class with "select.sel ect" function


      class mySocket:

      def __init__(self, ...):
      self.__socket = None
      ...


      def fileno(self):
      return self.__socket.f ileno()


      def connect(self, __host, __port):
      try:
      self.close()
      self.__socket = socket.socket(s ocket.AF_INET, socket.SOCK_STR EAM)
      self.__socket.c onnect((__host, __port))
      ...


      def close(self):
      try:
      if self.__socket is not None:
      self.__socket.c lose()
      finally:
      self.__socket = None

      ...


      groups.20.thebr iguy@spamgourme t.com wrote:[color=blue]
      > socket objects have a little quirk. If you try to receive 0 bytes on a
      > blocking socket, they block. That is, if I call recv(0), it blocks
      > (until some data arrives).
      >
      > I think that's wrong, but I don't want to argue that. I would like to
      > create a subclass of socket that fixes the problem. Ideally, something
      > like:
      >
      > class new_socket(sock et):
      > def recv( self, bufsize, flags=0 ):
      > if bufsize == 0:
      > return ""
      > else:
      > return socket.recv( bufsize, flags )
      >
      > They only problem is, sockets return socket objects via the accept
      > call. And the socket returned is of type socket, of course, not
      > new_socket, as I would like. I could override accept() to return a
      > new_socket, but I don't know how to convert the old socket to a new
      > socket. That is, I'd like to add a method to the class above something
      > like:
      >
      > def accept( self ):
      > conn, addr = socket.accept()
      > <convert conn, which is type socket to type new_socket>
      > return ( conn, addr )
      >
      > Does anyone have any suggestions on how to do the above?
      >[/color]


      --
      Best regards,
      Maksim Kasimov
      mailto: maksim.kasimov@ gmail.com

      Comment

      • groups.20.thebriguy@spamgourmet.com

        #4
        Re: Subclassing socket

        More simple way? What's that?

        Comment

        • Steve Holden

          #5
          Re: Subclassing socket

          groups.20.thebr iguy@spamgourme t.com wrote:[color=blue]
          > socket objects have a little quirk. If you try to receive 0 bytes on a
          > blocking socket, they block. That is, if I call recv(0), it blocks
          > (until some data arrives).
          >[/color]
          Well, arguably you should just try to stop receiving zero bytes. Why on
          earth is your application doing this?
          [color=blue]
          > I think that's wrong, but I don't want to argue that. I would like to
          > create a subclass of socket that fixes the problem. Ideally, something
          > like:
          >
          > class new_socket(sock et):
          > def recv( self, bufsize, flags=0 ):
          > if bufsize == 0:
          > return ""
          > else:
          > return socket.recv( bufsize, flags )
          >[/color]
          That would indeed work, were it not for the complications you are about
          to relate.
          [color=blue]
          > They only problem is, sockets return socket objects via the accept
          > call. And the socket returned is of type socket, of course, not
          > new_socket, as I would like. I could override accept() to return a
          > new_socket, but I don't know how to convert the old socket to a new
          > socket. That is, I'd like to add a method to the class above something
          > like:
          >
          > def accept( self ):
          > conn, addr = socket.accept()
          > <convert conn, which is type socket to type new_socket>
          > return ( conn, addr )
          >
          > Does anyone have any suggestions on how to do the above?
          >[/color]
          You could use the "delegation " pattern - return an object that contains
          a reference to the socket returned by accept(), and have that object
          implement recv() as you outline above, and __getattr__() so that any
          methods your socket *doesn't* implement are instead called on the socket
          returned by accept().

          There's a whole page of stuff at



          but the best read will probably be



          In that article Alex talks about how old-style classes can't inherit
          from basic Python types. This is out of date now for most types, but his
          exposition of the principles of delegation remains a beacon of clarity.

          regards
          Steve
          --
          Steve Holden +44 150 684 7255 +1 800 494 3119
          Holden Web LLC www.holdenweb.com
          PyCon TX 2006 www.python.org/pycon/

          Comment

          • groups.20.thebriguy@spamgourmet.com

            #6
            Re: Subclassing socket

            Steve,

            To your question of why you'd ever receive value:

            This is very common in any network programming. If you send a packet
            of data that has a header and payload, and the header contains the
            length (N) of the payload, then at some point you have to receive N
            bytes. If N is zero, then you receive 0 bytes. Of course, you CAN
            test for N == 0, that's obvious - but why would you if the underlying
            layers worked correctly? Its just extra code to handle an special case.

            Comment

            • groups.20.thebriguy@spamgourmet.com

              #7
              Re: Subclassing socket

              Correction to my last post:

              It should say:

              "To your question of why you'd ever recv(0):"

              Comment

              • Bryan Olson

                #8
                Re: Subclassing socket

                groups.20.thebr iguy@spamgourme t.com wrote:[color=blue]
                > To your question of why you'd ever [recv(0)].
                >
                > This is very common in any network programming. If you send a packet
                > of data that has a header and payload, and the header contains the
                > length (N) of the payload, then at some point you have to receive N
                > bytes. If N is zero, then you receive 0 bytes. Of course, you CAN
                > test for N == 0, that's obvious - but why would you if the underlying
                > layers worked correctly? Its just extra code to handle an special case.[/color]

                We need "extra code" around recv to ensure we get exactly
                N bytes; 'recv(N)' can return less. The most straightforward
                code I know to read exactly N bytes never passes zero to
                recv (untested):


                def recvall(sock, size):
                """ Read and return exactly 'size' bytes from socket 'sock'.
                Kind of the other side of sock.sendall.
                """
                parts = []
                while size > 0:
                data = sock.recv(size)
                if not data:
                raise SomeException(" Socket closed early.")
                size -= len(data)
                parts.append(da ta)
                return ''.join(parts)


                --
                --Bryan

                Comment

                • groups.20.thebriguy@spamgourmet.com

                  #9
                  Re: Subclassing socket

                  I don't think this is true in all cases - for example, if the protocol
                  is UDP, and the packet size is less than the MTU size. Although, I
                  could be wrong - I've always thought that to be the case.

                  I knew someone would have your response, that's why I earlier said I
                  didn't want to argue that. :-)

                  But thanks for your comments.

                  Comment

                  • Paul Rubin

                    #10
                    Re: Subclassing socket

                    groups.20.thebr iguy@spamgourme t.com writes:[color=blue]
                    > I would like to
                    > create a subclass of socket that fixes the problem.[/color]

                    The socket module is in a messy state right now and subclassing
                    sockets doesn't work for implementation-specific reasons besides the
                    issue you described. Take a look at socket.py to see the situation.

                    See also:


                    Comment

                    • Steve Holden

                      #11
                      Re: Subclassing socket

                      groups.20.thebr iguy@spamgourme t.com wrote:[color=blue]
                      > Steve,
                      >
                      > To your question of why you'd ever receive value:
                      >
                      > This is very common in any network programming. If you send a packet
                      > of data that has a header and payload, and the header contains the
                      > length (N) of the payload, then at some point you have to receive N
                      > bytes. If N is zero, then you receive 0 bytes. Of course, you CAN
                      > test for N == 0, that's obvious - but why would you if the underlying
                      > layers worked correctly? Its just extra code to handle an special case.
                      >[/color]
                      I understand all that, but you are presumably also aware that a
                      zero-length result from recv() indicates that the other party to a TCP
                      connection has closed their end of the socket?

                      Given that information, it's hard to know why you would ever really want
                      to recv(0), since the presumably empty return string would effectively
                      prohibit you form detecting that condition.

                      So I'd suggest a test for a requirement of zero bytes, with a
                      corresponding skip of the recv() call in those cases, at least for TCP.

                      regards
                      Steve
                      --
                      Steve Holden +44 150 684 7255 +1 800 494 3119
                      Holden Web LLC www.holdenweb.com
                      PyCon TX 2006 www.python.org/pycon/

                      Comment

                      Working...