I've been playing around with Python's SocketServer:
#!/usr/bin/python
import SocketServer
class EchoHandler(SocketServer.BaseRequestHandler):
def handle(self):
data=self.request.recv(1024)
self.request.send(data)
HOST, PORT = "localhost", 9999
server = SocketServer.TCPServer((HOST, PORT), TCPEchoServer)
server.serve_forever()
From reading the source, I know that RequestHandler.__init__() receives request as a parameter and keeps a reference to it in self.request.
Where can I find the specifications for the request object?
In the documentation of RequestHandler.handle.
Related
I am learning the socketserver module and I am following the example but I modified the handle function a bit
class CustomServer(socketserver.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print(f">{self.client_address[0]}: {self.data}")
def send(self, targets=[]):
if not targets:
return
if __name__ == "__main__":
HOST, PORT = "localhost", 6666
with socketserver.TCPServer((HOST, PORT), CustomServer) as server:
server.serve_forever()
Now when I try to use netcat and send sth to the server I don't see anything being outputted to the console
nc -v 10.0.0.112 6666
How do you properly edit the handle method so that it will print the address of the client each time
It is really important to understand the OOP concept and how to use it
Looking at the source code for socketserver I realized that I can create a class that inherits the BaseRequestHandler than I modified the handler method and passed my class to the TCPServer
class CustomHandler(BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print(f">{self.client_address[0]}: {self.data}")
if __name__ == "__main__":
HOST, PORT = "0.0.0.0", 6666
server = TCPServer(((HOST, PORT)), CustomHandler)
server.serve_forever()
I just started programming Python.
My goal is to built a digital Picture Frame with three Screens. Therefore I use 3 Raspis, one for each Monitor.
For the communication of these Raspis I need to program a server and a Client.
For a first test I want to built a server which is able to send and receive messages to/from multiple clients.
So I started with a few socket tutorials an created the following program.
Server Class (TcpServer.py)
class TcpServer:
clients = []
serverIsRunning = 0
port = 0
def __init__(self, port):
self.port = port
self.serverIsRunning = 0
self.serverRunning = 0
def startServer (self):
print("start Server...")
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind(("", self.port))
self.server.listen(1)
self.serverRunning = 1
while self.serverRunning:
read, write, oob = select.select([self.server] + self.clients, [], [])
for sock in read:
if sock is self.server:
client, addr = self.server.accept()
self.clients.append(client)
print ("+++ Client ", addr[0], " verbunden")
else:
nachricht = sock.recv(1024)
ip = sock.getpeername()[0]
if nachricht:
print (ip, nachricht)
else:
print ("+++ Verbindung zu ", ip , " beendet")
sock.close()
self.clients.remove(sock)
for c in self.clients:
c.close()
self.clients.remove(c)
self.server.close()
def send(self, message):
message = message.encode()
self.server.send(message)
Client class (TcpClient.py)
import socket
class TcpClient:
def __init__(self, ip, port):
self.serverAdress = (ip, port)
self.connected = 0
self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.connection.connect(self.serverAdress)
print ("connectet to ", self.serverAdress)
def send(self, message):
message = message.encode()
self.connection.send(message)
Server:
import threading
import TcpServer
tcpServer = TcpServer.TcpServer(50000)
threadTcpServer = threading.Thread(target = tcpServer.startServer)
threadTcpServer.start()
while True:
tcpServer.send(input("Nachricht eingeben: "))
Client:
import threading
import TcpClient
tcpClient = TcpClient.TcpClient("192.168.178.49", 50000)
while True:
tcpClient.send(input("Nachricht eingeben: "))
I can send messages from the Client to the server, but when I want to send a Message from the server to the client it generates the following error:
BrokenPipeError: [Errno 32] Broken pipe
I assume it is because the server thread blocks the socket while waiting of a incoming message. But I have no idea how to handle this.
How can I program a server who can send and receive messages? Can you recommend a tutorial? I didn't found a tutorial who describes a solution for my problem.
Edit:
Now I tried to solve the problem with the socketserver library, but I still can't solve may problem.
here is my new code for the server:
import socketserver
import threading
import time
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The RequestHandler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
threadTcpServer = threading.Thread(target = server.serve_forever)
threadTcpServer.start()
print("server started")
time.sleep(10)
print("sending Data")
server.request.sendall("Server is sending...")
it generates the error:
AttributeError: 'TCPServer' object has no attribute 'request'
My goal is to write a server with a thread who receives Data and still be able to send data from a other thread.
Is this even possible with only one socket?
You should use the provided socketserver rather than writing all the handling of sockets and select etc.
There are multiple problems with your code -
1 - The server is trying to write to the listening socket!! The client communication socket is the one that you get from the accept() call and that is the one you have to use for reading and writing.
2 - The client is sending the data and completing immediately, but it should really wait for getting a response. Otherwise, the python / OS will close the client socket as soon as the program completes and it will mostly be before the server gets a chance to respond.
I believe with the Handler code you are able to receive the data sent by the client on the server and are also able to send some data back from the Handler to the client? You must have understood that the server cannot send any data back unless there is a client connected to it?
Now, to send data to the client (or clients) from "another" thread, you will need a way to make the handler objects or the client sockets (available inside the Handler object as self.request) available to the "another" thread.
One way is to override the def __init__(self, request, client_address, server): method and save this object's reference in a global list. Remember to do the below as the last line of the overridden init -
# BaseRequestHandler __init__ must be the last statement as all request processing happens in this method
socketserver.BaseRequestHandler.__init__(self, request, client_address, server)
Once you have all the client handlers in the global list, you can easily write to all the clients from any thread as per your needs. You must read about synchronization (Locks) and understand that using same object / socket from multiple threads can create some logical / data issues with your application.
Another thing that you have to worry about and code for is cleaning up this global list whenever a client closes the connection.
Given that I have implemented a UDP Client in Twisted with the DatagramProtocol, and using it to communicate to a UDP Server, which at one point goes offline (due to a restart - so it does not change it's IP address), stopProtocol in my protocol is called, however the transport itself is set to None by Twisted.
How can I solve a simple reconnect in Twisted or re-initiate the transport?
I cannot connect again with udp according to the docs.
Given that in UDP the sender should be able to send packets even after the server is dead, and given that the protocol has it's own connection handling in the packets, I could reconnect the logical part entirely over the Packet layer, if the transport would not disappear.
I suppose running listenUDP again with a new protocol while the core is running won't work.
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
class UDPClientProtocol(DatagramProtocol):
def __init__(self, host, port):
self.host = host
self.port = port
def startProtocol(self):
# Called when transport is connected
self.transport.connect(self.host, self.port)
self.transport.write('initiate protocol') # pseudo code.
def stopProtocol(self):
print "I have lost connection and self.transport is gone!"
# wait some time and try to reconnect somehow?
t = reactor.listenUDP(0, UDPClientProtocol('127.0.0.1', 12345))
reactor.run()
I used following technique that I saw at Twisted DNS source file. It survives server disconnection and even network failures.
from twisted.internet import reactor, protocol, task
import time
class EchoClientDatagramProtocol(protocol.DatagramProtocol):
def __init__(self, host, port, reactor):
self.host = host
self.port = port
self._reactor = reactor
def startProtocol(self):
self.transport.connect(self.host, self.port)
def stopProtocol(self):
#on disconnect
self._reactor.listenUDP(0, self)
def sendDatagram(self):
datagram = ntp_packet
try:
self.transport.write(datagram, (self.host, self.port))
print "{:0.6f}".format(time.time())
except:
pass
def datagramReceived(self, datagram, host):
pass
#print 'Datagram received: ', repr(datagram)
#self.sendDatagram()
def main():
protocol = EchoClientDatagramProtocol('127.0.0.1', 8000, reactor)
t = reactor.listenUDP(0, protocol)
l = task.LoopingCall(protocol.sendDatagram)
l.start(1.0) # call every second
reactor.run()
if __name__ == '__main__':
main()
Interesting. That sounds like something that shouldn't happen. Is this due to a network interface restart or something? What conditions reproduce this?
The simple answer to your question is probably "call listenUDP again, with 'self'", but I am curious what could cause this error to happen in the first place.
I've created a class for a server with the declaration:
class myServer(socketserver.BaseRequestHandler):
def handle(self):
pass
And started it with:
someServer = socketserver.UDPServer((HOST, PORT), myServer)
someServer.serve_forever()
My question is: how can I get the server to shutdown itself? I've seen it has a base class (of a base class) called BaseServer with a shutdown method. It can be called on someServer with someServer.shutdown() but this is from the outside of the server itself.
By using threads. Serving by one thread and going via another after your timeout.
Consider this working example. Modify it for your UDPServer
import threading
import time
import SimpleHTTPServer
import SocketServer
PORT = 8000
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
def worker():
# minimal web server. serves files relative to the
print "serving at port", PORT
httpd.serve_forever()
def my_service():
time.sleep(3)
print "I am going down"
httpd.shutdown()
h = threading.Thread(name='httpd', target=worker)
t = threading.Thread(name='timer', target=my_service)
h.start()
t.start()
You could use twisted. Its about the best networking lib for python, here is an example of a UDP server here is (taken from the twisted documentation) the simplest UDP server ever written;
#!/usr/bin/env python
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
# See LICENSE for details.
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
# Here's a UDP version of the simplest possible protocol
class EchoUDP(DatagramProtocol):
def datagramReceived(self, datagram, address):
self.transport.write(datagram, address)
def main():
reactor.listenUDP(8000, EchoUDP())
reactor.run()
if __name__ == '__main__':
main()
You can then close this down by calling self.transport.loseConnection() When you are ready or a specific event happens.
The server instance is available as self.server in the handler class. So you can call self.server.shutdown() in the handle method.
I am trying to create a tcplistener in python (using pexpect if necessary) to listen for tcp connection from Ubuntu in virtualbox on a windows xp host. I would really appreciate it, if one of you could point me in the right direction. Thank you.
P.S: I have limited experience in the area, any help would be welcome.
Python already has a simple socket server provided in the standard library, which is aptly named SocketServer. If all you want is a basic listener, check out this example straight from the documentation:
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
"""
The RequestHandler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print "%s wrote:" % self.client_address[0]
print self.data
# just send back the same data, but upper-cased
self.request.send(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()