Python下UDP的Socket编程:服务器端因客户端的非正常退出而报错?

服务器端代码


import socket
import threading
import logging
import datetime

logging.basicConfig(format='%(message)s', level=logging.INFO)


class ChatUdpServer:
    def __init__(self, ip='127.0.0.1', port=9999, interval=10,):
        self.sock = socket.socket(type=socket.SOCK_DGRAM)
        self.addr = ip, port
        self.event = threading.Event()
        self.client_set = {}
        self.interval = interval

    def start(self):
        self.sock.bind(self.addr)
        threading.Thread(target=self.recv,).start()

    def recv(self):
        while not self.event.is_set():
            try:
                data, raddr_info = self.sock.recvfrom(1024)
                print(self.sock, raddr_info)
            except ConnectionResetError:
                print('{} client is stop'.format(raddr_info))
                self.client_set.pop(raddr_info)
                continue
            # temp_key = []
            # data, raddr_info = self.sock.recvfrom(1024)
            # if data.strip() == b'QAQ-TAT':
            #     self.client_set[raddr_info] = datetime.datetime.now().timestamp()
            #     continue

            if data.strip() == b'exit':
                self.client_set.pop(raddr_info)
                continue

            current_time = datetime.datetime.now().timestamp()
            self.client_set[raddr_info] = current_time

            logging.info((data, raddr_info))
            msg = '{} send {}'.format(raddr_info, data.decode()).encode()

            for addr, ts in self.client_set.items():
                # if current_time - ts > self.interval:
                #     temp_key.append(addr)
                #     continue
                self.sock.sendto(msg, addr)

            # for i in temp_key:
            #     self.client_set.pop(i)

    def stop(self):
        self.sock.close()


def main():
    cs = ChatUdpServer()
    cs.start()

    while True:
        cmd = input('>>>')
        if cmd.strip() == 'exit':
            cs.stop()
            break
        print(cs.client_set)


if __name__ == '__main__':
    main()

客户端代码

import socket
import threading
import logging
import random

logging.basicConfig(format='%(message)s', level=logging.INFO)


class ChatUdpClient:
    def __init__(self, ip='127.0.0.1', port=9999):
        self.sock = socket.socket(type=socket.SOCK_DGRAM)
        self.raddr = ip, port
        self.event = threading.Event()
        self.randomIP = ip, random.randint(10000, 65535)

    def start(self):
        self.sock.bind(self.randomIP)  # 尝试不连接,结果与connect()下一样。
        # self.sock.connect(self.raddr)
        threading.Thread(target=self.recv,).start()

    def recv(self):
        while not self.event.is_set():
            try:
                data, raddr = self.sock.recvfrom(1024)
            except OSError:
                logging.info('client is quit')
                break
            logging.info(data.decode())

    def send(self, msg: str):
        msg = '{}'.format(msg).encode()
        self.sock.sendto(msg, self.raddr)

    def stop(self):
        self.sock.close()


if __name__ == '__main__':
    cc = ChatUdpClient()
    cc.start()

    while 1:
        cmd = input('{} >>>'.format(cc.randomIP))
        if cmd.strip() == 'exit':
            cc.send(cmd)
            cc.stop()
            break
        cc.send(cmd)


print()语句,用来调试。  服务器端注释代码是为了加心跳包。

环境:windows7 下 Pycharm本地环境测试

1、服务器端开启

2、客户端开启两次(如果随机的端口被占用,重启)

3、client1发送数据,client2发送数据

4、非正常退出client1:点Pycharm终止键

5、client2发送数据多次。此时图示结果如下:

服务器窗口:

Python下UDP的Socket编程:服务器端因客户端的非正常退出而报错?_第1张图片

ConnectionResetError 异常抛出。 且多次被抛出。原因未明。作为UDP连接协议,两端理论上是无联系的。服务器端因客户端的非正常退出而报错???

客户端1窗口:

Python下UDP的Socket编程:服务器端因客户端的非正常退出而报错?_第2张图片

客户端2窗口:

Python下UDP的Socket编程:服务器端因客户端的非正常退出而报错?_第3张图片

解决方法:增加心跳机制,由心跳机制去控制删除异常掉线的客户端。

你可能感兴趣的:(python)