Skip to content Skip to sidebar Skip to footer

Python Blocking Sockets, Send Returns Immediately

I am writing a multithreaded socket application in Python using the socket module. the server listens for connections and when it gets one it spawns a thread for that socket. the s

Solution 1:

any ideas why send() is returning straight away?

all send() does is fill the network buffer and return the ammount of bytes sent.

if you want a send that blocks just recv an acknowledgement message from the client.

Solution 2:

The client doesn't have to be ready to receive data - data will queue up in the socket's receive buffer until you are ready to recv() it. Send returns instantly because the send buffer isn't full - if it was full, send() would block until there was room for the data you wanted to send.

Most of the time you'll never fill it - hence what you are experiencing. On a side, you probably don't want a recv call with 1024*1024 in it - that's a little on the high side.

Solution 3:

Sorry about the delay i fixed the problem shortly after asking this question. @Lee thanks for your answer it pointed me in the right direction. the solution was to send a 4byte int specifying the size of the data to follow. the client would always receive these four bytes and then the size of the data.

from commandClass import Command
from commandActionClass import CommandAction
import socket
from time import *
import struct

classClientSocket():
    instance = None
    __connected = False
    __clientSocket = None    @staticmethoddefgetInstance():
        if ClientSocket.instance == None:
            ClientSocket.instance = ClientSocket()
        return ClientSocket.instance

    def__init__(self):
        self.__connected = False
        self.receivedData = ''
        self.bufSize = 4096
        self.buffer = ''defconnect(self, server, port):
        if self.isConnected():
            raise Exception('Already connected.')

        self.__clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.__clientSocket.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
        self.__clientSocket.connect((server, port))
        self.__clientSocket.setblocking(1)
        self.__connected = Truedefdisconnect(self):
        try:
            self.receivedData = ''
            self.buffer = ''
            self.__clientSocket.close()
        except Exception, e:
            print e
        finally:
            self.__connected = FalsedefsendString(self,s):
        try:
            if (self.isConnected()):
                self.__clientSocket.send(s)
        except Exception, e:
            print e
            self.disconnect()

    def__pop(self, size):
        data = self.receivedData[:size]
        self.receivedData = self.receivedData[size:]
        return data

    def__recv(self,toRead):
        self.flush()
        while ((len(self.receivedData)<toRead)and(self.isConnected())):
            data = self.__clientSocket.recv(self.bufSize)
            ifnot data:
                self.disconnect()
            self.receivedData = self.receivedData + data

        return self.__pop(toRead)

    def__sendint(self, x):
        self.__sendall(struct.pack("i", x))

    def__recvint(self):
        data = self.__recv(4)
        ifnot data:
            raise Exception('Expected to receive buffer size')
        return struct.unpack("i", data)[0]

    defflush(self):
        iflen(self.buffer)>0:
            self.__clientSocket.sendall(self.buffer)
        self.buffer = ''def__sendall(self, s):
        self.buffer = self.buffer + s

    defsend(self,s):
        try:
            if (not self.isConnected()):
                raise Exception('Socket is not connected')
            data = s.pickle()
            self.__sendint(len(data))
            self.__sendall(data)
        except Exception, e:
            self.disconnect()
            raise e

    defsendEOC(self):
        self.send(Command(CommandAction.EOC, time()))#send our system time. can be used for pingdefreceive(self):
        if (not self.isConnected()):
            raise Exception('Socket Error. Not Connected')
        try:
            #first receive the size of packet
            buffsize = self.__recvint()
            #now receive the actual data
            data = self.__recv(buffsize)

            ifnot data:
                raise Exception('No data to receive')

            command = Command.unpickle(data)
        except Exception, e:
            self.disconnect()
            command = Command(CommandAction.Invalid, None)
            raise e
        #finally?return command

    defisConnected(self):
        return self.__connected

    defsetClientSocket(self, clientSocket):
        self.__clientSocket = clientSocket
        self.__connected = True#assume its connected

Post a Comment for "Python Blocking Sockets, Send Returns Immediately"