使用Python从网络设备的TCP套接字连接获取数据

3

我正在尝试编写一个简单的Python脚本,连接到多个Fluke Thermo-Hygrometers (DewK 1620A),并将温度和湿度读数写入文件,以便我可以导入Splunk。这是我第一次尝试使用Python,我已经接近成功了,但似乎无法通过TCP套接字获取数据。

概述

该脚本从外部JSON文件中读取设备列表,然后打开每个设备的连接,发送命令以获取当前读数,然后将这些读数写入文件。

在我的第一次尝试中,我只是进行了一个“data = s.recv(64)”调用,但设备返回完整结果时不一致。有时我会得到完整的结果(即“69.64,45.9,0,0”),而有时我只会得到部分读数(即“69.64,4”)。

While True循环

经过一些研究,我开始看到使用while True循环的建议,在第二次(或第三次)传递中获取“剩余”的数据。我用以下代码替换了简单的s.recv调用:

while True:
     data = s.recv(64)           # Retrieve data from device
     if not data:                # If no data exists, break loop
          continue
     f.write(data.decode())      # Write data to logfile

很遗憾,现在脚本无法完成。我怀疑循环没有退出,但响应永远不会超过24个字节。我不确定如何进行测试和退出循环。我尝试添加超时,但那会终止整个脚本。

connectDeviceTCP.py

import datetime
import json
import socket

# the command to be passed to the device
command = "read?\r"

# open the deviceLocation.json file for reading
jsonFile = open("devices.json", "r", encoding="utf-8")

# load the contents of the json file into 
locationFile = json.load(jsonFile)
jsonFile.close()

# for each device, connect & retrieve device readings
for device in locationFile["devices"]:

    location = device["location"]
    host = device["host"]
    portStr = device["port"]

    # convert the portStr variable from string to integer
    port = int(portStr)
    
    # open log file for appending.
    f = open("log/" + location + ".log", "a")

    try:

        # create a socket on client using TCP/IP
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        
        # set socket timeout to 3 seconds
        s.settimeout(10)
        
        # connect to host and port
        s.connect((host, port))

    except TimeoutError:

        # write to the log file if the host cannot be reached
        f.write(('\n{:%Y-%m-%d %H:%M:%S} - '.format(datetime.datetime.now())) + location + " - Error: " + host + ":" + portStr + " does not respond.")

    else:

        # send the command to the device
        s.sendall(command.encode())

        # write the timestamp and location to the log
        f.write(('{:%Y-%m-%d %H:%M:%S} - '.format(datetime.datetime.now())) + location + " - ")

        while True:
            data = s.recv(64)           # Retrieve data from device
            if not data:                # If no data exists, break loop
                break
            f.write(data.decode())      # Write data to logfile
        
        # --- The following work except the device doesn't always spit out all the data.
        # receive message string from device
        #data = s.recv(64)

        # write returned values to log file.
        #f.write(data.decode())

    finally:

        # disconnect the client
        s.close()      

        # close log file
        f.close()

1
如果你想要退出循环,if not data: continue 应该改为 if not data: break。使用 continue 只会跳过对 write 的调用。 - Carcigenicate
最初是使用了 "break",但在发布之前我将其更改为 "give it a shot"。但它仍然无法退出。 - MrFarland
如果循环永远不退出,则if not data必定永远为false。请仔细检查data是什么(在其中加入print语句)。 - Carcigenicate
那就是我困惑的地方。如果我使用netcat连接,我可以发送命令并接收响应。没有数据流。当我将写出改为打印时,我会得到以下结果:**b'76'b'.84,38.4,70.11,49.3\r'**在新行上,然后什么也没有了。它就像在等待没有到来的数据一样挂起。 - MrFarland
更多的数据没有到达是可以理解的,因为要发生这种情况,必须向设备发送另一个读取命令。 - Armali
1个回答

1
设备之间使用以\r结尾的行定向通信,因此只需读取一整行 - 将while True loop替换为此操作。
        data = s.makefile(newline='\r').readline()
        f.write(data)      # Write data to logfile

不幸的是,这也没有起作用。它仍然挂起,从未写入数据。我在写入之前添加了一个 print(data) 调用,但它从未显示任何返回的内容。我尝试将 makefile 模式明确设置为读取并设置 readline 的字节,但似乎都没有任何影响。 - MrFarland
啊,我刚在用户指南中读到:_响应以回车符终止(串行接口还可以配置为发送换行符)_。这就解释了为什么 readline()(等待 NL)无法工作。 - Armali
我调整了答案。 - Armali
1
那肯定是解决了问题。我已经运行了很多次,输出结果正好和我预期的一样。我在用户指南中也看到了这个,但除了将其放入命令中,我不知道如何使读取操作终止。谢谢。 - MrFarland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接