简体   繁体   English

recv 命令在线程和服务器崩溃时无法正常工作

[英]The recv command does not work as it should when threading and the server crashes

I set up a TCP server with the Python socket library that multiple devices can be connected to.我使用可以连接多个设备的 Python 套接字库设置了一个 TCP 服务器。 Since I use threading here, I regularly accept new incoming connections and try to recruit messages in the list.由于我在这里使用线程,因此我会定期接受新的传入连接并尝试在列表中招募消息。 My question is that usually recv threading gets stuck somewhere.我的问题是通常 recv 线程会卡在某个地方。 Sometimes the server, which is running smoothly, sometimes hangs on the first day.有时运行顺利的服务器有时在第一天就挂了。 Showing Incoming Connections but not receiving messages.显示传入连接但未接收消息。 c in clients, so when I print each threaded connection before get in recv command c 在客户端,所以当我在获取 recv 命令之前打印每个线程连接时

Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56446)>
Now on <socket.socket fd=9, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('172.31.15.96', 9680), raddr=('24.133.144.150', 56456)>

In the loop, it continued to show the same port (probably more than thousand times) until it sent a new message from the phone.在循环中,它继续显示相同的端口(可能超过一千次),直到它从手机发送一条新消息。 I am showing the problematic part because the code I wrote is about 500 lines after recv.我展示了有问题的部分,因为我写的代码在 recv 之后大约有 500 行。


import socket
import threading

host = '172.31.15.96'
port = 9680   

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    print("socket created")
    s.bind((host, port))
    print("socket connected {} port".format(port))
    s.listen(250)
    print("socket listening")
    db.logHere.insert_one({"socket log": {"socket created and port opened": port, "Time": time()}})

except socket.error as msg:
    print("Error:", msg)
    db.logHere.insert_one(
        {"Socket Log": {"Error happened": msg, "Time": time()}})

clients = [] # this is list for connected client

def accept():
    while True:
        global clients
        client, addr = s.accept()
        print('Connection from:', addr)
        db.logHere.insert_one({"Connection Log": {"Connection ip from": str(addr[0])+":"+str(addr[1]), "Connection time": time()}, "Time": time()})
        clients.append(client)

def new_message():
    while True:
        for c in clients:
            print("Now on", c) # I just try to use this print if new message thread work or stopped
            try:
                message = c.recv(2048)
                if message:
                    #there is my split or sendall commands. I put if messages inside try advice from : Marquis of Lorne*
            except socket.error as err:
                print("socket error", err)
                c.close()

threading.Thread(target=accept).start()
threading.Thread(target=new_message).start()

What should I do in order to solve this problem and to be able to operate properly with every incoming connection, that is, to maintain a healthy server?我应该怎么做才能解决此问题并能够在每个传入连接中正常运行,即维护健康的服务器? I think my main problem is i cannot delete disconnected client frim that clients list.我认为我的主要问题是我无法删除客户端列表中断开连接的客户端。 try except is not enough for that.尝试除了是不够的。 How can i understand one of client disconnected?我如何理解其中一个客户端断开连接?

**I apologize for my incomplete and incorrect language usage. **对于我不完整和不正确的语言使用,我深表歉意。 My native language is not English.我的母语不是英语。

Here is a minimal fix to your code using select to only read on client sockets having available data and removing closed sockets from the list:这是对您的代码的最小修复,使用select仅读取具有可用数据的客户端套接字并从列表中删除关闭的套接字:

...
def new_message():
    while True:
        # don't try to wait on a empty list...
        if len(clients) == 0:
            sleep(5)
        else:
            ready, _, _ = select.select(clients, [], [])
            # only loop on sockets having available data to read
            for c in ready:
                print("Now on", c) # I just try to use this print if new message thread work or stopped
                try:
                    message = c.recv(2048)
                    if message:
                        #there is my split or sendall commands. I put if messages inside try advice from : Marquis of Lorne*
                        print(message.decode())
                    else:
                        clients.remove(c)
                except socket.error as err:
                    ...

But in fact, you could include the listening socket on the select list, and fully discard one thread:但实际上,您可以将侦听套接字包含在选择列表中,并完全丢弃一个线程:

...
clients = [s] # this is list for connected client AND the listening socket

##def accept():
##    while True:
##        global clients
##        client, addr = s.accept()
##        print('Connection from:', addr)
##        db.logHere.insert_one({"Connection Log": {"Connection ip from": str(addr[0])+":"+str(addr[1]), "Connection time": time()}, "Time": time()})
##        clients.append(client)

def new_message():
    while True:
        ready, _, _ = select.select(clients, [], [])
        for c in ready:                    # loop over ready sockets
            if c == s:                     # special processing for listening one
                try:
                    client, addr = s.accept()
                except socket.error:       # exit if the listening socket is closed
                    for x in clients:
                        x.close()
                    return 
                print('Connection from:', addr)
                db.logHere.insert_one({"Connection Log": {"Connection ip from": str(addr[0])+":"+str(addr[1]), "Connection time": time()}, "Time": time()})
                clients.append(client)
            else:
                print("Now on", c) # I just try to use this print if new message thread work or stopped
                try:
                    message = c.recv(2048)
                    if message:
                        #there is my split or sendall commands. I put if messages inside try advice from : Marquis of Lorne*
                        print(message.decode())
                    else:
                        clients.remove(c)
                except socket.error as err:
                    print("socket error", err)
                    c.close()

##threading.Thread(target=accept).start()
threading.Thread(target=new_message).start()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM