Python套接字服务器脚本

Python套接字服务器脚本,python,server,raspberry-pi,raspbian,serversocket,Python,Server,Raspberry Pi,Raspbian,Serversocket,在运行最新Raspbian构建的RasPi(第1代)上设置一个连续运行的python编写的套接字服务器时,我遇到了一个问题。我想做的是将RasPi设置为远程temp的数据服务器。使用ESP32和WiFi进行通信的传感器。 我遇到的问题是我的服务器冻结,这是在不规则的基础上发生的。服务器所做的(或至少应该做的)是,它接受一个远程连接,获取数据,将其分块并将数据保存到一个文件中。脚本一开始运行得很好,一切都按预期运行,但随着时间的推移,它冻结了,为了编码神的爱,我不知道为什么。也许这里有人能帮我 服

在运行最新Raspbian构建的RasPi(第1代)上设置一个连续运行的python编写的套接字服务器时,我遇到了一个问题。我想做的是将RasPi设置为远程temp的数据服务器。使用ESP32和WiFi进行通信的传感器。 我遇到的问题是我的服务器冻结,这是在不规则的基础上发生的。服务器所做的(或至少应该做的)是,它接受一个远程连接,获取数据,将其分块并将数据保存到一个文件中。脚本一开始运行得很好,一切都按预期运行,但随着时间的推移,它冻结了,为了编码神的爱,我不知道为什么。也许这里有人能帮我

服务器代码如下:

import socket
import datetime

PARAMS=['T','P','A','H','B','C']
sensors={'id':0}

for param in PARAMS:
    sensors[param]={'value':0.0,'index_start':0,'index_end':0}


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('192.168.0.10', 7543 ))
s.listen(1)

while True:
    print("****Waiting for connection")
    conn, addr = s.accept()
    #create index for data slicing
    contents=[]
    with conn:
        print('***Incoming connection from: ', addr)
        while conn: # change here!
            print("****What do you have for me? ")
            content = conn.recv(1024)
            print("***Received: ")
            print(content)
            
            contents.append(content)
            print("****Data put into the pool")
            if not content:
                print("****No more data")
                break
            #conn.sendall(data)


    print("***Data passed for processing: ") 
    print(contents)
    
    now=datetime.datetime.now()
    timestamp=now.strftime("%Y-%m-%d %H:%M:%S")
    temp_list=[]
    for c in contents:
       
        clean_c=str(c).lstrip('b\'').rstrip('\'')
        temp_list.append(clean_c)
    text=''.join(temp_list)
    print(text)
    
    for i,param in enumerate(PARAMS):
        sensors[param]['index_start']=text.index(param)+2
        if param != 'T':
            prev_param=PARAMS[i-1]
            sensors[prev_param]['index_end']=text.index(param)
        if param == 'C':
            sensors[param]['index_end']=len(text)-1
    
    sensors['id']=text[:sensors['T']['index_start']-2]
    for param in PARAMS:
        sensors[param]['value']=text[sensors[param]['index_start']:sensors[param]['index_end']]
        if param == 'C':
            sensors[param]['value']=text[sensors[param]['index_start']:]



    value_tuple=(timestamp,sensors['id'],)
    for param in PARAMS:
        value_tuple+=(sensors[param]['value'].replace('.',','),)
        
    text='\t'.join(value_tuple)
    
    with open('/home/pi/Desktop/sensors.csv','a+') as file:
        file.write(text+'\n')    
    
    

    print("****Closing connection")
    print(timestamp)
    #conn.close()
  


冰冻总是发生在地面上

content = conn.recv(1024)
我知道这个函数会锁定我的程序,但我不知道如果没有数据为什么它会出现在那里?怎么做才能做到。。。。好。。不是吗?我在客户端关闭连接,据我所知,
with
函数应该响应socet关闭,对吗

任何帮助都将不胜感激

编辑1:

所以我被问及堆栈错误,但没有。在I Ctr+C之后,我得到了一个标准的响应,只有
content=conn.recv(1024)
reference:

Traceback (most recent call last):
  File "/home/pi/My_Python/Server2.py", line 27, in <module>
    conn, addr = s.accept()
  File "/usr/lib/python3.7/socket.py", line 212, in accept
    fd, addr = self._accept()
KeyboardInterrupt: Execution interrupted
这可能是stop()函数的EOF吗?如果是这样的话,我的服务器有时是否有可能没有收到此消息?这会使它冻结。但是如果是这样的话,我需要有一种方法来查看插座是否打开。如果我的客户端关闭了一个连接,这意味着套接字已经完成,服务器应该检测到它。我可以这样做。但如何做到这一点呢?我本来想从我的剧本中起诉“康恩”,但由于我刚刚开始使用这种语言,这对我来说仍然是压倒性的。那么“conn”是一个对象吗?变量?当我打印它时,我从中得到了大量的数据。那么,它是一根绳子吗?我在这里不知所措

编辑3:

这些帖子的编辑让人觉得很可笑,但我想这就是规则

首先,我要说一声“谢谢你!”感谢到目前为止一直在帮助我的每一个人。你们太棒了D
我花了一段时间才回答,因为我一直在排除故障。我想这是我并不特别喜欢Python的事情之一。没有包含完整功能描述的存储库。例如,我所看到的每个地方都有这样一句话:“socket.recv()是一个阻塞函数”。(引用亚历克·鲍德温(Alec Baldwin)在广告中的话)是的,它是一个阻塞函数,但不,它不是。您可以做的是
conn.recv(59,socket.MSG_DONTWAIT)
它所做的是获取传入缓冲区,就是这样。没有等待。我想这应该与
conn.recv()
相同,我很高兴尝试它,它一直运行正常,直到我得到暂时不可用的
[Errno 11]资源
,基本上说没有什么可读的。我认为这可能是获取EOF信号的问题——从何时抛出异常判断——即使我发送/读取了一定数量的字节。这意味着这个问题与我到目前为止的经历是一致的。冷tl;医生:

  • conn
    上设置超时,以避免客户端可能出现的问题
  • 尝试/除了
    content=conn.recv(1024)
    周围的所有异常,记录它们并关闭套接字
  • contents.append(content)
    发生在检查conn close之前,因此在输入结束时总是以[…,b'']结束
  • 关注客户机,可能使用tcpdump/wireshark进行更多调查
  • 我已使用netcat和telnet测试了以下最小服务器循环:

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('127.0.0.1', 7543 ))
    s.listen(1)
    
    while True:
        print("****Waiting for connection")
        conn, addr = s.accept()
        #create index for data slicing
        contents=[]
        with conn:
            print('***Incoming connection from: ', addr)
            while conn: # change here!
                print("****What do you have for me? ")
                content = conn.recv(1024)
                print("***Received: ")
                print(content)
                
                contents.append(content)
                print("****Data put into the pool")
                if not content:
                    print("****No more data")
                    break
                #conn.sendall(data)
    
    
        print("***Data passed for processing: ") 
        print(contents)
    
    意见1: 通过对netcat和telnet的多次测试,服务器继续按预期工作。使用netcat I Ctrl+C,在我的系统上,它使连接在等待时间上,但服务器继续工作(如预期的那样)。杀死任一客户端(使用
    kill
    )也不会对服务器产生影响

    我可能对服务器造成一些伤害的一种情况是,我使用以下命令强制终止客户端TCP连接:

    $ sudo ss -K dst 127.0.0.1 dport = 7543
    
    在这种情况下,服务器会因以下原因中断:

    Traceback (most recent call last):
      File "./tests.py", line 24, in <module>
        content = conn.recv(1024)
    ConnectionResetError: [Errno 104] Connection reset by peer
    
    上述行为是标准的。实际上,您并没有像问题中那样得到2条流,而是在同一个流中得到2条“消息”(在TCP中,我认为正确的术语是段)。第一个是客户端发送的数据,第二个(EOF)是在套接字终止时发送到应用程序(FIN,ACK+FIN,ACK)。我相信这里的EOF不是由客户端发送的,而是由本地TCP/IP堆栈(内核)发送到您的应用程序,以指示终止序列发生在TCP套接字中,因此您不能“错过它”(对此不是100%确定)。如果你错过了什么,那就是鳍序列

    观察3:recv上的插座超时和阻塞() 您在问什么是
    conn
    :它是特定于特定客户机的套接字对象。这就是回报

    如果您怀疑客户端已连接,但很长一段时间没有发送任何内容(是的,这会阻塞recv(),从而阻塞您的服务器),我建议您尝试。我这样说是因为从我收集的数据来看,客户机在每个循环中连接、发送、关闭。如果由于某种原因没有发生这种情况,而客户端只是连接并等待,那么它会使服务器循环保持忙碌,因为它刚刚接受客户端并等待
    conn
    套接字上的数据

    这是我认为服务器会阻塞
    recv()
    的唯一情况,很可能是由于客户端没有发送。。。在任何情况下,您的服务器都不应该真的“易受攻击”,因此我会尝试
    conn.settimeout(5)
    给客户端5秒的时间进行传输。您需要处理超时异常,该异常在时间过去且客户端未发送任何内容时引发

    我试图用下面的话来谴责这个案子
    $ sudo ss -K dst 127.0.0.1 dport = 7543
    
    Traceback (most recent call last):
      File "./tests.py", line 24, in <module>
        content = conn.recv(1024)
    ConnectionResetError: [Errno 104] Connection reset by peer
    
    ***Incoming connection from:  ('127.0.0.1', 49272)
    ****What do you have for me? 
    ***Received: 
    b'asdasd\r\n'
    ****Data put into the pool
    ****What do you have for me? 
    ***Received: 
    b'asdasd\r\n'
    ****Data put into the pool
    ****What do you have for me? 
    ***Received: 
    b'sadasd\r\n'
    ****Data put into the pool
    ****What do you have for me? 
    ***Received: 
    b'asdsda\r\n'
    ****Data put into the pool
    ****What do you have for me? 
    ***Received: 
    b''  # <<<<<< HERE you receive the "close"
    ****Data put into the pool
    ****No more data
    ***Data passed for processing: 
    [b'asdasd\r\n', b'asdasd\r\n', b'sadasd\r\n', b'asdsda\r\n', b'']  # <<<<<< Here you see you added it in contents
    
    ***Incoming connection from:  ('127.0.0.1', 51194)
    ****What do you have for me? 
    ***Received: 
    b'asdasd\n'
    ****Data put into the pool
    ****What do you have for me? 
    ***Received: 
    b'asdasd\n'
    ****Data put into the pool
    ****What do you have for me? 
    
    ^CTraceback (most recent call last):
      File "./tests.py", line 24, in <module>
        content = conn.recv(1024)
    KeyboardInterrupt
    
    ****Waiting for connection
    ***Incoming connection from:  ('127.0.0.1', 51858)
    ****What do you have for me? 
    ***Received: 
    b'asd\r\n'
    ****Data put into the pool
    ****What do you have for me? 
    !!! ERROR while receiving: timed out
    ***Data passed for processing: 
    [b'asd\r\n']
    ****Waiting for connection
    
    $ telnet localhost 7543
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    asd  # << This was received before timeout
    Connection closed by foreign host. ## << This is the server hanging up
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(('127.0.0.1', 7543 ))
    s.listen(1)
    
    while True:
        print("****Waiting for connection")
        conn, addr = s.accept()
        #create index for data slicing
        contents=[]
        with conn:
            conn.settimeout(5)  # << NEW!
            try:                # << NEW!
                print('***Incoming connection from: ', addr)
                while conn: # change here!
                    print("****What do you have for me? ")
                    content = conn.recv(1024)
                    print("***Received: ")
                    print(content)
                    
                    contents.append(content)
                    print("****Data put into the pool")
                    if not content:
                        print("****No more data")
                        break
                    #conn.sendall(data)
            except Exception as e:
                print("!!! ERROR while receiving:", str(e))
    
    
        print("***Data passed for processing: ") 
        print(contents)