I am trying to get this simple python3 code to run in docker using sockets, but I receive the following error. Can someone point me in the right direction. I am just trying to get it to work so i can integrate it into my broader project
File "registrar.py", line 29, in <module>
with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
AttributeError: __exit__
Server
import socketserver
import json
list_of_nodes = []
class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The request handler 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):
global list_of_nodes
# 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(json.loads(self.data))
# just send back the same data, but upper-cased
list_of_nodes.append(json.loads(self.data))
self.request.sendall(bytes(str(len(list_of_nodes)-1), 'utf-8'))
print(list_of_nodes)
if __name__ == "__main__":
HOST, PORT = "localhost", 58333
# Create the server, binding to localhost on port 9999
with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
Client
import socket
import sys
import time
import json
HOST, PORT = "localhost", 58333
data = " ".join(sys.argv[1:])
dict_node = {'nVersion': 1,
'nTime': time.time(),
'addrMe': socket.gethostbyname(socket.gethostname())
}
# Create a socket (SOCK_STREAM means a TCP socket)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# Connect to server and send data
sock.connect((HOST, PORT))
json_msg = json.dumps(dict_node)
sock.sendall(bytes(json_msg, "utf-8"))
# Receive data from the server and shut down
received = str(sock.recv(1024), "utf-8")
print("Sent: {}".format(json_msg))
print("Received: {}".format(json.loads(received)))
Related
I'm trying to setup a threaded server where multiple clients can connect at the same time. This is a bit long, please do bear with me. I've already read this helpful realpython article on sockets as well as the socket and socketserver docs.
Python provides facilities to create a server and the socketserver documentation even shows us:
import socket
import threading
import socketserver
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = str(self.request.recv(1024), 'ascii')
cur_thread = threading.current_thread()
response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
self.request.sendall(response)
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
def client(ip, port, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((ip, port))
sock.sendall(bytes(message, 'ascii'))
response = str(sock.recv(1024), 'ascii')
print("Received: {}".format(response))
if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
HOST, PORT = "localhost", 0
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
with server:
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print("Server loop running in thread:", server_thread.name)
client(ip, port, "Hello World 1")
client(ip, port, "Hello World 2")
client(ip, port, "Hello World 3")
server.shutdown()
This works fine on my machine but what I'd like to de-couple the client implementation from the server. So I split the implementations and I have.
server.py:
import socketserver
import threading
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = str(self.request.recv(1024), 'ascii')
cur_thread = threading.current_thread()
response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
self.request.sendall(response)
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
def main():
HOST, PORT = "localhost", 8080 # localhost aka 127.0.0.1
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
with server:
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = False # Do not stop and keep serving
server_thread.start()
print("Server loop running in thread: ", server_thread.name)
if __name__ == '__main__':
main()
and client.py
import socket
class Client:
def __init__(self, ip, port):
self.ip = ip
self.port = port
def start(self, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((self.ip, self.port))
sock.sendall(bytes(message, "ascii"))
response = str(sock.recv(1024), "ascii")
print("Received: {}".format(response))
def main():
client = Client("localhost", 8080)
client.start("Hello World!")
if __name__ == '__main__':
main()
Then I open two different shell occurences and I do:
$ python3 -m server
The server outputs its message and the shell hangs, which is the expected behavior since I turned daemon mode off and it is supposed to serve forever.
Pinging localhost works fine, all packages are received with no loss. On the other hand, using netstat, I can't seem to find the port I'm opening (8080).
and in the other:
$ python3 -m client
Fails with a ConnectionRefusedError which is the typical error when there is nothing to connect to.
My conclusion for now is that the server is closing the port at some point, I suppose when the main thread dies?
I'm not sure how to fix it though? What's wrong with the current implementation.
Thanks for the help.
I'm trying use the python socket module to connect to an ngrok server. If I put the ngrok into my browser it connects properly so the problem is somewhere with my client code. Here is the server code:
#server.py
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
if __name__ == "__main__":
HOST, PORT = "192.168.86.43", 8080
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
And here is the client:
#client.py
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect(("http://urlhere.ngrok.io", 8080))
sock.sendall(bytes("Hello" + "\n", "utf-8"))
Thanks!
In general you should be able to connect to any globally available address or DNS name, ensuring there is no network restrictions on the way. However you have to listen on the address that is locally available for global routing if you are communicating across the Internet.
As for particular code, there are 2 issues:
Socket should be connected to an address or DNS name. The protocol is defined with the socket type. In your case
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect(("localhost", 8080))
sock.sendall(bytes("Hello" + "\n", "utf-8"))
You're binding in the server to some speciffic not related address. To run your code you should bind to either localhost or to "any available" address "0.0.0.0":
import socketserver
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
if __name__ == "__main__":
HOST, PORT = "0.0.0.0", 8080
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
SocketServer Program
This code is in raspberry:
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
"""
The request handler 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)
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()
Socket Client Program
This code is in my laptop:
import socket
import sys
HOST, PORT = "192.168.1.40", 3360
data='Hello'
#data = data.join(sys.argv[1:])
# Create a socket (SOCK_STREAM means a TCP socket)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Connect to server and send data
sock.connect((HOST, PORT))
sock.sendall(data + "\n")
# Receive data from the server and shut down
received = sock.recv(1024)
finally:
sock.close()
print "Sent: {}".format(data)
print "Received: {}".format(received)
Here the data sent should be received to server and sent back to client.
This is the error:
[Errno 10061] No connection could be made because the target machine actively refused it.
Try changing to HOST, PORT = "0.0.0.0", 9999 in the server. Now the server should listen on all interfaces and not just the loopback interface. The same could also be achieved using an empty string i.e HOST, PORT = "", 9999.
I am wondering if there is any way to wirelessly connect to a computer/server using python's socket library. The dir(socket) brought up a lot of stuff and I wanted help sorting it out.
but one question. Is the socket server specific to python, or can
another language host and python connect or vise-versa?
As long as you are using sockets - you can connect to any socket-based server (made with any language). And vice-versa: any socket-based client will be able to connect to your server. Moreover it's cross-platform: socket-based client from any OS can connect to any socket-based server (from any OS).
It is unclear of what you mean by "Connect to a computer" so I gave you a TCP socket server and client.
Create a socket server on the computer you wish to "connect to" with:
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
print self.data
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)
server.serve_forever()
Now create the client:
import socket
import sys
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])
(SOCK_STREAM means a TCP socket)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((HOST, PORT))
sock.sendall(data + "\n")
received = sock.recv(1024)
finally:
sock.close()
print "Sent: {}".format(data)
print "Received: {}".format(received)
You run the server and then the client and the server should receive the client's connection and send it whatever you have as the data variable on the server. Source: https://docs.python.org/2/library/socketserver.html
Alright, I've spent about three hours fiddling with socket programming in Python trying to make a simple chat program. I've gotten the client to send text to the server and then, from then client, it repeats the message to it's self. However, I want the message to be sent to the server and then the server, not the client, re-send it to all client's connected. I'm having issues doing this. This is my code so far:
Server Side Code:
import SocketServer
def handle(self):
data = self.request[0].strip()
socket = self.request[1]
print "%s wrote:" % self.client_address[0]
print data
socket.sendto(data.upper(), self.client_address)
if __name__ == "__main__":
HOST, PORT = "localhost", 25555
server = SocketServer.UDPServer((HOST, PORT), MyUDPHandler)
server.serve_forever()
Client Side Code:
import socket
import sys
global HOST
global PORT
HOST, PORT = "localhost", 25555
while 1 > 0:
data = raw_input(">".join(sys.argv[1:]))
# SOCK_DGRAM is the socket type to use for UDP sockets
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# As you can see, there is no connect() call; UDP has no connections.
# Instead, data is directly sent to the recipient via sendto().
sock.sendto(data + "\n", (HOST, PORT))
received = sock.recv(1024)
print "Sent: %s" % data
print "Received: %s" % received
Right now your app is instantiating the MyUDPHandler class for each client connection. When the connection is opened you need to store that instance to a static array or queue. Then when the handle() call is made it can loop through all those sockets and send a copy of the data to each of them.
I'd checkout the python documentation; it basically does what your looking to: http://docs.python.org/library/socketserver.html#asynchronous-mixins
And what I'd change from that example (Don't just drop this in; it probably has glaring bugs!):
handlerList = []
class ...
def handle(self):
handlerList.append(self)
while (1):
data = self.request.recv(1024)
if (not data):
break
cur_thread = threading.currentThread()
response = "%s: %s" % (cur_thread.getName(), data)
for x in handlerList:
x.request.send(response)
psudo_code_remove_self_from_handlerList()
Would you like to play with a server that echos packets to all sockets but the original source of the data?
import socket, select
def main():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('', 8989))
server.listen(5)
sockets = [server]
while True:
for sender in select.select(sockets, [], [])[0]:
if sender is server:
sockets.append(server.accept()[0])
else:
try:
message = sender.recv(4096)
except socket.error:
message = None
if message:
for receiver in sockets:
if receiver not in (server, sender):
receiver.sendall(message)
else:
sender.shutdown(socket.SHUT_RDWR)
sender.close()
sockets.remove(sender)
if __name__ == '__main__':
main()