How do I flush a socket in python3?
I'm looking to do something like this
def clear_buffer(sock):
try:
while sock.recv(1024): pass
except:
pass
or
def clear_buffer(sock):
while True:
data = sock.recv(1024)
if not data:
break
After attempting to run these two functions neither seem to break the while loop and/or flush out the socket from incoming data. How do I conditionally do something when the socket has stopped receiving data?
while run_network:
recv = True
data = b''
try:
while recv:
try:
packet = socket.recv(10240)
if packet:
data += packet
else:
recv = False
try:
pickle.loads(data)
recv = False
except:
recv = True
except ConnectionResetError:
print(f"{client} has disconnected........")
break
except ConnectionError:
**strong text**
print(f"{client}has a Connection Error.....")
break
Related
I have a server-client setup that works as follows:
The client connects to the server.
The client sends the server a 64-byte message telling the server how much data to read
The server reads that many bytes of data, responds, and the process repeats.
When the client is finished, it sends the server a null message
The server sees that the message length is 0 and closes the connection.
This seems to work fine for the first pass. After the server responds though, it doesn't wait for the client to send more data. Instead the server immediately reads 64 bytes. Since the client hasn't responded, the length of the message is 0 and the connection is closed.
I'm unsure why the server is not pausing until the client sends more data.
Here is the server loop:
self.__stop = False
while not self.__stop:
if self.client_sock:
# Check if the client is still connected and if data is available
try:
rdy_read, rdy_write, sock_err = select.select(
[self.client_sock, ], [self.client_sock, ], [], 5)
except select.error as err:
self.stop()
return
if len(rdy_read) > 0:
# msg length will be sent as bytes
read_data = self.client_sock.recv(64)
# Check if the socket has been closed
if read_data == 0:
self.stop()
else:
msg_length = int(read_data)
msg = self.client_sock.recv(msg_length)
response = f"{[12, 15, 66]}\n"
msg_size = padded_size_of_msg(response)
self.client_sock.send(msg_size)
self.client_sock.send(f"{response}".encode('utf-8'))
else:
print(
f"[THREAD {self.number}] No client connected.")
self.stop()
self.close()
The function padded_size_of_msg() is to calculate the length of the message, pad that number to be 64-bytes, then send that to the client:
def padded_size_of_msg(msg):
msg_length = len(msg)
send_length = str(msg_length).encode('utf-8')
send_length += b' ' * (64- len(send_length))
return send_length
The complete class declaration is below:
class ServerSocketThread(Thread):
def __init__(self, client_sock, client_addr, number):
Thread.__init__(self)
self.client_sock = client_sock
self.client_addr = client_addr
self.number = number
def run(self):
self.__stop = False
while not self.__stop:
if self.client_sock:
# Check if the client is still connected and if data is available
try:
rdy_read, rdy_write, sock_err = select.select(
[self.client_sock, ], [self.client_sock, ], [], 5)
except select.error as err:
print(
f"[THREAD {self.number}] Select() failed on socket with {self.client_addr}")
self.stop()
return
if len(rdy_read) > 0:
# msg length will be sent as bytes
read_data = self.client_sock.recv(64)
# Check if the socket has been closed
if read_data == 0:
print(
f"[THREAD {self.number}] {self.client_addr} closed the socket")
self.stop()
else:
msg_length = int(read_data)
# Client will send msg as bytes. No need to decode to str
msg = self.client_sock.recv(msg_length)
response = f"{[12, 15, 66]}\n"
# Send outputs to client as bytes
msg_size = padded_size_of_msg(response)
self.client_sock.send(msg_size)
self.client_sock.send(f"{response}".encode('utf-8'))
else:
print(
f"[THREAD {self.number}] No client connected.")
self.stop()
self.close()
def stop(self):
self.__stop = True
def close(self):
if self.client_sock:
print(
f"[THREAD {self.number}] Closing conn with {self.client_addr}")
self.client_sock.close()
This ended up being an issue with using nc from the command line.
If I were to try and send "test" from the client, it would register the size as 4-bytes and tell the server to read 4-bytes. From the terminal, nc would instead send "test\n". The newline character '\n' would not be read and instead waited in the queue. When the second recv() was called, it immediately read the '\n' and took that as an indication to close the connection.
In an attempt to solve this, I'm trying to simplify the problem. Suppose I have a receiver listening to both TCP and UDP messages. It will receive several strings, append them to a deque and after receiving "finish" message, it will start processing the deque.
If I receive a UDP message, I need to stop the processing, remove the last item of deque and then continue the processing.
from collections import deque
host = commands.getoutput("hostname -I")
port = 5005
backlog = 5
BUFSIZE = 4096
q = deque()
def read_tcp(s):
conn, addr = s.accept()
print('Connected with', *addr)
while 1:
data = conn.recv(BUFFER_SIZE)
if not data: break
print "received data:", data
conn.send(data) # echo
conn.close()
if (data == 'finish'):
processP(q)
else:
q.append(data)
def read_udp(s):
data,addr = s.recvfrom(1024)
print("received message:", data)
del q[-1]
processP(q):
text = q.popleft()
textReverse = text[::-1]
print(textReverse)
def run():
# create tcp socket
tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
tcp.bind((host,port))
except socket.error as err:
print('Bind failed', err)
return
tcp.listen(1)
# create udp socket
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
udp.bind((host,port))
print('***Socket now listening at***:', host, port)
input = [tcp,udp]
try:
while True:
inputready,outputready,exceptready = select(input,[],[])
for s in inputready:
if s == tcp:
read_tcp(s)
elif s == udp:
read_udp(s)
else:
print("unknown socket:", s)
# Hit Break / Ctrl-C to exit
except KeyboardInterrupt:
print('\nClosing')
raise
tcp.close()
udp.close()
if __name__ == '__main__':
run()
I have problem in pausing the program upon receiving a UDP message and then returning to the processing phase. Right now, if a UDP message is sent to my program while processing, it won't receive the message until the end of processing (and then the deque is empty). I thought maybe threading or multiprocessing may help, but I can't figure out how to apply them to the code.
Nobody forces you to empty out the dequeue. You can check if an UDP message has arrived before dequeueing the next workload. And that is as far as you can get with threads, as they do not allow you to interrupt arbitrary code. They can always only be terminated cooperatively.
If your single item processing takes too long, then multiprocessing of work-items is an option, as you can kill an external process.
Use select.select to check for incoming data on your sockets with a short timeout, before continuing to process the next workload. Alternatively you could use a thread waiting on input on the thread and manipulate the dequeue.
EDIT This is your code made to work with python3, select.select and a timeout. Triggering read_udp works with netcat with echo foo | nc -4 -u localhost 5005 but then triggers an exception because you assume the existence of elements in the dequeue - which is an application logic problem that is independent of the question how to interleave listening and working.
import socket
import select
from collections import deque
host = "localhost"
port = 5005
backlog = 5
BUFSIZE = 4096
q = deque()
def read_tcp(s):
conn, addr = s.accept()
print('Connected with', *addr)
while 1:
data = conn.recv(BUFFER_SIZE)
if not data: break
print("received data:", data)
conn.send(data) # echo
conn.close()
if (data == 'finish'):
processP(q)
else:
q.append(data)
def read_udp(s):
data,addr = s.recvfrom(1024)
print("received message:", data)
del q[-1]
def processP(q):
text = q.popleft()
textReverse = text[::-1]
print(textReverse)
def run():
# create tcp socket
tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
tcp.bind((host,port))
except socket.error as err:
print('Bind failed', err)
return
tcp.listen(1)
# create udp socket
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
udp.bind((host,port))
print('***Socket now listening at***:', host, port)
input = [tcp,udp]
try:
while True:
print("select.select")
inputready,outputready,exceptready = select.select(input,[],[], 0.1)
for s in inputready:
if s == tcp:
read_tcp(s)
elif s == udp:
read_udp(s)
else:
print("unknown socket:", s)
# Hit Break / Ctrl-C to exit
except KeyboardInterrupt:
print('\nClosing')
raise
tcp.close()
udp.close()
if __name__ == '__main__':
run()
Is it possible to detect why a socket closed in Python, i.e. whether the other side sent a FIN or an RST?
The only way I know to detect if the other side has senta FIN or RST, is to read from the socket, and if you get the empty (byte) string, then we have received either a FIN or an RST. But how to know which one?
import asyncio
import socket
async def async_main(loop):
server_sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM,
proto=socket.IPPROTO_TCP)
server_sock.setblocking(False)
server_sock.bind(('', 8080))
server_sock.listen(socket.IPPROTO_TCP)
loop = asyncio.get_event_loop()
sock, adddress = await loop.sock_accept(server_sock)
while True:
data = await loop.sock_recv(sock, 1024)
if data == b'':
# Socket closed, but how?
break
print(data)
loop = asyncio.get_event_loop()
loop.run_until_complete(async_main(loop))
Based on James K Polk's comment, which I believe to be correct, you would distinguish FIN from RST by catching the appropriate exception:
while True:
is_rst = False
try:
data = await loop.sock_recv(sock, 1024)
except IOError as e:
if e.errno == errno.ECONNRESET:
data = b''
is_rst = True
else:
raise
if data == b'':
# Connection closed - use is_rst to distinguish
# between RST and FIN
break
print(data)
Hi i'm trying to send multiple messages to the tcp server but in my client i got an error that data is referenced before assignment. If i send one message there will be no error but if i try to send more than one it returns the error.
tcp server:
class Connect(object):
def __init__(self):
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print('socket cannot be created')
server_address = ('169.254.34.240', 10000)
#print('starting up: ' + server_address)
self.sock.bind(server_address)
self.sock.listen(1)
def listen(self):
while True:
connection, client_address = self.sock.accept()
print('client connected')
try:
data = connection.recv(16)
print(data)
if data == "STATUS":
connection.sendall("vision=ready")
elif data == "MEASURE":
connection.sendall("vision=computing")
elif data == "GET_RESULT":
connection.sendall("x=1.5,y=0.25,z=0.14,a=0.15")
else:
connection.sendall("wrong command")
finally:
connection.close()
def main():
connect = Connect()
connect.listen()
if __name__=='__main__':
main()
my tcp client which is sending messages:
class Connect(object):
def __init__(self):
# Create a TCP/IP socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port on the server given by the caller
print('connecting to host')
self.sock.connect(('169.254.34.240',10000))
def send(self, command):
try:
message = command
print('sending: ' + message)
self.sock.sendall(message)
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = self.sock.recv(16)
amount_received += len(data)
print('received: ' + data)
finally:
self.sock.close()
return data
def main():
connect = Connect()
print connect.send("STATUS")
print connect.send("MEASURE")
if __name__=='__main__':
main()
so anyone an idea, i suppose i don't end correctly or something, i thought it had something to do about my while in the client?
The problem is that you are calling self.sock.close() after each request without creating a new socket. You will need to create a new socket after each time you close it.
You can solve this by creating a connection per request as follows:
class Connect(object):
def connect(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('connecting to host')
sock.connect(('127.0.0.1',10000))
return sock
def send(self, command):
sock = self.connect()
recv_data = ""
data = True
print('sending: ' + command)
sock.sendall(command)
while data:
data = sock.recv(1024)
recv_data += data
print('received: ' + data)
sock.close()
return recv_data
def main():
connect = Connect()
print connect.send("STATUS")
print connect.send("MEASURE")
Providing full stack trace would help, pointing to exact line, where is the problem present. Learn reading these stack traces, they look boring, but provide valuable information like source file and line where it comes from.
Reading your code I suspect, that it fails at finally block, where you return data.
data will not have assigned value in case, the while amount_received < amount_expected would not allow even the first round in the loop or if withing that loop would happen an exception on the line self.sock.recv(16).
Btw.: you are assuming, that length of response will be the same as length of request, but your server does not provide responses with such length.
I have a program hande some devices in network. the program create a process for each device and each process run socket.recv function in a loop to receive messages from connected device.
when I turn device off and then turn it on, the connection between program and device would be lost but the recv function would not return any things or raise any exception and the process stay blocked.
How can handle this problem
this is my code :
if __name__ == '__main__':
ip = sys.argv[1]
port = sys.argv[2]
pingInterval = float(sys.argv[3])
deviceId = sys.argv[4]
print("A card reader started for ", ip)
Thread(target=setThePingerThread, args=(pingInterval,)).start()
while True:
clientsock = socket (AF_INET, SOCK_STREAM)
connectionSuccessful = False
while not connectionSuccessful:
try:
clientsock.connect((ip, int(port)))
connectionSuccessful = True
print('socket connected to ', ip, port)
except Exception as e:
print('Can''t connect to the device! device ip =>', ip)
time.sleep(5000)
pass
try:
mybuffer = bytes()
data = bytes()
cardNumbers = []
while True:
mybuffer = clientsock.recv(100)
data = data + mybuffer
cardNumbers, data = retreiveCardNumbers(data)
#print('debug: cardNumbers=', cardNumbers, ' data=',data, ' data-decoded=',data.decode("ascii"))
for cardNumber in cardNumbers:
print('A card hit:', cardNumber)
sendToQueue(cardNumber, deviceId)
except Exception as e:
print('Error processing card number! device ip =>', ip, e)
Referring to
the process stay blocked
I do not know the code of setThePingerThread but I guess the error is solved with this:
thread = Thread(target=setThePingerThread, args=(pingInterval,))
thread.deamon = True
thread.start()
thread.deamon is usually False which makes the program wait for the end of that thread.