Python下UDP的Socket程式設計:伺服器端因客戶端的非正常退出而報錯?
阿新 • • 發佈:2018-11-28
伺服器端程式碼
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傳送資料多次。此時圖示結果如下:
伺服器視窗:
ConnectionResetError 異常丟擲。 且多次被丟擲。原因未明。作為UDP連線協議,兩端理論上是無聯絡的。伺服器端因客戶端的非正常退出而報錯???
客戶端1視窗:
客戶端2視窗:
解決方法:增加心跳機制,由心跳機制去控制刪除異常掉線的客戶端。