I am currently working on a problem where I need to have a server handle multiple clients at the same time. I have a server.py file and a client.py file. Here is a snippet from server.py:
connections = []
addresses = []
for c in connections:
c.close()
del connections[:]
del addresses[:] #clears anything pre-existing
while True:
try:
csock, address = s.accept() #takes in connection and stores info
s.setblocking(1) #prevents timeout
connections.append(csock)
addresses.append(address)
print(f"Connection from {address} has been established!")
except:
print("Error has occurred")
When I run my server in terminal and then connect to it with a client. It behaves as I would expect, with it printing out Connection from ('192.168.1.84', 50824) has been established!.
When I open up another terminal and run client.py to make an additional connection, nothing happens. That is, until I close out of my first client process and then the server prints out
Error occurred
Connection from ('192.168.1.84', 50826) has been established!
I can kind of see what is happening here, but I'm very new to networking and I'm not super great at multithreading, so could anyone give me some insight as to what's going on and what I can do to make these processes run simultaneously as I would expect?
After s.accept() you should use threading to run code in separated thread - and this thread should continue connection with client. At the same time main thread may go back to s.accept() to wait for next client.
Minimal working code with some extra settings.
Server:
import socket
import threading
import time
# --- functions ---
def handle_client(conn, addr):
print("[thread] starting")
# recv message
message = conn.recv(1024)
message = message.decode()
print("[thread] client:", addr, 'recv:', message)
# simulate longer work
time.sleep(5)
# send answer
message = "Bye!"
message = message.encode()
conn.send(message)
print("[thread] client:", addr, 'send:', message)
conn.close()
print("[thread] ending")
# --- main ---
host = '0.0.0.0'
port = 8080
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # solution for "[Error 89] Address already in use". Use before bind()
s.bind((host, port))
s.listen(1)
all_threads = []
try:
while True:
print("Waiting for client")
conn, addr = s.accept()
print("Client:", addr)
t = threading.Thread(target=handle_client, args=(conn, addr))
t.start()
all_threads.append(t)
except KeyboardInterrupt:
print("Stopped by Ctrl+C")
finally:
if s:
s.close()
for t in all_threads:
t.join()
Client (for test)
import socket
# --- main ---
host = '0.0.0.0'
port = 8080
s = socket.socket()
s.connect((host, port))
print("Connected to the server")
message = "Hello"
print('send:', message)
message = message.encode()
s.send(message)
message = s.recv(1024)
message = message.decode()
print('recv:', message)
Related
Based on the highest-rated answer to this post:
Socket : 2 way communication in python
And the docks:
https://docs.python.org/3/library/socket.html#targetText=socket.makefile
I'm attempting to work out how to use socket.makefile to send/receive over a socket. Here is what I have so far:
Server.py:
# Server.py
import socket
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# bind the socket
sock.bind((HOST, PORT))
print('socket binded')
# start the socket listening
sock.listen(10)
print('socket now listening')
# accept the socket response from the client, get the connection object
conn, addr = sock.accept() # Note: execution waits here until the client calls sock.connect()
print('socket accepted, got connection object')
sockFile = sock.makefile()
while True:
message = sockFile.readline()
print('received: ' + str(message))
# end while
# end main
if __name__ == '__main__':
main()
Client.py:
# Client.py
import socket
import time
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# connect the socket
sock.connect((HOST, PORT)) # Note: if execution gets here before the server starts up, this line will cause a crash
print('socket connected')
sockFile = sock.makefile(mode='w')
myCounter = 0
while True:
message = 'message ' + str(myCounter)
print('sending: ' + message)
sockFile.write(message)
myCounter += 1
time.sleep(1) # wait for 1 sec before sending next text message
# end while
# end main
if __name__ == '__main__':
main()
Right now if I start the server, then the client from separate command prompts, the client seems to be working:
Client.py output:
$ python3 Client.py
socket instantiated
socket connected
sending: message 0
sending: message 1
sending: message 2
sending: message 3
sending: message 4
sending: message 5
But the server fails with the error:
$ python3 Server.py
socket instantiated
socket binded
socket now listening
socket accepted, got connection object
Traceback (most recent call last):
File "Server.py", line 38, in <module>
main()
File "Server.py", line 32, in main
message = sockFile.readline()
File "/usr/lib/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
OSError: [Errno 107] Transport endpoint is not connected
How can I connect the transport endpoint successfully on the server when using socket.makefile? I'm not sure what the syntax is in this case. I don't end up using conn and addr as I would on the server with the more traditional way of doing it, perhaps that's where I'm going wrong?
--- Edit ---
In Server.py I tried to use the connection with the makefile() function like so:
.
.
.
# accept the socket response from the client, get the connection object
conn, addr = sock.accept() # Note: execution waits here until the client calls sock.connect()
print('socket accepted, got connection object')
connFile = conn.makefile()
while True:
message = connFile.readline()
print('received: ' + str(message))
# end while
.
.
.
But this does not work either, Client.py still works as before but now Server.py just hangs:
$ python3 Server.py
socket instantiated
socket binded
socket now listening
socket accepted, got connection object
(hangs here forever)
--- Edit2 ---
Now I'm really confused. Based on this post:
https://bugs.python.org/issue35928
I pretty much copied the posters code so Server.py now looks like this:
# Server.py
import socket
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
print(f'Waiting for connection on port {s.getsockname()[1]}')
s.listen(1)
conn, addr = s.accept()
print(f'Connected by {addr}')
with conn:
f = conn.makefile(mode='rw')
while True:
print('before f.readline()')
m = f.readline()
print('after f.readline()')
print(f'msg: {m!r}')
if not m:
exit(0)
f.write(m)
f.flush()
# end main
if __name__ == '__main__':
main()
And Server.py still hangs on the read!!
$ python3 Server.py
Waiting for connection on port 65439
Connected by ('127.0.0.1', 47536)
before f.readline()
According to the last post in the responses the poster's original concern is supposedly fixed so this should work now. I'm still not sure how to accomplish this.
--- Edit3 ---
I'm using Ubuntu 18.04.3 with the latest updates and Python 3.6.9 if that matters
In your server code:
conn, addr = sock.accept()
calls sock.connect()
sockFile = sock.makefile()
while True:
message = sockFile.readline()
You made a client socket (conn) but you never used it.
The client is writing so you should be reading from the client socket (conn)
Also I think you should call accept from inside the while loop.
while True:
conn, addr = sock.accept()
sockFile = conn.makefile()
message = sockFile.readline()
Socket does not work this way. It is supposed to complete one message and to be destroyed. See "Socket Programming HOWTO" by Gordon McMillan on Python documentation page. So you could organize your code like below. This transmits one message and then shutdown/close.
# server.py
import socket
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# bind the socket
sock.bind((HOST, PORT))
print('socket binded')
# start the socket listening
sock.listen(10)
print('socket now listening')
# accept the socket response from the client, get the connection object
conn, addr = sock.accept() # Note: execution waits here until the client calls sock.connect()
print('socket accepted, got connection object')
sockFile = conn.makefile()
# while True:
message = sockFile.readline()
print('received: ' + str(message))
# end while
# end main
if __name__ == '__main__':
main()
and client code,
# client.py
import socket
import time
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# connect the socket
sock.connect((HOST, PORT)) # Note: if execution gets here before the server starts up, this line will cause a crash
print('socket connected')
sockFile = sock.makefile(mode='w')
myCounter = 0
# while True:
message = 'message ' + str(myCounter) + '\r\n'
print('sending: ' + message)
sockFile.write(message)
# sockFile.flush()
sockFile.close()
# myCounter += 1
# time.sleep(1) # wait for 1 sec before sending next text message
# end while
# end main
if __name__ == '__main__':
main()
If you really want to transmit multiple messages in one script, create one new socket for each message. See code below,
# server_multi.py
import socket
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# bind the socket
sock.bind((HOST, PORT))
print('socket binded')
# start the socket listening
sock.listen(10)
print('socket now listening')
while True:
# accept the socket response from the client, get the connection object
conn, addr = sock.accept() # Note: execution waits here until the client calls sock.connect()
print('socket accepted, got connection object')
sockFile = conn.makefile()
# while True:
message = sockFile.readline()
print('received: ' + str(message))
conn.close()
# end while
# end main
if __name__ == '__main__':
main()
and the client code looks like this,
# client_multi.py
import socket
import time
# module-level variables
HOST='127.0.0.1'
PORT=65439
ACK_TEXT = 'text_received'
def main():
# instantiate a socket object
myCounter = 0
while True:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket instantiated')
# connect the socket
sock.connect((HOST, PORT)) # Note: if execution gets here before the server starts up, this line will cause a crash
print('socket connected')
sockFile = sock.makefile(mode='w')
# while True:
message = 'message ' + str(myCounter) + '\r\n'
print('sending: ' + message)
sockFile.write(message)
# sockFile.flush()
sockFile.close()
myCounter += 1
time.sleep(1) # wait for 1 sec before sending next text message
# end while
# end main
if __name__ == '__main__':
main()
I am a total beginner in Python and today I tried to create a simple chat-program. So far it doesn't work too bad, but I am unable to communicate between the server and the client. I can only send from the server to the client but not in the other direction. I tried it with multithreading and these are the results:
Server:
import socket
import threading
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "127.0.0.1"
port = 4444
s.bind((host, port))
s.listen(3)
conn, addr = s.accept()
print("Connection from: "+str(addr[0])+":"+str(addr[1]))
def recv_data():
while True:
data = s.recv(2048).decode('utf-8')
print(data)
def send_data():
while True:
msg = input(str(socket.gethostname())+"> ")
msg = str(host + "> ").encode('utf-8') + msg.encode('utf-8')
conn.send(msg)
#t1 = threading.Thread(target=recv_data)
t2 = threading.Thread(target=send_data)
#t1.start()
t2.start()
Client:
import socket
import threading
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "127.0.0.1"
port = 4444
s.connect((host, port))
print("Connected to: "+ host)
def recv_data():
while True:
data = s.recv(2048)
data = data.decode('utf-8')
print(data)
def send_data():
while True:
msg = input(str(host)+"> ").encode('utf-8')
s.send(msg)
t1 = threading.Thread(target=recv_data)
#t2 = threading.Thread(target=send_data)
t1.start()
#t2.start()
This code works; the server can send, the client receive, but whenever I uncomment the second thread, so that it can do both I get an error:
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
I can't seem to find a solution, so please help, what am I doing wrong? :D
conn, addr = s.accept()
def recv_data():
while True:
data = s.recv(2048).decode('utf-8')
print(data)
conn is actually the socket you want to send or recv. The error occurs because you are trying to recv from the server socket, which is illegal action. Therefore you need to change s to conn if you want to make it work.
As in my chatting app here, when client sends a message sends a message to server it becomes necessary for server to send a reply before client can send a message again. How to avoid this?
Server program:
from socket import *
import threading
host=gethostname()
port=7776
s=socket()
s.bind((host, port))
s.listen(5)
print "Server is Ready!"
def client():
c, addr= s.accept()
while True:
print c.recv(1024)
c.sendto(raw_input(), addr)
for i in range(1,100):
threading.Thread(target=client).start()
s.close()
Client program:
from socket import *
host=gethostname()
port=7776
s=socket()
s.connect((host, port))
while True:
s.send(( raw_input()))
data= s.recv(1024)
if data:
print data
s.close()
I am pretty sure you were meant to make the central server receive messages from clients, and send them to all other clients, was it not? What you implemented isn't exactly that - instead, the server process just prints all messages that arrive from the clients.
Anyways, based on the way you implemented it, here's a way to do it:
Server:
from socket import *
import threading
def clientHandler():
c, addr = s.accept()
c.settimeout(1.0)
while True:
try:
msg = c.recv(1024)
if msg:
print "Message received from address %s: %s" % (addr, msg)
except timeout:
pass
host = "127.0.0.1"
port = 7776
s = socket()
s.bind((host, port))
s.listen(5)
for i in range(1, 100):
threading.Thread(target=clientHandler).start()
s.close()
print "Server is Ready!"
Client:
from socket import *
host = "127.0.0.1"
port = 7776
s = socket()
s.settimeout(0.2)
s.connect((host, port))
print "Client #%x is Ready!" % id(s)
while True:
msg = raw_input("Input message to server: ")
s.send(msg)
try:
print s.recv(1024)
except timeout:
pass
s.close()
I have a flash client use XMLsocket to connect python server like this:
Security.loadPolicyFile("xmlsocket://*.*.*.*:843");
socket = new XMLSocket();
socket.connect('*.*.*.*', 50000);
socket.send('hello world');
I use this python script to send security file
#security.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 843))
s.listen(5)
print('Start...')
def link(sock, addr):
print('Accept new connection from %s:%s...' % addr)
while True:
data = sock.recv(1024)
str = data.decode('utf-8')[:22]
if str=='<policy-file-request/>':
print('!!!!!!!')
sock.send(b'<?xml version="1.0"?>')
sock.send(b'<cross-domain-policy>')
sock.send(b'<allow-access-from domain="*" to-ports="50000" />')
sock.send(b'</cross-domain-policy>\0')
sock.close()
break
print('')
while True:
sock, addr = s.accept()
t = threading.Thread(target=link, args=(sock, addr))
t.start()
and use this to receive messages from client:
#server.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('0.0.0.0', 50000))
s.listen(5)
print('Waiting for connection...')
def tcplink(sock, addr):
print('Accept new connection from %s:%s...' % addr)
while True:
data = sock.recv(1024)
print(data.decode('utf-8'))
while True:
sock, addr = s.accept()
t = threading.Thread(target=tcplink, args=(sock, addr))
t.start()
when these scripts run,security.py outputs:
Start...
Accept new connection from *.*.*.*....
!!!!!!!
but server.py outputs nothing except this:
Waiting for connection...
and the debug of flash outputs nothing neither
it seems flash received security file successfully,but the XMLsocket.connect failed?
Hard to say what's wrong here but I'd guess there's still a security problem somewhere. Why don't you add event listeners to the socket connection and see if you will get any error messages? Take a look here at the bottom of the page for some event listener examples: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/XMLSocket.html .
And I guess you have already carefully read this, maybe it will give you some hints: http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7c60.html
I'm writing a very basic chat room in python. Clients connect and any message from a client is relayed to all clients. The problem I'm having is getting the client to listen and send messages at the same time. It seems to only do either one. I've set up a separate listening client and confirmed that the message is received but the listening server cannot send anything.
Currently the client has to send data before getting a response from the server, but I want clients to be able to receive data before sending - otherwise the chat room won't work. I attempted using clientsock.settimeout() and then use recv but it did not solve the issue as it did not move past the input part.
server.py
#!/usr/bin/python
#socket server using threads
import socket, sys, threading
from _thread import *
HOST = 'localhost'
PORT = 2222
lock = threading.Lock()
all_clients = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print ("Socket created")
#bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print ("Bind failed. Error code: " + str(msg[0]) + ' Message ' + msg[1])
sys.exit(0)
print ("Socket bind complete")
#Start listening on socket
s.listen(5)
print ("Socket now listening")
#function for handling connections. This will be used to create threads
def clientthread(conn):
#sending message to connected client
conn.send("Welcome to the server. Type something and hit enter\n".encode('utf-8'))
#infinite loop so that function does not terminate and thread does not end
while True:
#receiving data from client
data = conn.recv(1024)
reply = "OK..." + str(data, "utf-8")
if not data:
break
with lock:
for c in all_clients:
c.sendall(reply.encode('utf-8'))
#came out of loop
conn.close()
#keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
with lock:
all_clients.append(conn)
print ("Connected with " + addr[0] + ":" + str(addr[1]))
#start new thread takes 1st argument as a function name to be run, second
#is the tuple of arguments to the function
start_new_thread(clientthread ,(conn,))
s.close()
client.py
#!/usr/bin/python
import socket, sys
#client to transfer data
def main():
#create tcp stocket
clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#connect the socket to the server open port
server_address = ('localhost', 2222)
print ("connecting to %s port %s" % server_address)
clientsock.connect(server_address)
#receive data
data = clientsock.recv(1024)
print(str(data, "utf-8"))
while 1:
#send data
message = "sean: " + input()
clientsock.send(message.encode('utf-8'))
#look for the response
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = clientsock.recv(1024)
amount_received += len(data)
print ("received %s " % data)
print ("closing socket")
clientsock.close()
main()
new_client.py
#!/usr/bin/python
import socket, sys
from threading import Thread
#client for chat room
def send_msg(sock):
while True:
data = input()
sock.send(data.encode('utf-8'))
def recv_msg(sock):
while True:
stuff = sock.recv(1024)
sock.send(stuff)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 2222)
sock.connect(server_address)
print("Connected to chat")
Thread(target=send_msg, args=(sock,)).start()
Thread(target=recv_msg, args=(sock,)).start()
Create two threads, one for receiving the other for sending. This is the simplest way to do.
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect("address")
def send_msg(sock):
while True:
data = sys.stdin.readline()
sock.send(data)
def recv_msg(sock):
while True:
data, addr = sock.recv(1024)
sys.stdout.write(data)
Thread(target=send_msg, args=(sock,)).start()
Thread(target=recv_msg, args=(sock,)).start()