In the code shown below I am using the blocking call to receive 50 bytes of data from socket and echo it back.But what is happening is that the code stuck after receiving one byte.In the telnet running on another command prompt the connection still shows as connected. What might be missing from this ?
import socket
import sys
host = ''
port = 8888
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((host,port))
print 'Socket Bind Complete'
s.listen(10)
print 'Now Listening'
while 1:
conn, adr = s.accept()
print 'connected with' + adr[0] + ':' + str(adr[1])
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
s.close()
The problem is that you're accepting a new connection each time through the loop, and only receiving from that connection once. The next time through the loop, your forget about that connection and accept a new one, which blocks until someone else connects.
If you just want to handle a single connection and quit, just move the accept outside the loop:
conn, adr = s.accept()
print 'connected with' + adr[0] + ':' + str(adr[1])
while True:
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
s.close()
If you want to handle one connection at a time, but then wait for a new connection after you finish with the first, add an outer loop.
while True:
conn, adr = s.accept()
print 'connected with' + adr[0] + ':' + str(adr[1])
while True:
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
s.close()
If you want to handle more than one connection at a time, as most servers do, you need some sort of asynchronous mechanism—select and nonblocking sockets, gevent, threads, whatever. For example:
def handle_client(conn, addr):
print 'connected with' + adr[0] + ':' + str(adr[1])
while True:
data = conn.recv(50)
print data
if not data:
break
conn.sendall(data)
conn.close()
client_threads = []
try:
while True:
conn, adr = s.accept()
client_thread = threading.Thread(target=handle_client, args=[conn, addr])
client_thread.start()
client_threads.append(client_thread)
finally:
s.close()
for client_thread in client_threads:
client_thread.join()
In any of these designs, you're probably better off using a with statement instead of explicit close calls and/or try/finally.
Related
I'm building a tcp/ip server in python that works with clients.
Each client gets its own thread and its socket is added to a list called client_list.
there also is a variable "clients_connected" which stores the amount of connected clients.
for some reason it just works with one client at the moment.
Also when a client disconnects, it should be removed from client_list but I'm not sure how to do that.
Could you take a look at the code please? thanks a lot!
this thread is looking for incoming connections:
def addclientsthread(sock):
global client_list
conn, addr = sock.accept()
client_list += [conn]
print_line('Client connected on ' + addr[0] + "\n")
start_new_thread(clientthread, (conn,))
So when a client connects it gets its own "clientthread"
def clientthread(conn):
# handling connections.
global clients_connected
while True:
# Receiving from client
in_data = conn.recv(1024)
data = decrypt(in_data)
if data.lower().find("id=-1") != -1:
clients_connected += 1
print_line("new client ID set to " + str(clients_connected) + "\n")
crypted_msg = encrypt("SID=" + str(clients_connected))
conn.sendall(crypted_msg)
pass
elif data.lower().find("uin") == 0:
uin_id = int(data[4:])
clients_connected -= 1
break
else:
print_line(data)
if not data:
break
# If client disconnects
conn.close()
Oh and please don't hate, I just started coding :)
EDIT: This is the main code (not in a thread)
HOST = ''
PORT = 8820
clients_connected = 0
client_list = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Socket created')
# Bind socket to host and port
try:
s.bind((HOST, PORT))
except socket.error, msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket successfully binded'
# Start listening on socket
s.listen(100000)
print 'Socket is listening'
start_new_thread(addclientsthread, (s,))
is their a function that i can check if there is incoming connection or not to the server ( inside While Loop )?
import socket
import sys
HOST = ''
PORT = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
try:
s.bind((HOST, PORT))
except socket.error , msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
s.listen(10)
print 'Socket now listening'
while 1:
##### IF there is request to server Do #####
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
data = conn.recv(1024)
reply = 'OK...' + data
conn.sendall(reply)
##### Else Do something else like print for example #####
print 'Nothing yet'
conn.close()
s.close()
what i want to do is to check if there is no request to my server i will do something else.
is it possible to do that?
Yes, there's a such function.
From man accept:
In order to be notified of incoming connections on a socket, you can
use select(2), poll(2), or epoll(7). A readable event will be
delivered when a new connection is attempted and you may then call
accept() to get a socket for that connection.
In python you can use select combined with the timeout parameter:
import select
# somewhere in a while loop
timeout = 0
incoming_connections, _, __ = select.select([s], [], [], timeout)
if incoming_connections:
conn, addr = s.accept()
...
else:
...
Hello I've been trying to make my python sock server connection counter to go down
but I can't figure out how I can do this
def client_thread(conn):
while True:
conn.send("Command: ")
data = conn.recv(1024)
if not data:
break
reply = "" + data
conn.sendall("\r")
if data == "!* Connections":
conn.sendall("[+] Clients Connected: %s \r\n" % (clients))
conn.close()
while True:
conn, addr = sock.accept()
clients = clients + 1
start_new_thread(client_thread, (conn,))
sock.close()
I needn't show you all of the code because its irrelevant to this issue,
I have provided the code that make's the counter go up when a new connection connects, but as said before I don't know how to make it go down when a connection leaves.
When trying to find solutions online there show's nothing that can help my issue
Here is a small sample how to realize a client counter with the select.select function. I actually took it from the great article select – Wait for I/O Efficiently on pymotw.com and added a client counter. Basically you look for readable sockets and try to receive data from them. If a socket returns nothing it means it has been closed and can be removed from the client list.
import queue
import socket
import select
clients = 0
sock = socket.socket()
sock.bind(('localhost', 5000))
sock.listen(5)
inputs = [sock]
outputs = []
msg_queues = {}
while inputs:
readable, writable, exceptional = select.select(
inputs, outputs, msg_queues)
for s in readable:
if s is sock:
conn, addr = sock.accept()
print('new connection from ', addr)
conn.setblocking(0)
inputs.append(conn)
msg_queues[conn] = queue.Queue()
# increment client counter
clients += 1
print('Clients: ', clients)
else:
# try to receive some data
data = s.recv(1024)
if data:
# if data available print it
print('Received {} from {}'.format(data, s.getpeername()))
msg_queues[s].put(data)
# add output channel for response
if s not in outputs:
outputs.append(s)
else:
# empty data will be interpreted as closed connection
print('Closing connection to ', s.getpeername())
# stop listening for input on the connection
if s in outputs:
outputs.remove(s)
# remove from inputs
inputs.remove(s)
s.close()
# decrement client counter
clients -= 1
del msg_queues[s]
print('Clients: ', clients)
How can I have a Python socket server tell me when there is a connection and then CONTINUE to give me back data that the client sends? When I do it, it connects and then just loops over, telling me it connected over and over again.
I,just want it to connect and then continually check (or grab) data sent to the server.
Also, how can I tell if the client disconnected?
address = ('', 7777)
server_socket = socket(AF_INET, SOCK_STREAM)
server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
try:
server_socket.bind(address)
except Exception, e:
print colored("Address already in use", 'red')
server_socket.listen(2)
print colored("Socket ready", 'blue')
while True:
client_socket, addr = server_socket.accept()
hostIP = addr[0]
port = addr[1]
try:
host = gethostbyaddr(hostIP)[0]
except:
host = hostIP
print colored("Got connection from: " + host, 'blue')
try:
recv_data = server_socket.recv(2048)
print("Got: " + recv_data)
except:
print "nothing"
recv_data = "" # this is because I test what it is later, but that's irrevlevant.
Thanks
You didn't do anything with client_socket; ie: the actual client connection. Furthermore, the server
cannot know how much the client wants to send and so it must CONTINUE (ie: in a
loop) to receive data. When the connection sends 'empty' data, the connection
is terminated and the server goes back to listening. If you want the server to
accept new connections and continue to receive data from existing connections
look up the threading module.
import socket
address = ('', 7777)
server_socket = socket.socket(AF_INET, SOCK_STREAM)
server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
try:
server_socket.bind(address)
except Exception, e:
print colored("Address already in use", 'red')
server_socket.listen(2)
print colored("Socket ready", 'blue')
while True:
client_socket, addr = server_socket.accept()
hostIP = addr[0]
port = addr[1]
try:
host = gethostbyaddr(hostIP)[0]
except:
host = hostIP
print colored("Got connection from: " + host, 'blue')
while True:
try:
recv_data = client_socket.recv(2048)
if not recv_data:
break
print("Got: " + recv_data)
except socket.error, e:
print "nothing"
recv_data = "" # this is because I test what it is later, but that's irrevlevant.
I am writing a simple TCP server in python, and am trying to input a timeout. My current code:
import socket
def connect():
HOST = '' # Symbolic name meaning the local host
PORT = 5007 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
s.settimeout(5)
conn, addr = s.accept()
print 'Connected by', addr
return conn
conn = connect()
while 1:
data = conn.recv(1024)
if not data: break
print data
conn.close()
Issue is when I try to connect I get an error at data = conn.recv(1024)
error: [Errno 10035] A non-blocking socket operation could not be completed immediately
Code works without the timeout.
You can turn on blocking:
# ...
conn.setblocking(1)
return conn
# ...
Try to set the timeout on the socket and the blocking on the connection. Like this:
import socket
def connect():
HOST = '' # Symbolic name meaning the local host
PORT = 5007 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
s.bind((HOST, PORT))
s.listen(1)
return s
s = connect()
while 1:
conn, addr = s.accept()
print 'Connected by', addr
conn.setblocking(1)
data = conn.recv(1024)
conn.close()
if not data: break
print data
s.close()
Ran into the same problem 30 minutes ago. Found a simple non-elegant work around...if you give the socket time to breathe by doing time.sleep(1), catching the 10035 error and doing a retry it works. I'm using 2.7.5...maybe this is a bug that got fixed. Not real sure.
Code sample...please understand this is very simplistic test code I use (only recv 1 byte at a time).So where 's' is the socket with a 10s timeout and 'numbytes' is number of bytes I need...
def getbytes(s,numbytes):
din = ''
socketerror10035count = 0
while True:
try:
r = s.recv(1).encode('hex')
din += r
if len(din)/2 == numbytes:
print 'returning',len(din)/2, 'bytes'
break
except socket.timeout as e:
din = 'socket timeout'
break
except socket.error as e:
if e[0] == 10035 and socketerror10035count < 5:
socketerror10035count = socketerror10035count +1
time.sleep(1)
else:
din = 'socket error'
break
except:
din = 'deaddead'
break
return din
For Python 3 and above, the above code which references e as a scriptable object will need to be changed to "e.errno". And, of course the print statements require parenthesis around the arguments.
Additionally, you may want to change the "except socket.error as e:" line to "except BlockingIOError as e:". However, the code works as is under Python 3.8.5 on Windows.