【问题标题】:Not getting complete data from socket connection未从套接字连接获取完整数据
【发布时间】:2021-05-17 04:56:20
【问题描述】:

我正在尝试编写一个从服务器接收数据流的套接字客户端。 我能够获得前几个字节,但随后就中断了。

代码:

import socket
import sys

readOut = 0                 # serial data
ipaddr = "192.168.1.246"    # ip address of digital thermometer socket server

#def hitsocket(ipaddr):
    #with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
print ("Starting up")
connected = False

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    try:
        s.connect((ipaddr , 8080))
        amount_received = 0
        while True:
            data = s.recv(1024)
            amount_received += len(data)
            if not data:
                break
            print(amount_received, end="\n")
            while True:
                print ("Reading: ", amount_received)
                if "Fahrenheit" in amount_received:
                    cread = amount_received[22:-2]
                    newcread = float(cread)
                    print("readOut ", amount_received, "cread ", cread, 
                          "newcread ", newcread)
                    break
                print ("Restart")
    finally:
        print(sys.stderr, 'closing socket')
        s.close()

输出:

Starting up
19
Writing:  1
Reading:  19
<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'> closing socket
Traceback (most recent call last):
  File "climatemngrDebug-v3.py", line 58, in <module>
    if "Fahrenheit" in amount_received:
TypeError: argument of type 'int' is not iterable

socket的netcat输出:

kermit@whale:~/dev $ netcat 192.168.1.246 8080
mcp9809 Fahrenheit 72.0500
mcp9809 Fahrenheit 72.0500
mcp9809 Fahrenheit 72.0500
mcp9809 Fahrenheit 72.1625
mcp9809 Fahrenheit 72.0500
mcp9809 Fahrenheit 72.0500
mcp9809 Fahrenheit 72.1625
mcp9809 Fahrenheit 72.0500

如何让我的套接字输出一整行数据?

我已经阅读了 python 文档,我也查看了其他示例,但我仍然弄错了。

【问题讨论】:

  • amount_received 是一个整数,而不是数据。名义上,您想查看文本是否在 data 中,它保存接收到的数据(作为您可能想要解码为字符串的字节)。您能告诉我们更多有关传入数据的信息吗?你怎么知道你什么时候收到了正确的金额?它是单次读取,并且遥控器在发送时关闭套接字?它是一系列以换行符结尾的文本字符串吗?您的while 需要知道何时读取了正确数量的数据并且可以提取它。
  • amount_received 实际上是一个包含整数的字符串,我必须将其取出。我无法获得足够的信息来看看出了什么问题。我发布了数据。网猫输出。我的输出应该和 netcat 的输出一样。
  • amount_received += len(data) .. 它是一个整数。 netstat 输出一开始并没有点击我,所以这是一堆以 lline 结尾的字符串。
  • 那条线并没有像我想象的那样。我不知道。
  • @tdelaney 当我用数据交换 amount_received 时,我得到 <_io.textiowrapper name="<stderr>" mode="w" encoding="UTF-8"> 关闭套接字

标签: python python-3.x loops sockets iterator


【解决方案1】:

您在amount_received 中查找“Fahrenheit”一词,它是数据的整数计数,而不是数据本身。接收到的数据在data 中,这是一个Bytes 字符串。 recv 不知道服务器发送的行,它只是抓取一些字节。但是您可以缓冲接收数据并自己查找换行符。假设数据是字节编码的(ascii、Windows 代码页、utf-8 - 但不是 utf-16),您可以在字节中搜索 b'\n',一旦您知道有一行,将其转换为字符串以进行进一步处理.在这个例子中,我编写了一个类,它读取字节流并在找到时返回行。

client.py

import socket
import sys

readOut = 0                 # serial data
#ipaddr = "192.168.1.246"    # ip address of digital thermometer socket server
# todo: change as needed for test server or real server
ipaddr = 'localhost'
ipport = 8080

#def hitsocket(ipaddr):
    #with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
print ("Starting up")
connected = False

class LineReader:

    def __init__(self, socket, encoding='ascii'):
        self.s = socket
        self.encoding = encoding
        self.buf = b''
        self.closed = False

    def readline(self):
        while True:
            index = self.buf.find(b'\n')
            if index >= 0:
                line = self.buf[:index+1]
                self.buf = self.buf[index+1:]
                return line.decode(self.encoding)
            if self.closed:
                line = self.buf
                self.buf = b''
                return line.decode(self.encoding)
            data = self.s.recv(1024)
            self.closed = len(data) == 0
            print("raw recv:", data)
            self.buf += data

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    try:
        s.connect((ipaddr , ipport))
        reader = LineReader(s)
        while True:
            line = reader.readline()
            if not line:
                break
            print(f"Reading: {line}", end='')
            if "Fahrenheit" in line:
                cread = line[22:-2]
                newcread = float(cread)
                print("cread ", cread, 
                      "newcread ", newcread)
    finally:
        print('closing socket', file=sys.stderr)
        s.close()

testserver.py

import socket
import time

test_data =  b'mcp9809 Fahrenheit 72.0500\n'
s = socket.socket()
# todo: change as needed, but must match address in client script
s.bind(('localhost', 8080))
s.listen()
while True:
    c, addr = s.accept()
    # send in framents to test reassembler
    c.send(test_data)
    time.sleep(.1)
    c.send(test_data * 2)
    time.sleep(.1)
    c.send(test_data[:9])
    time.sleep(.1)
    c.send(test_data[9:])
    c.send(test_data * 3 + test_data[:9])
    time.sleep(.1)
    c.send(test_data[9:])
    c.shutdown(socket.SHUT_RDWR)
    c.close()

【讨论】:

  • 首先我收到关于设置 amount_received 的错误。我把它设置为零。现在代码没有错误,但也没有做任何事情。 ://
  • 我修复了 amount_received 问题。我使用我编写的测试服务器运行,它对我有用。我会发布测试代码,你试试看。
  • 我更新了我的服务器代码以获得更好的测试,并且不得不在阅读器中插入一些漏洞。最后,您正在打印 sys.stderr 对象,而不是写入 stderr,因此也对其进行了调整。这个发布的代码对我有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-15
  • 1970-01-01
相关资源
最近更新 更多