Pregunta

Estoy escribiendo una aplicación de socket multiproceso en Python usando el módulo de socket.el servidor escucha las conexiones y cuando obtiene una genera un hilo para ese socket.

el hilo del servidor envía algunos datos al cliente.pero el cliente aún no está listo para recibirlo.Pensé que esto habría provocado que el servidor esperara hasta que el cliente iniciara la recepción, pero en su lugar regresaría inmediatamente.

Luego, el cliente llama a recv, que está bloqueando y nunca se reciben datos.

constructor de sockets de cliente

self.__clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.__clientSocket.connect((server, port))

constructor de sockets de servidor

        self.servSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.servSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        #self.servSock.settimeout(None)
        self.servSock.setblocking(1)
        self.servSock.bind((self.addr,self.port))
        self.servSock.listen(5)

escuchando aceptar hilo

    try:
        (cs, address) = self.servSock.accept()
    except socket.timeout:
        return
    threadName = '\r\nClient %s:%s\r\n' % (cs, address)
    print threadName
    clientSocketHandler = ClientSocket()
    clientSocketHandler.setClientSocket(cs)
    self.clients.newThread(self.clientFunc, {clientSocketHandler : "1"}, threadName).start()

métodos de envío/recepción del servidor y los clientes desde el interior de ClientSocket

receivedData = self.__clientSocket.recv(1024*1024)

self.__clientSocket.send(s)

¿Alguna idea de por qué send() regresa de inmediato?

¿Fue útil?

Solución

  

alguna idea de por qué send () está regresando de inmediato?

toda send () hace es llenar el búfer de red y devolver el ammount de bytes enviados.

si desea un envío que bloquea simplemente recv un mensaje de reconocimiento por parte del cliente.

Otros consejos

El cliente no tiene que estar listo para recibir datos: los datos se pondrán en cola en el búfer de recepción del socket hasta que esté listo para recibirlos.El envío regresa instantáneamente porque el búfer de envío no está lleno; si estuviera lleno, send() se bloquearía hasta que hubiera espacio para los datos que desea enviar.

La mayoría de las veces nunca lo llenarás, de ahí lo que estás experimentando.Por un lado, probablemente no quieras una llamada de recepción con 1024*1024; eso es un poco alto.

Lo siento por el retraso i fijo el problema poco después de hacer esta pregunta. @Lee gracias por su respuesta que me señaló en la dirección correcta. la solución era enviar un 4byte int especificando el tamaño de los datos a seguir. el cliente siempre recibiría estos cuatro bytes y luego el tamaño de los datos.

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

class ClientSocket():
    instance = None
    __connected = False
    __clientSocket = None

    @staticmethod
    def getInstance():
        if ClientSocket.instance == None:
            ClientSocket.instance = ClientSocket()
        return ClientSocket.instance

    def __init__(self):
        self.__connected = False
        self.receivedData = ''
        self.bufSize = 4096
        self.buffer = ''

    def connect(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 = True

    def disconnect(self):
        try:
            self.receivedData = ''
            self.buffer = ''
            self.__clientSocket.close()
        except Exception, e:
            print e
        finally:
            self.__connected = False

    def sendString(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)
            if not 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)
        if not data:
            raise Exception('Expected to receive buffer size')
        return struct.unpack("i", data)[0]

    def flush(self):
        if len(self.buffer)>0:
            self.__clientSocket.sendall(self.buffer)
        self.buffer = ''

    def __sendall(self, s):
        self.buffer = self.buffer + s

    def send(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

    def sendEOC(self):
        self.send(Command(CommandAction.EOC, time()))#send our system time. can be used for ping

    def receive(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)

            if not 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

    def isConnected(self):
        return self.__connected

    def setClientSocket(self, clientSocket):
        self.__clientSocket = clientSocket
        self.__connected = True #assume its connected
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top