I am very confused about sockets... I have two scripts, one is server.py, and second is client.py:
server.py
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 1235))
server.listen(1)
while True:
client, address = server.accept()
try:
client.recv(1024)
except socket.Timeouterror:
print 'timeout'
client.py
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('ip', 1235))
Why server.py script does not show an error of timeout?
You need to set the timeout for the socket if you wan to have one:
...
client, address = server.accept()
client.settimeout(10)
...
Or you can use a default timeout for all sockets.
socket.Timeouterror doesn't exist, it should be socket.timeout.
Also, you probably should close the client socket, otherwise the client will not know that the connection is closed. The timeout alone doesn't do that for you.
Some of the socket calls are blocking, by default. If nothing happens, they would block indefinitely. recv() is one of those calls. Other blocking calls are accept(), recvfrom(), read().
Related
I want to send some simple information, like an int or a string, between two Python programs. I thought of doing it by having the programs read and write from a single-line file. But that doesn't seem to work, since one file seems to block the file. Especially since I want to check for updates every 1/12 of a second or so.
If it did work, my idea use case would be for one program to send a message with
with open('input.py','w') as file:
file.write('hello')
and receive it with
with open('input.py','r') as file:
print(file.read())
I've been looking into how to do it with sockets, but every 'simple' tutorial seems to be targeted some much more complex use case. So how do I do what I need to do in a way that'll actually work?
The best route to go is to use the socket library. This creates a client-server connection, where you can send strings between programs from there.
server.py:
import socket
s = socket.socket()
print "Socket successfully created"
port = 12345 # Reserve a port on your computer...in our case it is 12345, but it can be anything
s.bind(('', port))
print "Socket binded to %s" %(port)
s.listen(5) # Put the socket into listening mode
print "Socket is listening"
while True:
c, addr = s.accept() # Establish connection with client
print 'Got connection from', addr
c.send('Thank you for connecting') # Send a message to the client
c.close()
client.py:
import socket
s = socket.socket()
port = 12345 # Define the port on which you want to connect
s.connect(('127.0.0.1', port)) # Connect to the server on local computer
print s.recv(1024) # Receive data from the server
s.close()
From the terminal/shell:
# start the server:
$ python server.py
Socket successfully created
Socket binded to 12345
Socket is listening
Got connection from ('127.0.0.1', 52617)
# start the client:
$ python client.py
Thank you for connecting
As you can see, the client was able to receive the string "Thank you for connecting" by the server, thanks to the send() and recv() methods from the socket library.
I have a server that uses a thread to listen for new connections and then starts one thread for every client to serve him. Now, the server runs perfectly, but when a client connects it gives me the error in the title. I think because both client and server are trying to use the same port.
Here's the server code:
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def __init__(self, conne):
initialization
def handle(self):# "run"
does something
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
HOST = '' # Symbolic name meaning all available interfaces
PORT = 1000 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(5)
n=1
while 1:
conn, addr = s.accept() # wait for a new connection. Get a new socket (conn) for each new connection
print 'Connected by', addr
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler) #this line gives me the error
ip, port = server.server_address
server_thread = threading.Thread(target=server.serve_forever)
server_thread.setDaemon(True)
server_thread.setName('Client '+str(n))
server_thread.start() # Start the new thread
n+=1
server.shutdown()
server.server_close()
And here's the client:
import socket
HOST, PORT = "localhost", 1000
data = "0"
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((HOST, PORT))
sock.sendall(data)
received = sock.recv(1024)
finally:
sock.close()
print "Sent: {}".format(data)
print "Received: {}".format(received)
First you create server socket and bind it to port 1000. Then when client connects you receive a socket connected with client (conn, addr = s.accept()) that should be used to communicate with client but you completely ignore it. Instead you create another server that tried to bind again to port 1000. This results in "already used" error as expected.
I'd suggest you check this example of TcpServer threading and forking. Here a custom class derived from SocketServer.TCPServer is created initially (not a simple server socket as you do). It internally loops over accepting incoming client connections and for each connection calls specified SocketServer.BaseRequestHandler from a new thread or process (in case of forking) so you don't need to deal with them explicitly. Custom request handler just needs to, well, handle the request, potentially in a loop if communication with client is multi-step.
Be aware that thread/process per client approach doesn't scale well on large number of simultaneous client connections.
When I try to execute Python server socket program and client socket program (both running in same linux machine) in Linux terminal I don't get any error, server accepts connection and sends data to client successfully.
But when I execute the same programs in python IDLE I get "[Errno 111] Connection refused" error.
What is the difference in both execution?
I'm using serversock.bind(('',port#)) in server
and in client i'm using clientsock.connect(('localhost',port#))
Server.py
import socket
serversock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = ''
print host
port = 5800
serversock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serversock.bind((host,port))
serversock.listen(2)
try:
while True:
csock,addr = serversock.accept()
print 'Recieved address from %s '% str(addr)
csock.send('hello')
csock.close()
except Exception,e:
print e
client.py
import socket
try:
c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = 'localhost'
port = 5800
c.connect((host,port))
data = c.recv(1024)
print data
except Exception,e:
print e
finally:
c.close()
Server side you must use:
serversock.bind(('',port#)) # binds to port
serversock.listen(5) # actually listen to port and allow 5 incoming calls
conv = serversock.accept() # accept first incoming call
The connection will only be accepted after the listen call, before it, you have only bound a socket, but have not declared that you were ready to accept incoming calls, so they are refused.
With added code, another possible error cause is that you close connection (server side) immediately after sending data. That is bad: the close condition can destroy the socket before the data has actually been sent.
You should use a graceful shutdown:
server side:
csock.send('hello')
csock.shutdown(socket.SHUT_WR) # shutdown the socket
csock.read() # wait the close from peer
csock.close()
client side: you can leave the code as is in your use case you do not send anything to server, so when the client has finished reading it can safely close the socket
Anyway you should close serversock when everything is finished
try:
...
except ...:
...
finally:
serversock.close()
So I am trying to make a server program that will call the client program. The server client work fine if I call them myself from the command line but the connection is refused when the server calls it. Why is this not working?
This is the server code:
import socket,os
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
os.remove("/tmp/SocketTest")
except OSError:
pass
s.bind("/tmp/SocketTest")
os.system("python compute.py")#compute is the client
#execfile('compute.py')
s.listen(1)
conn, addr = s.accept()
while 1:
data = conn.recv(1024)
if not data: break
conn.send(data)
conn.close()
This is the client code:
import socket
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/tmp/SocketTest")
s.send('Hello, world \n')
s.send('its a mighty fine day')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
os.system will run the command you give it to completion, and you’re doing this before you call listen. As such, the client will try to connect to the server before it’s listening. Only once the client exits will the server move on past that line of code to actually start listening and accepting connections.
What you probably want to do is after the call to listen, but before the call to accept (which is when you start blocking), use subprocess.Popen to spawn a subprocess and do not wait on it.
I think the error is that you're calling compute.py before calling listen.
os.system will block your server until the call to python compute.py is completed.
Try subprocess.Popen to spawn the call to compute.py in parallel to your server in a non blocking manner. Callingsubprocess.Popen will launch python compute.py in a new process, and will continue executing the next line conn, addr = s.accept() )
#!/usr/bin/env python
import socket
import os
import subprocess
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
os.remove("/tmp/SocketTest")
except OSError:
pass
s.bind("/tmp/SocketTest")
s.listen(1)
sp = subprocess.Popen(["/usr/bin/env", "python", "compute.py"])
conn, addr = s.accept()
while 1:
data = conn.recv(1024)
if not data:
break
conn.send(data)
conn.close()
That outputs:
Received 'Hello, world \nits a mighty fine day'
This works fine
#!/usr/bin/python
import urllib
import socket
import os
s = socket.socket()
host = socket.gethostname()
port = 1514
s.bind((host, port))
s.listen(500)
c, addr = s.accept()
while True:
# Establish connection with client.
print 'Got connection from', addr
print c.recv(1024)
c.send('Recieved')
c.close()
raw_input()
But a few things:
When the client disconnects, the program closes. I want to make it so even if the client disconnects, the program will keep on listening for a new connection
How can I make it wait infinitely for a connection?
You can just put a while True loop on the outside and try/except for the connection closing inside. In other words, accept() can be called in a loop.
However, the "right" way to do this is usually with an asynchronous/event-driven approach as is implemented by Python Twisted. That way you can accept connections from multiple clients concurrently, rather than having to wait for one connection to close before accepting the next one.