web-dev-qa-db-ja.com

Python 2.7のピア[errno104]によって接続がリセットされました

私はインターネットでこの特定の問題についてたくさん見たり読んだりしました。主に学習目的でpython)のソケットを使用して簡単なチャットサーバーとクライアントを作成しています。

ここで問題が発生しました。

これが私のサーバーコードです:

___author__ = 'pchakraverti'

import socket
import select
import sys


class NickSocketMap(object):
    count = 0

    def __init__(self, nick, client_socket):
        self.nick = nick
        self.client_socket = client_socket
        NickSocketMap.count += 1

    @staticmethod
    def display_count():
        print "Total number of clients is %d" % NickSocketMap.count


Host = ""
port = 7575
socket_list = []
nick_list = []
cnt = 0
recv_buffer = 1024


def register_nick(nick, client_socket):
    obj = NickSocketMap(nick, client_socket)
    nick_list.append(obj)


def process_request(request_string, client_socket):
    parts = request_string.split("|")
    if parts[0] == "set_nick":
        register_nick(parts[1], client_socket)
        client_socket.send("nick_set")
    Elif parts[0] == "transmit_msg":
        broadcast_message(parts[1], parts[2])
    return 1


def broadcast_message(message, client_nick):
    for s in nick_list:
        if s.nick == client_nick:
            try:
                s.client_socket.send(message)
            except socket.errno, ex:
                print ex
            break


def run_server():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.bind((Host, port))
    except socket.errno, ex:
        print ex
        sys.exit(-1)
    sock.listen(10)
    # add the parent socket in the list
    socket_list.append(sock)
    # keep the server alive
    while True:
        try:
            read_ready, write_ready, in_error = select.select(socket_list, [], [], 0)
        except select.error, ex:
            print ex
            continue
        for s in read_ready:
            # check if s is the parent socket
            if s == sock:
                # accept new connection and append to list
                try:
                    con, addr = s.accept()
                    if con not in socket_list:
                        socket_list.append(con)
                except socket.errno, ex:
                    print ex
            else:
                try:
                    # receive packet from connected client
                    packet = s.recv(recv_buffer)
                    if not packet:
                        socket_list.remove(s)
                        read_ready.remove(s)
                        for n in nick_list:
                            if n.client_socket == s:
                                nick_list.remove(n)
                                break
                        break
                    print packet
                except socket.errno, ex:
                    print ex
                    continue
                process_request(packet, s)
    sock.close()


if __name__ == "__main__":
    run_server()
_

これが私のクライアントコードです:

___author__ = 'pchakraverti'

import socket


nick = ""
Host = "192.168.0.167"
port = 7575
sock = ""


def welcome():
    print "Welecome to SecuChat!"
    print "---------------------"


def init():
    nick = raw_input("Enter your chat nickname : ")
    print nick
    global sock
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        sock.connect((Host, port))
    except socket.errno, ex:
        print ex
    sock.send("set_nick|"+nick)
    #sock.close()

if __name__ == "__main__":
    welcome()
    init()
_

クライアントコードで、sock.close()を実行しないと、サーバーで例外が発生します。

_Traceback (most recent call last):
  File "server.py", line 102, in <module>
    run_server()
  File "server.py", line 84, in run_server
    packet = s.recv(recv_buffer)
socket.error: [Errno 104] Connection reset by peer
_

ただし、その行を追加しても問題は発生しません。

今私は2つの質問があります:

i)server.pyで例外を処理しましたが、なぜこの例外が処理されないのですか、またなぜコードがクラッシュするのですか?サーバーをより堅牢にするにはどうすればよいですか?また、何が欠けていますか?

ii)クライアントのsock.close()行に関連して、このクラッシュと例外の背後にあるロジックは何ですか?

4
Priyabrata

i)try-exceptブロックは例外をキャッチしません。

exceptの最初の引数は、キャッチする例外のタイプである必要があります。 _socket.errno_は例外クラスではなく、モジュールです。 _socket.error_をキャッチする必要があります:

_ except socket.error, ex:
     print ex
_

コールスタックのどこかで処理されない例外は、exceptに到達するまで外部に伝播するため、コードが「クラッシュ」します。ハンドラーがない場合、プログラムは終了します。

ii)クライアントが接続を閉じずに終了すると、RSTパケットがOSのTCP/IPスタックによって送信されます。これは、さようならを言わずに電話を切るのとほぼ同じです。 Pythonは、これを「ピアによって接続がリセットされました」というテキストで例外に変換します。これは、read() Pythonあなたは何かを受け取ることを期待していて、接続が突然切断されたとき、Pythonは例外を発生させることによって、これを通知します。

14
cg909