【问题标题】:Trying to get data from a TCP socket connection on a networked device using Python尝试使用 Python 从联网设备上的 TCP 套接字连接获取数据
【发布时间】:2021-08-03 02:52:35
【问题描述】:

我正在尝试编写一个简单的 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 循环在第二次(或第三次)传递中获取“其余”数据的建议。我用以下内容更改了我的简单 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()

【问题讨论】:

  • if not data: continue 应该是 if not data: break 如果你想离开循环。 continue 只会导致对 write 的调用被跳过。
  • 最初是“中断”,然后我在发布前对其进行了更改以试一试。它仍然没有退出。
  • 如果循环永远不会退出,那么if not data 绝对不能为真。仔细检查data 是什么(在里面放一个print)。
  • 这就是我感到困惑的地方。如果我与 netcat 连接,我可以发送命令并接收响应。没有数据流。当我将写入更改为打印时,我得到如下结果:b'76'b'.84,38.4,70.11,49.3\r'在新线路上,然后什么都没有。它只是挂在那里,就像在等待未到来的数据一样。
  • 更多数据 没有到来是可以理解的,因为要发生这种情况,必须向设备发送另一个读取命令。跨度>

标签: python sockets tcp


【解决方案1】:

设备与以\r 终止的行进行面向行通信,因此只需读取整行 - 将 while True 循环 替换为

        data = s.makefile(newline='\r').readline()
        f.write(data)      # Write data to logfile

【讨论】:

  • 不幸的是,这也不起作用。它仍然挂起并且从不写入数据。我在写入之前添加了一个print(data) 调用,它永远不会显示任何返回。我尝试将makefile模式显式设置为读取并设置readline的字节,但似乎都没有任何影响。
  • 啊,我刚刚阅读了用户指南:响应以回车结束(串行接口也可以配置为发送换行符)。为什么readline()(等待 NL)不起作用。
  • 我调整了答案。
  • 这似乎确实可以解决问题。我已经运行了很多次,输出完全符合我的预期。我在用户指南中也看到了这一点,但是除了将它放在命令中之外,我不知道如何使读取操作终止。谢谢。
猜你喜欢
  • 2019-12-14
  • 1970-01-01
  • 2016-05-14
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-13
  • 1970-01-01
相关资源
最近更新 更多