prises de courant de blocage de python, envoyez retourne immédiatement
-
19-09-2019 - |
Question
Je vous écris une application de prise dans le python multithread à l'aide du module de prise. le serveur écoute les connexions et quand il fait une il génère un filetage pour que la douille.
le fil du serveur envoie des données au client. mais le client n'est pas encore prêt à le recevoir. Je pensais que cela aurait causé le serveur d'attendre jusqu'à ce que le client commence recv mais retourne immédiatement à la place
le client appelle ensuite recv qui bloque et aucune donnée n'est reçu.
constructeur de socket client
self.__clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.__clientSocket.connect((server, port))
constructeur de socket serveur
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)
écoute fil accepter
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()
serveur et les clients envoient des méthodes / rec de l'intérieur ClientSocket
receivedData = self.__clientSocket.recv(1024*1024)
self.__clientSocket.send(s)
idées pourquoi envoyer () est de retour tout de suite?
La solution
idées pourquoi envoyer () est de retour tout de suite?
tout envoi () ne fait remplir la mémoire tampon de réseau et le retour ammount d'octets envoyés.
si vous voulez un envoi qui bloque juste recv un message d'accusé de réception du client.
Autres conseils
Le client ne doit pas être prêt à recevoir des données - données file d'attente dans la mémoire tampon de réception de la prise jusqu'à ce que vous êtes prêt à recv () il. Envoyer instantanément parce que le rendement tampon d'émission est pas plein -. Si elle était pleine, envoyer () bloquerait jusqu'à ce qu'il y avait de la place pour les données que vous souhaitez envoyer
La plupart du temps vous ne remplissez - donc ce que vous vivez. D'un côté, vous ne voulez probablement pas un appel recv avec 1024 * 1024 en elle -. Qui est un peu sur le côté haut
Désolé du retard je fixe le problème peu de temps après avoir posé cette question. @Lee merci pour votre réponse, il m'a orienté dans la bonne direction. la solution était d'envoyer un 4byte int spécifiant la taille des données à suivre. le client recevrait toujours ces quatre octets et la taille des données.
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