2

socket モジュールを使用して、Python でマルチスレッド ソケット アプリケーションを作成しています。サーバーは接続をリッスンし、接続を取得すると、そのソケットのスレッドを生成します。

サーバースレッドはクライアントにデータを送信します。しかし、クライアントはまだそれを受け取る準備ができていません。これにより、クライアントが recv を開始するまでサーバーが待機することになると思いましたが、代わりにすぐに戻ります

次に、クライアントはブロックしている recv を呼び出しますが、データはまったく受信されません。

クライアントソケットコンストラクタ

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

サーバーソケットコンストラクター

        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)

リスニング受け入れスレッド

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

サーバーとクライアントは、ClientSocket 内からメソッドを送信/受信します

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

self.__clientSocket.send(s)

send() がすぐに返される理由はありますか?

4

3 に答える 3

4

send() がすぐに返される理由はありますか?

send() が行うことは、ネットワーク バッファを埋めて、送信されたバイト数を返すことだけです。

クライアントからの確認メッセージを受信するだけでブロックする送信が必要な場合。

于 2010-03-12T14:36:08.023 に答える
1

クライアントはデータを受信する準備ができている必要はありません。recv() の準備が整うまで、データはソケットの受信バッファにキューイングされます。送信バッファーがいっぱいではないため、Send は即座に戻ります。送信バッファーがいっぱいの場合、送信したいデータ用のスペースができるまで send() はブロックされます。

ほとんどの場合、それを埋めることはありません - したがって、あなたが経験していることです。一方で、おそらく 1024*1024 を含む recv 呼び出しは必要ないでしょう。これは少し高い側です。

于 2010-03-12T21:47:00.373 に答える
1

この質問をした直後に問題を修正しました。@Leeあなたの答えに感謝します。それは私を正しい方向に向けました。解決策は、続くデータのサイズを指定する 4 バイトの int を送信することでした。クライアントは常にこれらの 4 バイトを受け取り、次にデータのサイズを受け取ります。

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
于 2010-05-03T22:09:53.827 に答える