Twisted : How to know which client has closed the connection - python

This is a follow-up to my previous question.
I am building a simple client server program using ´twisted´ package in Python.
I would like to keep a record of which client has joined and closed the connection.
Suppose, if Client B closes the connection, I would like to print at the server "Client B has closed the connection"
Here is the code I am using :
factory = protocol.ServerFactory()
factory.protocol = Echo
PortNo = 8000
reactor.listenTCP(PortNo,factory)
reactor.run()
def connectionLost(self, reason):
print "Connection lost"
Any idea how to do it ?
Thanks

The connection which was lost is the one associated with the protocol instance referenced by the self argument to connectionLost.
With a normal factory (like ServerFactory, as you are using) there is a one to one relationship between connections and protocol instances.

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.

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 detect client "socket.close()" in tornado socket server

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'

Closing Perspective Broker connection in Twisted

I have program which has servers interacting with each other using Twisted's remote procedure calls, and I run in problems with closing connections when they are not needed anymore. Connections should be able to close itself in both sides.
Case 1: How do I close connection in connecting part?
factory = pb.PBClientFactory()
reactor.connectTCP(ip, port, factory)
deferred = factory.login(credentials.UsernamePassword(username, password), client=self)
deferred.addCallbacks(self.connectedToServer, self.errorConnectingToServer)
def connectedToServer(self, server):
self.server = server
# Closing connection comes here
Case 2: How do I close connection in server part?
class MyPerspective(pb.Avatar):
def connected(self, server):
self.client = server
# Closing connection comes here
At the moment I use raising pb.Error() to close connection, but I don't think that's the proper way to do it.
Another option is reference.broker.transport.loseConnection().
RemoteReference instances which are created over a PB connection are given a broker attribute. The broker attribute refers to the protocol instance that created them. As usual for a protocol, the broker has a transport attribute, and the transport has a loseConnection method.

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