2009-09-24 27 views
12

私は自分自身にPythonのネットワークを教えています。私は自分自身にスレッドを教えていたときに、this pageを見つけたので、スクリプトをコピーし、Python 3.1.1のためにそれらを更新して実行しました。彼らは完璧に働いた。なぜホストは接続を中断していますか?

次に、私はいくつかの変更を行いました。私の目標は単純なことです:

  1. クライアントは整数をpickleしてサーバーに送信します。
  2. サーバーは、ピクルスされた整数を受信し、それをアンピクルし、倍にしてから、ピクルスしてクライアントに返します。
  3. クライアントは、ピクルされた(および倍増された)整数を受け取り、それをアンピクルして出力します。ここで

は、サーバーの:

import pickle 
import socket 
import threading 

class ClientThread(threading.Thread): 
    def __init__(self, channel, details): 
     self.channel = channel 
     self.details = details 
     threading.Thread.__init__ (self) 

    def run(self): 
     print('Received connection:', self.details[0]) 
     request = self.channel.recv(1024) 
     response = pickle.dumps(pickle.loads(request) * 2) 
     self.channel.send(response) 
     self.channel.close() 
     print('Closed connection:', self.details [ 0 ]) 

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
server.bind(('', 2727)) 
server.listen(5) 

while True: 
    channel, details = server.accept() 
    ClientThread(channel, details).start() 

そして、ここでクライアントです:

import pickle 
import socket 
import threading 

class ConnectionThread(threading.Thread): 
    def run(self): 
     client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     client.connect(('localhost', 2727)) 

     for x in range(10): 
      client.send(pickle.dumps(x)) 
      print('Sent:',str(x)) 
      print('Received:',repr(pickle.loads(client.recv(1024)))) 

     client.close() 

for x in range(5): 
    ConnectionThread().start() 

サーバが正常に動作し、私は、クライアントを実行すると、正常に接続し、整数の送信と受信を開始します彼らは期待どおりに倍増した。しかし、非常に速く例外を除きます:

Exception in thread Thread-2: 
Traceback (most recent call last): 
    File "C:\Python30\lib\threading.py", line 507, in _bootstrap_inner 
    self.run() 
    File "C:\Users\Imagist\Desktop\server\client.py", line 13, in run 
    print('Received:',repr(pickle.loads(client.recv(1024)))) 
socket.error: [Errno 10053] An established connection was aborted by the softwar 
e in your host machine 

サーバーは動作し続けて接続は正常です。クライアントだけがクラッシュします。これは何の原因ですか?

EDIT:

import pickle 
import socket 
import threading 

class ConnectionThread(threading.Thread): 
    def run(self): 
     for x in range(10): 
      client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      client.connect(('localhost', 2727)) 
      client.send(pickle.dumps(x)) 
      print('Sent:',str(x)) 
      print('Received:',repr(pickle.loads(client.recv(1024)))) 
      client.close() 

for x in range(5): 
    ConnectionThread().start() 

しかし、私はまだ何が起こっているのか理解していない:私は、次のコードでの作業クライアントが得ました。これはちょうど開いてソケットの束を閉じていないのですか?それに時間的な制限はないはずです(ソケットを閉じた直後にソケットを開くことはできません)。

+0

コードにいくつかの明らかなバグがあります。一方の側で1つのsendコールがもう一方の側で1つのrecvコールを引き起こすと思われます。これは真ではないかもしれません。TCPはストリームプロトコルです。しかし、どのようにエラーメッセージに関連するか分からない。 – leeeroy

+0

@leeroy私は明らかにこれに新しいことがあるので、私は完全にここで批判に開放されています。あなたは、パケット指向ではなくストリームなので、私はTCPを使用すべきではないことを示唆しているようです。パケットを単にデータの非常に短いストリームとして表すことはできませんか?どのように使うべきかはわかりませんが、テストするためだけです。明らかに、私は単一の整数よりもはるかに多くのデータをプッシュするつもりです。 – Imagist

+0

@leeroy(続き)私の目標は、Pythonでのみhttp://www.mcwalter.org/technology/java/httpd/tiny/index.htmlのようなものを実装することです。 – Imagist

答えて

7

あなたのクライアントは現在正しくなっています - ソケットを開いてデータを送信し、返信を受信して​​からソケットを閉じたいと思っています。

エラー元のエラーは、同じ接続で2番目のメッセージを送信しようとしたときに、クライアントが接続のクローズメッセージを受信する原因となった最初の応答を送信した後にソケットを閉じることによって発生しました。

しかし、私はまだ理解していません 何が起こっているのですか。これはちょうど ソケットの束を開閉する 回ですか?

はい。最高のパフォーマンスを実現する方法ではないとしても、これは受け入れられます。

があり、時間と 制限(あなたはそうすぐにそれを閉じ 後にソケットを開くことができ すべきではない)ではないでしょうか?

ソケットを開くたびにクライアントのソケットを開くことができます。新しいローカルポート番号を取得すると、接続が妨害されません。上記のサーバーコードでは、着信接続ごとに新しいスレッドが開始されます。

すべてのIP接続(source_address、source_port、destination_address、destination_port)には4つの部分があり、このクワッド(既知のとおり)は常に接続するために変更する必要があります。 source_portを除くすべてがクライアントソケット用に固定されているので、OSはあなたのために変更されます。

オープニングサーバソケットより厄介です - あなたはすぐに新しいサーバソケットを開きたい場合は、あなたの

server.bind(('', 2727)) 

、あなたがSO_REUSEADDRをよく読んでする必要が上。

-15

これは、Pythonのネットワーキングプログラミングを学ぶ方法ではありません。深刻なことをしている人はいないでしょうから、Pythonのネットワーキングプログラミングをしない方法を学んでいます。

  1. ソケットは低レベルであり、Pythonは高水準言語です。次に、Pythonネットワークプログラミングを行うために、Pythonの方法で、ソケットを完全に扱うことを避け、それをいくつかのモジュールまたはパッケージに残したいとします。低レベルのものがどのように機能するかを知りたい場合は、既存の実装を検討することが必須です。したがって、high-level libraryを学ぶことが不可欠です。
  2. pickle実際には、どのようにあなたがそれらを送信するためにPythonオブジェクトをシリアル化するのではありません。彼らは、あなたが解読しているときにアルビタリコードを実行する偽のピクルスパケットを作ることができるので、あなたが考えている潜在的なセキュリティ上の問題です。安全なシリアライズメソッドを使用する方が良いです。整数オブジェクトにstr()を呼び出し、反対側にint()を呼び出すなど、利用可能なメソッドが多数あるためです。
  3. 同時に複数のクライアントにサービスを提供するには、スレッドを使用しないでください。特に、使用していると思われる「接続ごとに1つのスレッド」アプローチを使用しないでください。あなたの考えるように縮尺は変わりません。スレッドを使用するとエラーが発生しやすく、デバッグが難しく、最終結果には全く利点がありません。bringing problems instead、それらを完全に回避しようとします。ソケット(したがって、項目1で説明したhigher level libraries)は、非ブロックモードで動作し、他のコードが実行されている間に操作でき、スレッドを使用せずにを実行できます。

    @leeroy(続き)私の目標は、このような何かを実装するまで働くことです:http://www.mcwalter.org/technology/java/httpd/tiny/index.htmlだけのPython

    を私は質問にあなたのコメントを見てきました

これは実用的な実装です:

from SimpleHTTPServer import SimpleHTTPRequestHandler as RH 
from SocketServer import TCPServer 

print "serving current directory at port 8000" 
TCPServer(("", 8000), RH).serve_forever() 
+18

-1。このような敵対的な答えが必要ないと思っています。特にPythonに新しい人がいると思います。 – dcrosta

+0

@dcrosta:申し訳ありませんが、私の答えはどこに敵対していますか? – nosklo

+1

@dcrosta - 記録のために、私はPythonには新しいものではなく、ネットワーキングの新機能です。私は、しばらくの間、Pythonの質問に答えてきました。 :) – Imagist

関連する問題