Python 2.7中的“Connection reset by peer [errno 104]”

4

我在互联网上看到和阅读了很多关于这个特定问题的内容。我正在使用Python中的socket编写一个简单的聊天服务器和客户端,主要是为了学习目的。

我发现了一个问题。

以下是我的服务器代码:

__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

然而,当我添加这行代码时,问题就不会发生了。
现在我有两个问题:
i)我在server.py中处理了异常,为什么这个异常没有被处理,而是导致代码崩溃?如何使服务器更加健壮,我漏掉了什么?
ii)与客户端中的sock.close()的代码行有关的崩溃和异常背后的逻辑是什么?
1个回答

15

i) 你的try-except块没有捕获任何异常。

except的第一个参数必须是你想要捕获的异常类型。 socket.errno不是一个异常类,而是一个模块。你需要捕获 socket.error:

 except socket.error, ex:
     print ex

如果调用堆栈中没有任何异常处理程序,那么任何未被处理的异常都会向外传播,直到它撞到一个except。如果没有处理程序,程序将终止。

ii) 当客户端在不关闭连接的情况下终止时,OS的TCP / IP堆栈会发送一个RST数据包。这大致相当于挂断电话而不说再见。 Python将其转换为文本为“ Connection reset by peer”的异常。它只是意味着由于您调用了read(),Python假设您希望接收某些内容,当连接突然断开时,Python通过引发异常来通知您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接