在Python 2.7中由peer [errno 104]重置连接

Pri*_*ata 4 python sockets python-2.7

我已经在互联网上看到并阅读了很多关于这个特定问题的内容.我正在写一个简单的聊天服务器和客户端使用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()
Run Code Online (Sandbox Code Playgroud)

这是我的客户代码:

__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()
Run Code Online (Sandbox Code Playgroud)

在客户端代码中,当我不这样做时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
Run Code Online (Sandbox Code Playgroud)

然而,当我添加该行时,问题不会发生.

现在我有两个问题:

i)我已经处理了server.py中的异常,为什么没有处理这个异常,为什么它会导致代码崩溃?如何使服务器更健壮,我缺少什么?

ii)sock.close()与客户端中的线路相关的崩溃和异常背后的逻辑是什么?

cg9*_*909 14

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

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

 except socket.error, ex:
     print ex
Run Code Online (Sandbox Code Playgroud)

它会"崩溃"你的代码,因为在调用堆栈中某处未处理的任何异常都会向外传播,直到它命中为止except.如果没有处理程序,程序将被终止.

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