简体   繁体   中英

Not getting complete data from socket connection

I am trying to write a socket client that receives a data stream from the server. I am able to get the first couple of bytes but then it breaks.

Code:

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()

Output:

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

netcat output of socket:

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

How do I get my socket to output a complete line of data?

I have read the python doc, I have looked at the other examples, but I'm still getting it wrong.

You look for the word "Fahrenheit" in amount_received which is an integer count of the data, not the data itself. The received data is in data which is a Bytes string. recv doesn't know about the lines sent by the server, it just grabs some bytes. But you can buffer the receive data and find the newlines yourself. Assuming the data is byte encoded (ascii, Windows code page, utf-8 - but not utf-16), you can search the bytes for b'\n' and once you know you have a line, convert that to a string for further processing. In this example, I wrote a class that reads a stream of bytes and returns lines as they are found.

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()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM