首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python套接字模块:Recv()数据响应中断

Python套接字模块:Recv()数据响应中断
EN

Stack Overflow用户
提问于 2019-04-01 00:30:48
回答 2查看 0关注 0票数 0

说明

我目前正在尝试使用python脚本控制智能电源板。为此,我正在使用与套接字模块的TCP连接。大约75%的时间,我得到了我正在寻找的响应/数据,一切都很完美。但是,大约25%的时间,响应被切断为完全相同的长度,1024字节。这对我没有任何意义,因为我的缓冲区大小实际设置为2048字节。我在使用recv()之间等待的速度似乎也没有影响/导致这种情况。Altough TCP是一个字节流,它是否仍然可能与数据包碎片有关?

代码

主要代码

代码语言:javascript
复制
ip='192.168.0.62'
port=9999

sock_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock_tcp.connect((ip, port))
sock_tcp.send(encrypt('{"system":{"get_sysinfo":{}}}'))
data = sock_tcp.recv(2048)
sock_tcp.close()
print len(data) #On succesful runs output is 1221, on unsuccesful runs it is 1024
rec = decrypt(data[4:])
print str(rec) #See output below

加密功能

代码语言:javascript
复制
def encrypt(string):
    key = 171
    result = pack('>I', len(string))
    for i in string:
        a = key ^ ord(i)
        key = a
        result += chr(a)
    return result

解密功能

代码语言:javascript
复制
def decrypt(string):
    key = 171
    result = ""
    for i in string:
        a = key ^ ord(i)
        key = ord(i)
        result += chr(a)
    return result

输出

我收到的字符串本身。它最像是不相关的,但我认为无论如何我都会包含它。这是变量rec的值。

期望和定期输出

完全想要的输出

{"system":{"get_sysinfo":{"sw_ver":"1.0.6 Build 180627 Rel.081000","hw_ver":"1.0","model":"HS300(US)","deviceId":"80067B24A755F99C4D6C1807455E09F91AB7B2AA","oemId":"5C9E6254BEBAED63B2B6102966D24C17","hwId":"34C41AA028022D0CCEA5E678E8547C54","rssi":-60,"longitude_i":-1222955,"latitude_i":379078,"alias":"TP-LINK_Power Strip_4F01","mic_type":"IOT.SMARTPLUGSWITCH","feature":"TIM:ENE","mac":"B0:BE:76:12:4F:01","updating":0,"led_off":0,"children":[{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA00","state":0,"alias":"CezHeat","on_time":0,"next_action":{"type":-1}},{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA01","state":1,"alias":"CezUVB","on_time":191208,"next_action":{"type":-1}},{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA02","state":1,"alias":"CyanHeat","on_time":191208,"next_action":{"type":-1}},{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA03","state":1,"alias":"ZanderHeat","on_time":191208,"next_action":{"type":-1}},{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA04","state":1,"alias":"CairoHeat","on_time":191208,"next_action":{"type":-1}},{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA05","state":1,"alias":"KodaMister","on_time":191208,"next_action":{"type":-1}}],"child_num":6,"err_code":0}}}

异常输出

{"system":{"get_sysinfo":{"sw_ver":"1.0.6 Build 180627 Rel.081000","hw_ver":"1.0","model":"HS300(US)","deviceId":"80067B24A755F99C4D6C1807455E09F91AB7B2AA","oemId":"5C9E6254BEBAED63B2B6102966D24C17","hwId":"34C41AA028022D0CCEA5E678E8547C54","rssi":-59,"longitude_i":-1222955,"latitude_i":379078,"alias":"TP-LINK_Power Strip_4F01","mic_type":"IOT.SMARTPLUGSWITCH","feature":"TIM:ENE","mac":"B0:BE:76:12:4F:01","updating":0,"led_off":0,"children":[{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA00","state":0,"alias":"CezHeat","on_time":0,"next_action":{"type":-1}},{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA01","state":1,"alias":"CezUVB","on_time":191207,"next_action":{"type":-1}},{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA02","state":1,"alias":"CyanHeat","on_time":191207,"next_action":{"type":-1}},{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA03","state":1,"alias":"ZanderHeat","on_time":191207,"next_action":{"type":-1}},{"id":"80067B24A755F99C4D6C1807455E09F91AB7B2AA04","state":1,"alias":"CairoHeat","on

结论

如果有人能够为我提供关于为什么输出/流被切断的解决方案或解释,那将非常感激。我使用了很多来自这个开源模块的代码。我也希望更多地了解这一切是如何运作的,所以如果你能解释一下,我会非常感激。

EN

回答 2

Stack Overflow用户

发布于 2019-04-01 09:17:36

问题的原因确实是TCP是流协议,因此数据包可以在任何状态进行分段或重组:发送方TCP / IP堆栈,网络设备,接收方TCP / IP堆栈 - 我在其中包含用户层库这里为了简化TCP / IP堆栈。

这就是为什么你应该总是在TCP之上使用更高级别的协议才能在合理的消息中分割流。在这里您可以注意到消息的结尾'}}}',因此您可以在缓冲区中连接输入,直到找到该模式:

代码语言:javascript
复制
def recv_until(c, guard):
    """Receive data from a socket until guard if found on input"""
    guard_sz = len(guard) - 1
    data = b''
    sz = 0
    while True:
        buffer = c.recv(1024)      # read by chuncks of size 1024 (change value to your needs)
        got = len(buffer)
        data += buffer             # concatenate in buffer
        ix = data.find(guard, sz - guard_sz if sz > guard_sz else 0)    # is guard found?
        if ix != -1:
            return (data[:ix + guard_sz + 1],   # return the message, and what could be behind it
                data[ix + guard_sz + 1:])

        sz += got

诀窍是考虑来自最后一个块的guard_sz字节,在防护可以分成两个块的情况下。

票数 0
EN

Stack Overflow用户

发布于 2019-04-01 10:23:54

Marco,请使用recv_into(buffer[, nbytes[, flags]])socket的方法。

我的TCP-microserver示例:

代码语言:javascript
复制
import socket
import struct

def readReliably(s,n):
    buf = bytearray(n)
    view = memoryview(buf)
    sz = s.recv_into(view,n)
    return sz,buf

def writeReliably(s,buf,n):
  sz = 0
  while sz < n:
    sz += s.send(buf[sz:],n-sz)

# Client
host = "127.0.0.1"
port = 23456
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(10)
s.connect((host,port))
# Request
buf = struct.pack("4B",*[0x01,0x02,0x03,0x04])
io.writeReliably(s,buf,4)
# Response
sz,buf = io.readReliably(s,4)
a = struct.unpack("4B",buf)
print repr(a)

# Server
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
#s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
s.bind((host,port))
s.listen(10) # unaccepted connections
while True:
  sk,skfrom = s.accept()
  sz,buf = io.readReliably(sk,4)
  a = struct.unpack("4B",buf)
  print repr(a)
  # ...
  io.writeReliably(sk,struct.pack("4B",*[0x01,0x02,0x03,0x04]))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100008998

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档