2017-04-14 17 views
0

私はエコーサーバーの例をpythonのドキュメントからコピーしました。しかし、コードを編集すると、データをクライアントに送り返すことはできません。socket.recv()メソッドは、2度目の呼び出し時には返されません。 PythonドキュメントのオリジナルバージョンでPythonソケットは送信せずに受信しません

import socket 

HOST = '' 
PORT = 50007 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.bind((HOST, PORT)) 
s.listen(1) 

conn, addr = s.accept() 
print('Connected by', addr) 

while True: 
    data = conn.recv(1024) 
    if not data: break 
conn.sendall(b'ok') 
conn.close() 

whileループはわずかに異なっている:

while True: 
    data = conn.recv(1024) 
    if not data: break 
    conn.sendall(data) 

クライアントのコード:

import socket 

HOST = 'localhost' 
PORT = 50007 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect((HOST, PORT)) 
s.sendall(b'Hello, world') 
data = s.recv(1024) 
s.close() 
print('Received', repr(data)) 
+0

はどこクライアントのソースコードですか? 'nc'または' telnet'で直接接続していますか? – Kevin

+0

クライアントは接続を閉じるまで受信を返しません。しかし、クライアントは何かを受け取るまで接続を閉じません。 – tdelaney

+0

私はまず、クライアントがサーバによってOKを受け取った後に接続を終了したいと思っています...私の場合はどうしたらいいですか? – no0by5

答えて

2

TCPソケットはデータストリームです。片方のコールを送信し、他方のコールを受信する間には、1対1の相関はありません。実装するプロトコルに基づいて、より高いレベルの相関があります。元のコードでは、クライアントが接続の受信側を閉じるまで、サーバは受信した内容を正確に送信するというルールがありました。その後、サーバーはソケットを閉じました。

変更に伴い、ルールが変更されました。クライアントが接続の受信側を閉じるまで、サーバーはデータの受信と廃棄を続けます。次に、サーバーは「ok」を送信し、ソケットを閉じます。

最初のルールを使用するクライアントは、ソケットを閉じる前に予期しているデータがハングするため、ハングします。この新しいサーバールールで作業したい場合は、ソケットの送信側を終了してサーバーにdoneを通知してから、戻りデータを取得する必要があります。

私は接続のシャットダウン部分にクライアントとサーバーを更新しました。また、受信データが断片化している場合にクライアントが複数のrecvを実行するようにしました。断片化を起こす可能性は低いので、実際の生産コードではひどく壊れてしまうため、実装の複雑さは少ないです。

サーバー

import socket 

HOST = '' 
PORT = 50007 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
s.bind((HOST, PORT)) 
s.listen(1) 

conn, addr = s.accept() 
print('Connected by', addr) 

while True: 
    data = conn.recv(1024) 
    if not data: break 
conn.sendall(b'ok') 
conn.shutdown(socket.SHUT_WR) 
conn.close() 

クライアント

import socket 

HOST = 'localhost' 
PORT = 50007 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.connect((HOST, PORT)) 
s.sendall(b'Hello, world') 
s.shutdown(socket.SHUT_WR) 
data = b'' 
while True: 
    buf = s.recv(1024) 
    if not buf: 
     break 
    data += buf 
s.close() 
print('Received', repr(data)) 
+0

ありがとう、それは私が探していたものです! – no0by5

3

受信及び送信動作の数が原因と一致しなければなりません彼らはブロックしています。

Server listen 
Client connect 
Server receive (this waits until a message arrives at the server) [1] 
Client send 'Hello world' (received by [1]) 
Server receive (because there was data received) [2] 
Client receive [3] 

現在、サーバーとクライアントがブロックされているため、これ以上プログラムを続行することはできません。

解決方法は、サーバーの送信呼び出しを削除したため、クライアントの受信呼び出しを削除することです。

+0

ありがとう、ありがとう!すべてのデータを受け取った後、クライアントに回答を送信する方法はありますか? – no0by5

+0

@ no0by5:クライアントはどのくらいのデータを送信するのかをサーバに伝える必要があります。サーバは 'recv()'に渡す値を知っています。今のところ、サーバーはクライアントが接続を閉じるまで "クライアントが送信するすべてのもの"を受信しようとしているだけです。クライアントが接続を終了するのではなく応答を待つことを止めようとするとうまくいきません。 – Kevin

+0

ありがとう、私はそれを試してみよう! – no0by5

関連する問題