在udp套接字中关闭客户端时获取连接重置错误

2024-06-16 11:19:05 发布

您现在位置:Python中文网/ 问答频道 /正文

下面是一个基于udp套接字的python服务器,它创建了两个端口,用于从每个客户端接收数据。但是,当我关闭任何客户端时,程序会引发ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host错误并被卡住

服务器

import socket, simpleaudio as sa
import threading, queue
from threading import Thread, get_ident
import time


isRunning = True

class ServerUDP:
    existing = []
    joined = []
    def __init__(self):

        while True and isRunning:
            try:
                self.socket_rtp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                self.socket_rtp.bind(('', 0))
                self.clients_rtp = set()
                self.recvPackets_rtp = queue.Queue()
                break
            except:
                print("Couldn't bind to that RTP port")

        while True and isRunning:
            try:
                self.socket_rtcp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                self.socket_rtcp.bind(('', 0))
                self.clients_rtcp = set()
                self.recvPackets_rtcp = queue.Queue()
                break
            except:
                break
                print("Couldn't bind to that RTCP port")

    def get_ports(self, socket):
        return socket.getsockname()
    
    def RecvData(self, socket):
        
        while True and isRunning:
            data,addr = socket.recvfrom(3000)
            # print(addr, "read", data)
            y = list(addr)
            addr = tuple(y)

            if socket == self.socket_rtp:
                self.clients_rtp.add(addr)
                self.recvPackets_rtp.put((data,addr)) 
            elif socket == self.socket_rtcp:
                self.clients_rtcp.add(addr)
                self.recvPackets_rtcp.put((data,addr)) 


    def run(self, socket): 

        threading.Thread(target=self.RecvData, args = (socket,)).start() #separate thread for listening to the clients

        i = 1
        while True and isRunning:
            while not (self.recvPackets_rtp.empty() if socket == self.socket_rtp else self.recvPackets_rtcp.empty()):
                
                data,addr = self.recvPackets_rtp.get() if socket == self.socket_rtp else self.recvPackets_rtcp.get()
                # print(data)
                if data:
                    print(threading.get_ident(),": ",i," ")
                    i = i+1
                    for c in (self.clients_rtp if socket == self.socket_rtp else self.clients_rtcp):
                        if c[1]!=addr[1]:      #Don't send to the actual sender but to all others, comparing on the basis of port, because of same machine
                            socket.sendto(data,c)
                            print("send", c)
                else:
                    self.clients_rtp.remove(addr) if socket == self.socket_rtp else self.clients_rtcp.remove(addr)
                    print("Removing", self.clients_rtp)
                    if(self.clients_rtp==set()):
                        self.close()
                        return                  
        self.close(socket)

    def close(self, socket):
        socket.close()


if __name__ == "__main__":

        roomserver = ServerUDP()        
                                       
        t_rtp = Thread(target= roomserver.run, args = (roomserver.socket_rtp,))
        t_rtcp = Thread(target= roomserver.run, args= (roomserver.socket_rtcp,))
        
        t_rtp.start()     
        t_rtcp.start()                                                 
        port_rtp = roomserver.get_ports(roomserver.socket_rtp)[1]
        port_rtcp = roomserver.get_ports(roomserver.socket_rtcp)[1]

        print("port for rtp is", port_rtp, " thread id: ", t_rtp.getName)
        print("port for rtcp is", port_rtcp, " thread id: ", t_rtcp.getName)  
        
        try:
            while 1:
                time.sleep(.1)
        except KeyboardInterrupt:
            print("Attempting to close threads....")
            isRunning = False
            t_rtp.join()
            t_rtcp.join()
            print("Threads successfully closed")        

关于服务器的一点解释是,它旋转两个端口,都用于通过RecvData函数从每个客户端接收数据,run用于将接收到的数据包发送到除实际发送方之外的所有其他客户端

输出/日志

port for rtp is 53035  thread id:  <bound method Thread.getName of <Thread(Thread-1, started 11336)>>
port for rtcp is 53036  thread id:  <bound method Thread.getName of <Thread(Thread-2, started 2820)>>
2820 :  1  
11336 :  1  
11336 :  2  
11336 :  3  
2820 :  2  
11336 :  4  
2820 :  3  
send ('127.0.0.1', 10001)
11336 :  5  
send ('127.0.0.1', 10000)
2820 :  4  
send ('127.0.0.1', 20001)
11336 :  6  
send ('127.0.0.1', 20000)
11336 :  7  
send ('127.0.0.1', 10000)
11336 :  8  
send ('127.0.0.1', 20000)
2820 :  5  
11336 :  9  
send ('127.0.0.1', 10001)
send ('127.0.0.1', 10000)
11336 :  10  
2820 :  6  
send ('127.0.0.1', 20000)
send ('127.0.0.1', 20001)
11336 :  11  
Exception in thread Thread-3:
send ('127.0.0.1', 20000)
Traceback (most recent call last):
  File "C:\Users\nana\AppData\Local\Programs\Python\Python38\lib\threading.py", line 932, in _bootstrap_inner
    self.run()
  File "C:\Users\nana\AppData\Local\Programs\Python\Python38\lib\threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "c:/Users/nana/Desktop/aaaa/bbbb/cccc/server.py", line 42, in RecvData
    data,addr = socket.recvfrom(3000)
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
2820 :  7  
send ('127.0.0.1', 20001)
Exception in thread Thread-4:
Traceback (most recent call last):
  File "C:\Users\nana\AppData\Local\Programs\Python\Python38\lib\threading.py", line 932, in _bootstrap_inner
    self.run()
  File "C:\Users\nana\AppData\Local\Programs\Python\Python38\lib\threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "c:/Users/nana/Desktop/aaaa/bbbb/cccc/server.py", line 42, in RecvData      
    data,addr = socket.recvfrom(3000)
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host

服务器逻辑中的另一个错误是,为了使用ctr+C退出服务器,我使用了一个isRunning变量,所有线程都会不断检查该变量。但它不起作用。我还试图用threading.Event()实现这一点,但仍然没有成功


Tags: inselfsenddataifportsocketthread