Python: Socket:在蜂窝网络上处理TCP连接

3

我正在使用Python进行套接字编程,开发一个客户端TCP/IP套接字与一个较慢的嵌入式设备进行通信。有时,当响应应该只有一个数据包时,它会被分成两个数据包。我的当前解决方案是sleep() Python程序,等待确保我需要的所有数据已经到达。

comSocket.send('\r')

sleep(1)

comSocket.send('\r')

comSocket.recv(128)

comSocket.send('\r\r')

comSocket.recv(256)



#sending I commands for data

comSocket.send('1I\r\r3I\r\r4I\r\r13I\r\r5I\r\r8I\r\r7I\r\r9I\r\r')

sleep(2)

#receiving data

rawData = comSocket.recv(512)

sleep(1.5)

我在想是否有更好的方法来处理这种情况?


你能具体说明通信渠道吗?这是IP网络、串行总线还是其他的? - Mike Pennington
@Mike Pennington:这是在IP网络上的TCP/IP套接字。 - Tu Hoang
3个回答

1

如果只有一个设备,您应该使用处理低级socket交互的解决方案... Python 有几个类似pexpect, exscript, 或者 paramiko (仅限ssh)... 如果有多个设备并且需要异步通信,请使用@zeekay的答案(尽管异步编程,特别是使用twisted,如果您不熟悉它,可能会很困难)。

我在这里回答了一个关于如何通过telnet发送命令到单个设备的问题...

Catching a dying process in pexpect

上面的答案使代码更高效,但对于初学者来说更具挑战性... 下面的代码更简单,它在TCP/23上建立telnet连接,等待*,发送命令,并将命令的响应放入mydata1中...

import pexpect as px
import sys

def send_this(child, retcode, COMMAND):
    if retcode == 2:
        child.sendline(COMMAND)
    else:
        raise RuntimeError, "Could not complete login, due to socket error"

def expect_this(child, EXPR, timeout = 10):
    return child.expect([px.TIMEOUT, px.EOF, EXPR], timeout = timeout)

HOST = '192.168.49.49'
CMD1 = '1I'
PROMPT = '\*'     #Note: you might not need the backslash
TIMEOUT = 10

child = px.spawn('telnet %s' % HOST)
retcode = expect_this(child, PROMPT)
send_this(child, retcode, CMD1)
retcode = expect_this(child, PROMPT)
mydata1 = child.before    # mydata has the output from CMD1

无论解决方案如何,最重要的是调整超时时间,这样您就不必担心长时间的蜂窝网络延迟(在我的经验中有时超过5秒)。
移动通信中的另一个令人讨厌的动态是,许多消费设备在移动时会定期更改其IP地址(由于它们依赖dhcp)...如果发生这种情况,TCP无能为力...如果您没有静态地址,则连接将在设备拉取新的ip地址时断开。

该设备具有静态IP。我现在正在阅读pexpect,因为我以前从未编写过Python代码,所以它似乎很难理解。这实际上是我第一次尝试 :) - Tu Hoang
@Mike Pennington:我正在使用Linux,Python 2.7.2。 - Tu Hoang
@Mike Pennington:我正在阅读你的脚本。对于我的设备来说,它要简单得多:不涉及任何身份验证,我只需要建立连接,发送3个不同的消息,接收相应的响应,由于延迟很长且波动,我不得不使用 sleep() 函数。我正在寻找更好的处理等待的方法来替代 sleep() - Tu Hoang
是的。提示符将是 *。由于设备建造已经很久了,我们无法对身份验证进行任何操作。 - Tu Hoang
1
@Tanner,没问题...我已经编辑了我认为你需要的内容...如果这不起作用,请告诉我你遇到了什么问题...请注意,如果您需要查看此脚本的终端日志,可以插入child.logfile = sys.stdout - Mike Pennington
显示剩余4条评论

1

0
你需要在一个循环中使用recv函数,并且必须使用协议解析器检查是否已经接收到所有的消息。
condition = True
while condition:
    rawData += sock.recv(512)
    # parse rawData to check if message is complete and if so you can set condition = False to break the loop
    if parser.is_complete(rawData):
        condition = False

需要导入哪个“库”或“模块”来进行解析器操作? - Tu Hoang
那只是一段示例代码..你的设备有协议吗?可能你需要实现或寻找一个实现... - Felipe Cruz

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