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.