How detect client "socket.close()" in tornado socket server - python

I am implementing a tornado socket server based on this code:
https://gist.github.com/robcowie/974695
Client is Python simple socket client. When I call socket.close() in client, nothing happens in server. I put full print traces in the server and closing is not detected nowhere.
I know I can detect the closure for example sending a string "CNNDEND" which means closing. But I wonder if there is any way to detect on server socket.close() from client.

in Connection __init__:
self.stream.set_close_callback(self.__onClose)
in Connection class:
def __onClose(self):
print 'close detected'

Related

Python TCP server throws OSError: [WinError 10057] when calling socket.shutdown(1)

I have quite a complex TCP/IP server that connects to several clients. I was running into an issue where my clients were not being updated that the socket was closing. I believe I need to call both socket.shutdown() and socket.close() to be able send a server closing advisory to all of the clients. However, I get an OS error whenever I call socket.shutdown().
OSError: [WinError 10057] A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Does anybody know why this is happening? Or some other way of closing the socket while still sending the advisory to all connected clients? I could always write a custom command that resets all of the clients before calling socket.close(), but something seems wrong with my server. Below is minimum reproducible example.
import socket
import selectors
class server_test:
host = ''
port = 12345
sel = selectors.DefaultSelector()
def __init__(self):
self.start_server()
self.stop_server()
#Server Functions
def start_server(self):
self.lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.lsock.bind((self.host, self.port))
self.lsock.listen()
print("Server starting, listening on ",. (self.host, self.port))
self.lsock.setblocking(False)
self.sel.register(self.lsock, selectors.EVENT_READ, data=None)
def stop_server(self):
print("Shutting server down")
self.lsock.shutdown(1)
self.lsock.close()
I believe I need to call both socket.shutdown() and socket.close() to be able send a server closing advisory to all of the clients.
No. A shutdown(1) on a connected socket will send a FIN to the peer to signal that the local system will not send more data, but it might actually accept more data. A shutdown(0) will stop receiving data locally and reject any data send by the peer. A close() essentially combines a shutdown(1) and a shutdown(0).
self.lsock.listen()
...
self.lsock.shutdown(1)
You are trying to tell the peer of self.lsock that you will no longer send data. But self.lsock is the local listener socket which is not itself connected and thus has no peer. Since you are thus try to do an operation which requires a connected socket on a socket which is not connected (only listening) it will result in the error "... socket is not connected ...".
If you want to shutdown the connection to all clients you actually have to call shutdown or close on all connected sockets (i.e. result from self.lsock.accept() and not on the listener socket.

Python Sockets: How to detect when client has disconnected ungracefully? (e.g. WiFi disconnect)

I'm writing a pair of client/server scripts where it is important to maintain connection as well as detect quickly when the client disconnects. The server normally only sends data, so to test if the client has disconnected normally, I set the socket to timeout mode and check what it returns:
try: # check if client disconnect
c.settimeout(1)
if not (c.recv(1024)):
print("## Socket disconnected! ##")
c.settimeout(None)
closeConnection(c)
return
except Exception as e:
print(e)
c.settimeout(None)
This works instantly if I close the client. However, if I disconnect the WiFi on the client machine, the recv on the server doesn't return anything. It just times out like it would if the connection was up but there wasn't anything being sent.
I've tried using send() to send empty messages to the client as a way to poll. When I do this, the operation succeeds and returns 0 regardless of if the client has disconnected.

How to handle socket.io broken connection in Flask?

I have a very simple Python (Flask socket.io) application which works as a server and another app written in AngularJS which is a client.
In order to handle connected and disconnected client I use respectlivy:
#socketio.on('connect')
def on_connect():
print("Client connected")
#socketio.on('disconnect')
def on_disconnect():
print("Client disconnected")
When Client connects to my app I get information about it, in case if client disconnect (for example because of problems with a network) I don't get any information.
What is the proper way to handle the situation in which client disconnects unexpectedly?
There are two types of connections: using long-pooling or WebSocket.
When you use WebSocket clients knows instantly that server was disconnected.
In the case of long-polling, there is need to set ping_interval and pint_timeout parameters (I also find information about heartbeat_interval and heartbeat_timeout but I don't know how they are related to ping_*).
From the server perspective: it doesn't know that client was disconnected and the only way to get that information is to set ping_interval and ping_timeout.

Detect when Websocket is disconnected, with Python Bottle / gevent-websocket

I'm using the gevent-websocket module with Bottle Python framework.
When a client closes the browser, this code
$(window).on('beforeunload', function() { ws.close(); });
helps to close the websocket connection properly.
But if the client's network connection is interrupted, no "close" information can be sent to the server.
Then, often, even 1 minute later, the server still believes the client is connected, and the websocket is still open on the server.
Question: How to detect properly that a websocket is closed because the client is disconnected from network?
Is there a websocket KeepAlive feature available in Python/Bottle/gevent-websocket?
One answer from Web Socket: cannot detect client connection on internet disconnect suggests to use a heartbeat/ping packet every x seconds to tell the server "I'm still alive". The other answer suggests using a setKeepAlive(true). feature. Would this feature be available in gevent-websocket?
Example server code, taken from here:
from bottle import get, template, run
from bottle.ext.websocket import GeventWebSocketServer
from bottle.ext.websocket import websocket
users = set()
#get('/')
def index():
return template('index')
#get('/websocket', apply=[websocket])
def chat(ws):
users.add(ws)
while True:
msg = ws.receive()
if msg is not None:
for u in users:
u.send(msg)
else:
break
users.remove(ws)
run(host='127.0.0.1', port=8080, server=GeventWebSocketServer)
First you need to add a timeout to the receive() method.
with gevent.Timeout(1.0, False):
msg = ws.receive()
Then the loop will not block, if you send even an empty packet and the client doesn't respond, WebsocketError will be thrown and you can close the socket.

How to connect a Python socket on client-side to Node.js/socket.io?

I want to connect Blender (v2.55) to a webpage through sockets.
For the web part, I can use Node.js & socket.io. I've already used a little node.js/socket.io, it's not a problem I think.
Now for Blender, it runs on Python 3.1, so I've already sockets and I can add libraries if needed. I'm new to Python sockets, can I connect a client to node.js/socket.io directly ?
I tried with the basic code from the Python doc:
import socket
import sys
HOST, PORT = "127.0.0.1", 8080
data = "Hello from Blender"
# Create a socket (SOCK_STREAM means a TCP socket)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to server and send data
sock.connect((HOST, PORT))
sock.send(bytes(data + "\n","utf8"))
# Receive data from the server and shut down
received = sock.recv(1024)
sock.close()
print("Sent: %s" % data)
print("Received: %s" % received)
It results by:
Sent: Hello from Blender
Received: b''
It seems that Blender is connected, but doesn't receive data. Also Node shows no new client connected…
Do I need something else ? If somebody can help me out…
You are missing a protocol/handshake. What you have there is a bare TCP socket connection. node.js/socket.io lives on top of a TCP socket. Basically when you open a connection to a socket.io server, it's expecting you to use some protocol for communication (websockets, longpolling, htmlfile, whatever). The initial handshake defines what that protocol will be. Websockets is one of the supported protocols. This blog post should help you. It doesn't look all that hard to get websockets implemented.
you can try the form of loop to receive valid data.
import socket
host="127.0.0.1"
port=8088
web=socket.socket()
web.bind((host,port))
web.listen(5)
print("recycle")
while True:
conn,addr=web.accept()
data=conn.recv(8)
print(data)
conn.sendall(b'HTTP/1.1 200 OK\r\n\r\nHello world')
conn.close()
and use your browser to visit the host and port for a check
I understand this thread is extremely old. But I faced the same problem recently and couldn't find an answer or any similar questions. So here is my answer.
Answer: Use socket.io for python python-socketio
The reason why built-in sockets or any other websocket library in python won't work is explained in the socket.io website socket.io
Socketio is simply just not a websoket connection. Although they say, it uses websockets for transport internally, the connection is established with HTTP protocol http:// as opposed to the WEBSOCKET protocol ws://. This results in the failure of handshake and the connection fails to be established.

Categories