Python Steckdosen blockiert, sofort senden Rückkehr
-
19-09-2019 - |
Frage
Ich bin eine Multithreading-Socket-Anwendung in Python zu schreiben das Socket-Modul. der Server wartet auf Verbindungen, und wenn es einen wird es erzeugt einen Thread für die Buchse.
der Server-Thread an den Client sendet einige Daten. aber der Kunde ist noch nicht bereit, sie zu empfangen. Ich dachte, das der Server verursacht würde warten müssen, bis die Client recv beginnt, sondern kehrt sofort zurück
der Kunde ruft dann recv, die blockiert und keine Daten jemals erhalten.
Client-Socket-Konstruktor
self.__clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.__clientSocket.connect((server, port))
Server-Socket-Konstruktor
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)
Thread hören akzeptieren
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()
Server und Clients senden / rec Methoden von innen Clientsocket
receivedData = self.__clientSocket.recv(1024*1024)
self.__clientSocket.send(s)
irgendwelche Ideen, warum send () kehrt sofort?
Lösung
irgendwelche Ideen, warum send () kehrt sofort?
alle send () tut, ist die Netzwerkpuffer füllen und die ammount der gesendeten Bytes zurück.
Wenn Sie eine Nachricht senden möchten, dass Blöcke empf nur eine Bestätigungsnachricht von dem Client.
Andere Tipps
Der Client muss nicht bereit, Daten zu empfangen - Daten werden in den Sockel der Warteschlange Empfangspuffer bis zu recv bereit sind () es. Senden kehrt sofort, weil der Sendepuffer nicht voll ist -. Wenn es voll ist, send () würde blockieren, bis es Platz für die Daten war die Sie senden wollten
Die meiste Zeit werden Sie es nie füllen - also, was Sie erleben. Auf einer Seite, wollen Sie wahrscheinlich keinen recv Anruf mit 1024 * 1024 in ihm -., Die ein wenig auf der hohen Seite ist
Es tut uns Leid über die Verzögerung festgelegt i das Problem kurz nach diese Frage stellen. @Lee Dank für Ihre Antwort darauf wies mich in der richtigen Richtung. Die Lösung war eine 4-Byte-int Angabe der Größe der Daten senden zu folgen. der Kunde würde diese vier Bytes und dann die Größe der Daten immer erhalten.
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