Python socket timeout and flush - python

I'm trying to translate this from Ruby to Python.
Ruby code:
def read_byte
begin
Timeout.timeout(0.5) do
b = socket.read 1
end
rescue Timeout::Error => e
socket.write("\n")
socket.flush
retry
end
end
def socket
#socket ||= TCPSocket.open #host, #port
rescue SocketError
# TODO: raise a specific error
raise "Unable to open connection to #{#host} with given parameters"
end
My mean problem here is with
socket.flush
I can't find a way to do flush. what other way can I do this?
I wrote this.
Python code:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((self.host, self.port))
s.settimeout(0.5)
while True:
try:
print s.recv(1)
except socket.timeout:
s.sendall("\n")

I doubt that flushing the socket will make a difference, but here is a way to "flush" the socket by first creating a file-like object.
def flush_socket(s):
f = s.makefile()
f.flush()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((self.host, self.port))
s.settimeout(0.5)
while True:
try:
print s.recv(1)
except socket.timeout:
s.sendall("\n")
flush_socket(s)

The stream is kinda hanging with my code.
Of course it is, since it is an endless loop unless some exception other than socket.timeout occurs.
maybe it's another part of the ruby code
It must be ... Inspect the Ruby loop where read_byte is called and compare that to your Python while True.

Related

Python breaks string after first character

My Python socket program is breaking after the first character when receiving a single line string. The socket program runs in Raspberry Pi and the client and Java. Here is my code for socket
HOST = ''
PORT = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')
try:
s.bind((HOST, PORT))
except socket.error as socketError:
print('socket binding failed, ', socketError)
print('Exiting...')
sys.exit(0)
print('Socket binding complete')
s.listen(1)
print('Socket listening for connection...')
conn, addr = s.accept()
print('connected to ',addr[0])
try:
while True:
data = conn.recv(1024).decode('utf-8')
print('value received',data)
except Exception as loopException:
print("Exception occurred in loop, exiting...",loopException)
finally:
s.close()
This is how I send data from java
socket = new Socket(dstAddress, Integer.parseInt(dstPort));
os = new DataOutputStream(socket.getOutputStream());
os.writeBytes("Connection-Ready to receive commands");
This is what I get in terminal
value received C
value received onnected-Ready to receive commands
Does anybody know why it is behaving like this?
You need to read in a loop until you get all of the input. You need a way to know when you have all of the input.
If the client is writing and then closing the socket, then you can read until you get to EOF. If the client isn't closing the socket, then you need some way to know how much to read. The simplest thing is to have the client send a length word before sending the characters. You read the length and then read that many characters.
To put in a delay is a hack that may work for now, but isn't reliable. If you have some slowdown in your network, your code can break.
It looks from your output like you are closing the stream on the client side even though you don't show that. So then you just need to buffer up all your data until you reach the end of the stream. This should work:
buffer = b''
try:
while True:
data = conn.recv(1024)
if not data:
break
buffer += data
except Exception as loopException:
print("Exception occurred in loop, exiting...", loopException)
finally:
s.close()
print('value received', buffer.decode('utf-8'))
I think this will work. I don't have a connection to try it against, but my IDE likes it. I'm not that familiar with Python 3 byte streams. If this doesn't quite work, you should get the idea here anyway.
Sockets are a byte stream and there is no guarantee that a recv will have all the bytes of a complete message. It is your responsibility to buffer the received data until you have a complete message.
This also means you need to provide a way to know you have a complete message. Send the length of the message before the message, or read until a newline.

Find socket responsible for timeout?

sock1.settimeout(2)
conn.settimeout(1) #conn comes from sock1
except socket.timeout, e:
print <responsible socket>
Is there a way to distinguish the socket responsible for the timeout?
Perhaps I'm doing something wrong if I have two sockets that are timing out.
As far as I can tell, there's nothing in the socket.timeout exception object that identifies the socket. So you need to keep track of which socket you're reading from, that will be the one that timed out:
try:
cursock = sock1
data = sock1.recv(bufsize)
cursock = conn
data1 = conn.recv(bufsize)
except socket.timeout, e:
print cursock
Or you could wrap try/except around each recv call. You could put this into a helper function:
def try_recv(sock, bufsize, flags=0):
try:
return sock.recv(bufsize, flag)
except socket.timeout, e:
print sock

Getting timeout on UDP socket when timeout is set to 'None' - Python

I am writing a connector using UDP in Python 3.3
When I am sending data to the UDP port, everything works fine. The problem is that when I am not sending any data, I get an error generated by the receiving port once per minute that says "timed out". While debugging, I used the socket.gettimeout() function and it returned 'None'.
Why am I getting this timeout error? Any help would be greatly appreciated!
import socket
from EventArgs import EventArgs
import logging
class UDPServer(object):
"""description of class"""
def __init__(self, onMessageReceivedEvent = '\x00'):
self.__onMessageReceivedEvent = onMessageReceivedEvent
self.__s = '\x00'
self.__r = '\x00'
def openReceivePort(self,port):
try:
self.__r = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.__r.bind(("",port))
print ("opening port: ", port)
except socket.error as e:
logging.getLogger("ConnectorLogger").critical(e)
def openBroadcastPort(self):
try:
self.__s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.__s.bind(("",2101))
print ("opening port: ", 2101)
except socket.error as e:
logging.getLogger("ConnectorLogger").critical(e)
def closePorts():
if self.__r != '\x00':
self.__r.close()
if self.__s != '\x00':
self.__s.close()
def getUDPData(self):
try:
data, addr = self.__r.recvfrom(1024)
if self.__onMessageReceivedEvent != '\x00':
eventArgs = EventArgs()
eventArgs.Addr = addr
eventArgs.Data = data
self.__onMessageReceivedEvent.fire(self, eventArgs)
except socket.error as e:
logging.getLogger("ConnectorLogger").critical(e)
def send(self,ipAddress,port,message):
try:
self.__s.sendto(message.encode(),(ipAddress,23456))
except socket.error as e:
logging.getLogger("ConnectorLogger").critical(e)
I figured out the answer to my own problem. I was using the default configuration for socket.setblocking which is 0 (non-blocking). The documentation says that using this configuration is the equivalent of using a settimeout value of 0. If I use a blocking socket, it is the equivalent of using a settimeout value of 'None'. Once I changed to a blocking socket I no longer saw this error.
socket.setblocking(flag)-Set blocking or non-blocking mode of the socket: if flag is 0, the socket is set to non- blocking, else to blocking mode. Initially all sockets are in blocking mode. In non-blocking mode, if a recv() call doesn’t find any data, or if a send() call can’t immediately dispose of the data, a error exception is raised; in blocking mode, the calls block until they can proceed. s.setblocking(0) is equivalent to s.settimeout(0.0); s.setblocking(1) is equivalent to s.settimeout(None)*

Python: How to set a timeout on receiving data in SocketServer.TCPServer

I've read quite a few things and this still escapes me. I know how to do it when using raw sockets. The following works just fine, times out after 1 second if no data is received:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((HOST, PORT))
sock.listen(1)
while 1:
conn, addr = sock.accept()
data = ''
conn.settimeout(1)
try:
while 1:
chunk = conn.recv(1024)
data += chunk
if not chunk:
break
print 'Read: %s' % data
conn.send(data.upper())
except (socket.timeout, socket.error, Exception) as e:
print(str(e))
finally:
conn.close()
print 'Done'
But when trying something similar when using SocketServer.TCPServer with SocketServer.BaseRequestHandler (not with SocketServer.StreamRequestHandler where I know how to set a timeout) it seems not as trivial. I didn't find a way to set a timeout for receiving the data. Consider this snippet (not complete code):
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = ''
while 1:
chunk = self.request.recv(1024)
data += chunk
if not chunk:
break
if __name__ == "__main__":
HOST, PORT = "0.0.0.0", 9987
SocketServer.TCPServer.allow_reuse_address = True
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
Suppose the client sends only 10 bytes. The while loop runs once, chunk is not empty, so then executes self.request.recv() again but the client has no more data to send and recv() blocks indefinitely ...
I know I can implement a small protocol, check for terminating strings/chars, check message length etc., but I really want to implement a timeout as well for unforeseen circumstances (client "disappears" for example).
I'd like to set and also update a timeout, i.e. reset the timeout after every chunk, needed for slow clients (though that's a secondary issue at the moment).
Thanks in advance
You can do the same thing with SocketServer.BaseRequestHandler.request.settimeout() as you did with the raw socket.
eg:
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.request.settimeout(1)
...
In this case self.request.recv() will terminate if it takes longer than 1 second to complete.
class MyTCPHandler(SocketServer.BaseRequestHandler):
timeout=5
...
... will raise an exception (which serve_forever() will catch) and shut down the connection if 5 seconds pass without receiving data after calling recv(). Be careful, though; it'll also shut down your connection if you're sending data for more than 5 seconds as well.
This may be Python 3 specific, mind, but it works for me.

What does Python's socket.recv() return for non-blocking sockets if no data is received until a timeout occurs?

Basically, I've read in several places that socket.recv() will return whatever it can read, or an empty string signalling that the other side has shut down (the official docs don't even mention what it returns when the connection is shut down... great!). This is all fine and dandy for blocking sockets, since we know that recv() only returns when there actually is something to receive, so when it returns an empty string, it MUST mean the other side has closed the connection, right?
Okay, fine, but what happens when my socket is non-blocking?? I have searched a bit (maybe not enough, who knows?) and can't figure out how to tell when the other side has closed the connection using a non-blocking socket. There seems to be no method or attribute that tells us this, and comparing the return value of recv() to the empty string seems absolutely useless... is it just me having this problem?
As a simple example, let's say my socket's timeout is set to 1.2342342 (whatever non-negative number you like here) seconds and I call socket.recv(1024), but the other side doesn't send anything during that 1.2342342 second period. The recv() call will return an empty string and I have no clue as to whether the connection is still standing or not...
In the case of a non blocking socket that has no data available, recv will throw the socket.error exception and the value of the exception will have the errno of either EAGAIN or EWOULDBLOCK. Example:
import sys
import socket
import fcntl, os
import errno
from time import sleep
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
fcntl.fcntl(s, fcntl.F_SETFL, os.O_NONBLOCK)
while True:
try:
msg = s.recv(4096)
except socket.error, e:
err = e.args[0]
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
sleep(1)
print 'No data available'
continue
else:
# a "real" error occurred
print e
sys.exit(1)
else:
# got a message, do something :)
The situation is a little different in the case where you've enabled non-blocking behavior via a time out with socket.settimeout(n) or socket.setblocking(False). In this case a socket.error is stil raised, but in the case of a time out, the accompanying value of the exception is always a string set to 'timed out'. So, to handle this case you can do:
import sys
import socket
from time import sleep
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
s.settimeout(2)
while True:
try:
msg = s.recv(4096)
except socket.timeout, e:
err = e.args[0]
# this next if/else is a bit redundant, but illustrates how the
# timeout exception is setup
if err == 'timed out':
sleep(1)
print 'recv timed out, retry later'
continue
else:
print e
sys.exit(1)
except socket.error, e:
# Something else happened, handle error, exit, etc.
print e
sys.exit(1)
else:
if len(msg) == 0:
print 'orderly shutdown on server end'
sys.exit(0)
else:
# got a message do something :)
As indicated in the comments, this is also a more portable solution since it doesn't depend on OS specific functionality to put the socket into non-blockng mode.
See recv(2) and python socket for more details.
It is simple: if recv() returns 0 bytes; you will not receive any more data on this connection. Ever. You still might be able to send.
It means that your non-blocking socket have to raise an exception (it might be system-dependent) if no data is available but the connection is still alive (the other end may send).
When you use recv in connection with select if the socket is ready to be read from but there is no data to read that means the client has closed the connection.
Here is some code that handles this, also note the exception that is thrown when recv is called a second time in the while loop. If there is nothing left to read this exception will be thrown it doesn't mean the client has closed the connection :
def listenToSockets(self):
while True:
changed_sockets = self.currentSockets
ready_to_read, ready_to_write, in_error = select.select(changed_sockets, [], [], 0.1)
for s in ready_to_read:
if s == self.serverSocket:
self.acceptNewConnection(s)
else:
self.readDataFromSocket(s)
And the function that receives the data :
def readDataFromSocket(self, socket):
data = ''
buffer = ''
try:
while True:
data = socket.recv(4096)
if not data:
break
buffer += data
except error, (errorCode,message):
# error 10035 is no data available, it is non-fatal
if errorCode != 10035:
print 'socket.error - ('+str(errorCode)+') ' + message
if data:
print 'received '+ buffer
else:
print 'disconnected'
Just to complete the existing answers, I'd suggest using select instead of nonblocking sockets. The point is that nonblocking sockets complicate stuff (except perhaps sending), so I'd say there is no reason to use them at all. If you regularly have the problem that your app is blocked waiting for IO, I would also consider doing the IO in a separate thread in the background.

Categories

Resources