Simple server application in Python - python

Problem: My server application only accepts one connection at a time. I'd like to know why serverSocket.listen() doesn't listen and serverSocket.accept() doesn't accept all connections.
import socket
SERVER_ADDRESSES = ['0.0.0.0']
SERVER_PORT = 8091
CONNECTED_CLIENTS = {}
def processClientConnection(clientSocket, clientAddress):
while True:
try:
print("Listening for messages...")
message = clientSocket.recv(1024)
message = message.decode("UTF-8")
for client in CONNECTED_CLIENTS.keys():
print(f"{CONNECTED_CLIENTS[client]} vs {clientAddress}")
print(CONNECTED_CLIENTS[client] == clientAddress)
if CONNECTED_CLIENTS[client] != clientAddress:
print(f"Sending message to {CONNECTED_CLIENTS[client]}")
client.send(b"%s: %s" % (CONNECTED_CLIENTS[client][0], message))
except ConnectionResetError:
print(f"{CONNECTED_CLIENTS[clientSocket][0]} disconnected!")
for client in CONNECTED_CLIENTS.keys():
if clientSocket != client:
client.send(b"%s disconnected!" % CONNECTED_CLIENTS[clientSocket][0])
del(CONNECTED_CLIENTS[clientSocket])
def startServer(serverAddress):
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(f"Socket Host Name: {serverAddress}:{SERVER_PORT}")
serverSocket.bind((serverAddress, 8091))
# become a server socket
while True:
print("Listening for connections")
serverSocket.listen()
(clientSocket, address) = serverSocket.accept()
if (clientSocket, address) in CONNECTED_CLIENTS:
print("Can't connect multiple of same client")
break
CONNECTED_CLIENTS[clientSocket] = address
print(f"{CONNECTED_CLIENTS[clientSocket][0]} connected!")
ct = threading.Thread(target=processClientConnection, args=([clientSocket, address]))
ct.run()
def runServer():
for serverAddress in SERVER_ADDRESSES:
serverThread = threading.Thread(target=startServer, args=([serverAddress]))
serverThread.start()
if __name__ == '__main__':
print('Server Started')
runServer()
import socket
SERVER_ADDRESS = '127.0.0.1'
SERVER_PORT = 8091
def receiveMessage(sock):
while True:
try:
message = sock.recv(1024).decode("UTF-8")
if len(message):
print(message)
except ConnectionResetError:
print("Server disconnected you")
sock.close()
exit(0)
except ConnectionAbortedError:
print("Server disconnected you")
sock.close()
exit(0)
def sendMessage(sock):
while True:
try:
message = input()
sock.send(bytes(message, "UTF-8"))
except ConnectionResetError:
print("Server disconnected you")
sock.close()
exit(0)
except ConnectionAbortedError:
print("Server disconnected you")
sock.close()
exit(0)
except EOFError:
print("Client closed")
sock.close()
exit(0)
def runClient():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((SERVER_ADDRESS, SERVER_PORT))
except TimeoutError:
print("Server down")
s.close()
exit(0)
except ConnectionRefusedError:
print("Server down")
s.close()
exit(0)
print("Connected to server. Type your message.\n")
messagingThread = threading.Thread(target=sendMessage, args=([s]))
messagingThread.start()
receivingThread = threading.Thread(target=receiveMessage, args=([s]))
receivingThread.start()
if __name__ == '__main__':
print("Client started")
runClient()

while True:
print("Listening for connections")
serverSocket.listen()
(clientSocket, address) = serverSocket.accept()
...
ct = threading.Thread(target=processClientConnection, args=([clientSocket, address]))
ct.run()
This is wrong in multiple ways:
A server socket should be created once, should be bound once to the address and should call listen once in order to setup the listen queue. After that accept should be called again and again to get the newly established connections. You instead create it once, bind it once but then call listen again and again.
You are attempting to create a new thread for each new connection in order to handle the new client connection in parallel to the other activity. But since you use ct.run() instead of ct.start() the thread function will be called directly within the current thread and not in parallel to the existing one. This means new connections will only be accepted once the code is done with the current one.

Related

How to handle multithreading with sockets in Python?

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)

Running an echo server as a daemon process for testing in python

I want to automate testing of an instrument and wrote a little server program to imitate the instrument which will send back the command except when it receives a special command "*IDN?". When I ran the echo server directly in its own script, and then run a client script separately, everything works great, and I am getting back the expected results. Now I wanted to run the server directly from the testing script. So I thought I would start it using multiprocessing. But the problem seems to be when the server socket gets to the s.accept() line it just waits there and never returns. So how do I accomplish automated testing if I cannot run this server in the same code as the test function?
import socket
import multiprocessing as mp
import time,sys
HOST = '127.0.0.1' # Standard loopback interface address (localhost),
PORT = 65432 # Port to listen on (non-privileged ports are > 1023),
FTP_PORT = 63217 # Port for ftp testing, change to 21 for device
def handle_connection(conn,addr):
with conn:
conn.send('Connected by', addr)
print("Got connection")
data = conn.recv(1024)
if not data:
return 'Nodata'
elif (data == b'*IDN?\n'):
print('SONY/TEK,AWG520,0,SCPI:95.0 OS:3.0 USR:4.0\n')
conn.sendall(b'SONY/TEK,AWG520,0,SCPI:95.0 OS:3.0 USR:4.0\n')
return 'IDN'
else:
conn.sendall(data)
return 'Data'
def echo_server(c_conn,host=HOST,port=PORT):
# this server simulates the AWG command protocol, simply echoing the command back except for IDN?
p = mp.current_process()
print('Starting echo server:', p.name, p.pid)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((host, port))
s.listen()
try:
while True:
print("Waiting for connection...")
c_conn.send('waiting for connection...')
conn, addr = s.accept()
handle_connection(conn,addr)
c_conn.send('serving client...')
finally:
conn.close()
c_conn.send('done')
time.sleep(2)
print('Exiting echo server:', p.name, p.pid)
sys.stdout.flush()
def test_echo_server():
print("entering client part")
with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as mysock:
mysock.connect((HOST,PORT))
mysock.sendall('test\n'.encode())
data = mysock.recv(1024)
print('received:',repr(data))
if __name__ == '__main__':
parent_conn, child_conn = mp.Pipe()
echo_demon = mp.Process(name='echo', target=echo_server(child_conn, ))
echo_demon.daemon = True
echo_demon.start()
time.sleep(1)
echo_demon.join(1)
test_echo_server()
if parent_conn.poll(1):
print(parent_conn.recv())
else:
print('Waiting for echo server')
I managed to solve my own question using some code snippets I found in the book "Getting started with Python" by Romano, Baka, and Phillips. here is the code for the server:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen()
try:
while True:
print("Waiting for connection...")
client, addr = s.accept()
with client:
data = client.recv(1024)
if not data:
break
elif (data == b'*IDN?\n'):
client.sendall(b'SONY/TEK,AWG520,0,SCPI:95.0 OS:3.0 USR:4.0\n')
else:
client.sendall(data)
finally:
time.sleep(1)
print('Exiting echo server:')
and here is the code for the testing file which runs this server in a separate process, and a couple of simple tests:
#pytest.fixture(scope="session")
def awgserver():
print("loading server")
p = subprocess.Popen(["python3", "server.py"])
time.sleep(1)
yield p
p.terminate()
#pytest.fixture
def clientsocket(request):
print("entering client part")
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as mysock:
mysock.connect((HOST, PORT))
yield mysock
mysock.close()
#pytest.mark.run_this
def test_echo(awgserver, clientsocket):
clientsocket.send(b"*IDN?\n")
#assert clientsocket.recv(1024) == b"SONY/TEK,AWG520,0,SCPI:95.0 OS:3.0 USR:4.0\n"
assert clientsocket.recv(10) == b"TEK" # deliberately make test fail
#pytest.mark.run_this
def test_echo2(awgserver, clientsocket):
clientsocket.send(b"def")
assert clientsocket.recv(3) == b"def"
Set HOST to loopback IP, and PORT to > 1024

Python ConnectionRefusedError: [WinError 10061]

I am new at python and I want to make a server-client application but every time I am attempting a connection I see this error.
I have tried changing sequency of send() and receive() functions but that didn't worked out
msg = client_socket.recv (BUFSIZ) .decode ("utf8")
OSError: [WinError 10038] An attempt was made to perform an operation on an object that is not a socket
Here is the code
Client.py
"""Handles receiving of messages."""
#client_socket.bind((HOST, PORT))
#client_socket.connect((HOST, PORT))
msg = client_socket.recv(BUFSIZ).decode("utf8")
print(msg)
client_socket.close()
def send(event=None): # event is passed by binders.
"""Handles sending of messages."""
client_socket.connect((HOST, PORT))
msg = input("MSG: ")
client_socket.send(bytes(msg, "utf8"))
client_socket.close()
#----Now comes the sockets part----
HOST = '127.0.0.1'
PORT = 7557
if not PORT:
PORT = 33000
else:
PORT = int(PORT)
BUFSIZ = 1024
ADDR = (HOST, PORT)
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(ADDR)
receive_thread = Thread(target=receive)
receive_thread.start()
if __name__ == '__main__':
client_socket.close()
receive()
send()
receive()
Ps: 99% of code is from internet
Don't close your socket after receiving and sending information.
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
def receive() :
"""Handles receiving of messages."""
while True :
msg = client_socket.recv(BUFSIZ).decode("utf8")
print(msg)
def send():
"""Handles sending of messages."""
while True:
msg = input("MSG: ")
client_socket.send(bytes(msg, "utf8"))
#----Now comes the sockets part----
HOST = '127.0.0.1'
PORT = 7557
BUFSIZ = 1024
ADDR = (HOST, PORT)
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(ADDR)
receive_thread = Thread(target=receive, args=() )
send_thread = Thread(target=send, args=())
if __name__ == '__main__':
receive_thread.start()
send_thread.start()
This is a modified version of your code.
I made a similar application by myself using the same logic, take a look:
https://github.com/moe-assal/Chatting_Server

Locking another computer using sockets without interrupting the connection

I am trying to set up a server that can send each client - commands.
One command is 'lock' which locks the screen of the client.
When a client gets the word "lock" it runs this code on the client:
import ctypes
ctypes.windll.user32.LockWorkStation()
This code does lock the screen however- it ends my connection with the client..
How can I make the client stay connected but still locked?
Note: The locking is not forever! it is only once, like putting the client's computer in sleep mode until he wants to unlock the screen.
Hope I was clear enough. Thanks for helping!
Server:
import socket
def main():
sock = socket.socket()
sock.bind(('0.0.0.0', 4582))
print("Waiting for connections...")
sock.listen(1)
conn, addr = sock.accept()
print ("New connection from: ", addr)
while 1:
command = input("Enter command> ")
if command == 'shutdown':
sock.send(b'shutdown')
elif command == 'lock':
sock.send(b'lock')
else:
print ("Unknown command")
data = sock.recv(1024)
print (data)
if __name__ == '__main__':
main()
Client:
import socket
import ctypes
def main():
sock = socket.socket()
sock.connect(('127.0.0.1', 4582))
while 1:
data = sock.recv(1024)
print (data)
if data == 'lock':
sock.send(b'locking')
ctypes.windll.user32.LockWorkStation()
sock.recv(1024)
if __name__ == '__main__':
main()
I adapted the example from the Python docs to your needs.
Example for server.py:
import socket
HOST = '127.0.0.1'
PORT = 4582
with socket.socket() as s:
print('Waiting for connection...')
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = input('Which command? ')
if data in ['lock', 'shutdown']:
conn.send(data.encode())
else:
print('Command unknown')
Example for client.py:
import ctypes
import socket
HOST = '127.0.0.1'
PORT = 4582
with socket.socket() as s:
s.connect((HOST, PORT))
while True:
data = s.recv(1024).decode()
if not data:
print('Server disconnected')
break
print('Received command:', data)
if data == 'shutdown':
print('Shutting down client...')
break
if data == 'lock':
print('Locking...')
ctypes.windll.user32.LockWorkStation()

Socket Python Exchange

I am trying to build a TCP Chat Program that is multithreaded. So far I think most of the functions are setup fine. When starting the server and connecting with a client only responses sent from the server are broadcasted to all clients connected. I think I figured out why that is and it comes from the CONNECTION_LIST array I have. The server appends all clients to this list and I thought I had the same thing going for the clients but the client instance never sees this list so when sending messages they messages aren't sent anywhere. I basically need a way to copy the CONNECTION_list from the server instance over to the connected clients. I been trying figure out how to possibly do this all day and its driving me crazy.
import socket
import platform
import threading
import sys
import time
import os
'''Define Globals'''
HOST = ""
PORT = 25000
ADDR = (HOST, PORT)
CONNECTION_LIST = []
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
'''Connect Client to the Server'''
def client_connect():
server_ip = input("[+] Server's IP to connect to: ")
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client.connect((server_ip, PORT))
print("[+] Connected to Server at address: %s" %client.getpeername()[0])
except ConnectionRefusedError:
print("[*] No Server Listening at Specified Address")
sys.exit()
communicate(client)
'''Threaded loop to continue listening for new connections'''
def server_loop():
server.bind(ADDR)
server.listen(10)
print("[*] Server started on %s" %platform.node())
while True:
client_socket, client_addr = server.accept()
CONNECTION_LIST.append(client_socket)
print("\r[+] New Connection from: %s" %client_addr[0])
'''Broadcast data to all clients except sender'''
def broadcast_data(sock, message):
for socket in CONNECTION_LIST:
if socket != server and socket != sock:
try:
socket.send(str.encode("[%s] => %s" %(os.getlogin(),message)))
except:
socket.close()
CONNECTION_LIST.remove(socket)
'''Server Host Connect Back'''
def self_connect():
sc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sc.connect(("localhost", 25000))
CONNECTION_LIST.append(sc)
communicate(sc)
def communicate(client):
dump_thread = threading.Thread(target=dump, args=(client,))
dump_thread.start()
while True:
try:
time.sleep(0.5)
data = input("> ")
broadcast_data(client, data)
except:
print("[*] Error - Program Terminating")
client.close()
sys.exit()
def dump(client):
while True:
print(client.recv(1024).decode("utf-8"))
def main():
server_thread = threading.Thread(target=server_loop)
while True:
try:
print("Select Operating Mode")
print("---------------------")
print("1. Server Mode")
print("2. Client Mode")
mode = int(input("Enter mode of operation: "))
print("\n\n")
if mode in [1,2]:
break
else:
raise ValueError
except ValueError:
print("Enter either (1) for Server or (2) for Client")
if mode == 1:
server_thread.start()
time.sleep(1)
self_connect()
elif mode == 2:
client_connect()
main()

Categories