Python: Socket: Handling TCP connections over a cell network
I am doing some socket programming in python in which I develop a client TCP/IP socket to communicate with a slow embedded device. So sometimes, when the response is supposed to be only one package, it is broken in to two packages. My current solution to that is to sleep()
the python program, waiting to make sure that all the data 开发者_开发技巧I need already arrived.
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)
I am wondering whether there is a better way to handle this situation?
If it is a single device, you should use a solution that handles the low-level socket
interactions for you... python has several like pexpect
, exscript, or paramiko
(ssh only)... if it is multiple devices and you need asynchronous communication, use @zeekay's answer (although async programming, particularly with twisted, is unpleasant if you're not already familiar with it).
I answered a question with the way you telnet and send a list of commands to a single device here...
Catching a dying process in pexpect
The answer above makes the code efficient, but is more challenging for a beginner to understand... the following code is simpler, it makes a telnet connection on TCP/23, waits for *
, sends a command, and puts the response to the command in 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
Regardless of the solution, the most important thing is tweaking your timeouts so you don't have to concern yourself with the long cell-network delays (which are sometimes over 5 seconds in my experience).
The other nasty dynamic in cellular communication is that many consumer devices routinely change their IP address when they are moving (due to their reliance on dhcp)... there isn't much TCP can do if this happens... if you don't have a static address the connection will drop when the device pulls a new ip address.
Use a networking library like twisted or zeromq.
You have to recv
inside a loop and will have to check if all message has been received with a protocol parser..
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
精彩评论