Detect (non-blocking) key press while accepting client connections - python-3.x

I am fairly new at programming in python. I am trying to code some form of simulation using sockets. I am able connect multiple clients to the server successfully. However I would like the server to accept client connections while waiting for some input (say enter key or a string input from the console/terminal). If the user presses the enter key or enters that string, then the server should stop accepting client connections and send the list of connected clients to all clients. I know how to code the rest of the part but I dont know where to detect this key press while accepting connections. This is what I have so far. I have tried looking for similar approaches taken, but I have not found something that fits my needs.
Server File:
import socket, sys, traceback, json, pygame, curses, time
from threading import Thread
clientList = {}
def initialize():
serverConnect()
def serverConnect():
local_hostname = socket.gethostname()
host = socket.gethostbyname(local_hostname)
port = 6666
sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sockfd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
sockfd.bind((host, port))
except:
print("Bind failed. Error : " + str(sys.exc_info()))
sys.exit()
sockfd.listen(3)
cid = 0
# infinite loop - do not reset for every requests
while True:
print("Awaiting client connection...")
clientSocket, address = sockfd.accept()
cid += 1
add_client_to_list(cid, address)
ip = str(address[0])
port = str(address[1])
print("Connected with " + ip + ":" + port)
try:
Thread(target=client_thread, args=(clientSocket, ip, port, cid, address)).start()
except:
print("Thread did not start.")
traceback.print_exc()
sockfd.close()
def client_thread(clientSocket, ip, port, cid, address, BUFSIZE = 5120):
clientAddress = address
clientID = cid
print("Sending client ID " + str(clientID) + " to " + ip + ":" + port)
clientSocket.sendall(str(clientID).encode("utf-8"))
threadActive = True
while threadActive:
recdData = receive_input(clientSocket, BUFSIZE)
if "--QUIT--" in recdData:
print("Client is requesting to quit")
clientSocket.close()
print("Connection " + ip + ":" + port + " closed")
threadActive = False
else:
print("\nReceived: {}".format(recdData) + " from %d" %clientID)
clientSocket.sendall("-".encode("utf8"))
def receive_input(clientSocket, BUFSIZE):
recdData = clientSocket.recv(BUFSIZE)
recdDataSize = sys.getsizeof(recdData)
if recdDataSize > BUFSIZE:
print("The input size is greater than expected {}".format(recdDataSize))
decodedData = recdData.decode("utf8").rstrip() # decode and strip end of line
result = process_input(decodedData)
return result
def process_input(input_str):
return str(input_str).upper()
def add_client_to_list(client_ID, client_address):
clientList[client_ID] = client_address
print(clientList)
def send_client_list(clientSocket, clientList):
jsonList = json.dumps(clientList)
clientSocket.sendall(str(jsonList).encode("utf-8"))
def keyPress(stdscr):
"""checking for keypress"""
stdscr.nodelay(True) # do not wait for input when calling getch
return stdscr.getch()
if __name__ == "__main__":
initialize()
Client File:
import socket
import sys
import json
def initialize():
sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 6666
try:
sockfd.connect((host, port))
except:
print("Connection error")
sys.exit()
# Receiving server assigned client ID
try:
myID = sockfd.recv(1024).decode("utf-8")
print("Received ID: " + myID + " from server.")
except:
print("Could not receive my ID from server")
sys.exit()
print("Enter 'quit' to exit and 'list' to receive client List")
message = input(" -> ")
while True:
if message == "list":
print("Receiving clientList from server...")
try:
jsonList = sockfd.recv(8192).decode("utf-8")
clientList = json.loads(jsonList)
print("Received list: %s" % clientList)
except:
print("Could not receive list from server")
sys.exit()
elif message != 'quit':
sockfd.sendall(message.encode("utf8"))
if sockfd.recv(5120).decode("utf8") == "-":
pass
message = input(" -> ")
else:
sockfd.send(b'--quit--')
break;
if __name__ == "__main__":
initialize()
This is what I have found. It is a small script which detects if the user inputs {a} on the console. And if he does, then a message is printed. Else it keeps listening for key presses.
import curses, time
def keyPress(stdscr):
# checking for keypress
stdscr.nodelay(True) # do not wait for input when calling getch
return stdscr.getch()
while True:
if curses.wrapper(keyPress) == 97:
print("You pressed 'a'")
else:
pass
time.sleep(0.1)
It would be great if you could guide me how I can use this concept to detect key press on the server side and stop accepting client connections and call the function to send client list to all clients. Or if you have any other approaches or suggestions.

Related

Why isnt my python socket server receiving the messages?

so i am making a chatroom in python using sockets for practice. I have made the server code using threading so that i can have more clients. Ive also made the client code, and when i try to run two clients at once so that they message from one to another, they connect to server, but the server doesnt seem to be receiving the message sent from either of the clients.
SERVER CODE:
import select
from threading import *
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# takes the first argument from command prompt as IP address
IP_address = "127.0.0.1"
# takes second argument from command prompt as port number
Port = int("50204")
server.bind((IP_address, Port))
server.listen(1000)
list_of_clients = []
def clientthread(conn, addr):
# sends a message to the client whose user object is conn
conn.send("Welcome to this chatroom!")
while True:
try:
message = conn.recv(4096)
if message:
print("<" + addr[0] + "> " + message.decode("UTF-8"))
# Calls broadcast function to send message to all
message_to_send = "<" + addr[0] + "> " + message
broadcast(message_to_send.encode("UTF-8"), conn)
else:
remove(conn)
except:
continue
def broadcast(message, connection):
for clients in list_of_clients:
if clients != connection:
try:
clients.send(message)
except:
clients.close()
# if the link is broken, we remove the client
remove(clients)
def remove(connection):
if connection in list_of_clients:
list_of_clients.remove(connection)
while True:
conn, addr = server.accept()
list_of_clients.append(conn)
# prints the address of the user that just connected
print(addr[0] + " connected")
# creates and individual thread for every user
# that connects
Thread(target=clientthread, args=(conn, addr))
conn.close()
server.close()
CLIENT CODE:
import socket
import sys
import time
class client:
def __init__(self):
self.server_ip = "127.0.0.1"
self.port = 50204
self.s = self.connect()
def connect(self):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print("Failed to create socket.")
sys.exit()
print("Socket created")
try:
s.connect((self.server_ip, self.port))
except socket.error:
print("Failed to connect to ip " + self.server_ip)
print("Connected to: " + str(s.getsockname()))
return s
def SocketQuery(self, Sock, cmd):
try:
try:
# Send cmd string
Sock.send(cmd)
print("Sent!")
time.sleep(1)
except socket.error:
# Send failed
print("Send failed!")
sys.exit()
reply = Sock.recv(4096)
return reply
except ConnectionResetError:
print("Server is down!")
def SocketClose(self, Sock):
# close the socket
Sock.close()
time.sleep(.300)
if __name__ == "__main__":
c = client()
c.connect()
print("connected")
while True:
inp = input(">>> ")
if inp == ":q":
break
reply = c.SocketQuery(c.s, inp.encode("UTF-8"))
if reply:
print(reply.decode("UTF-8"))
c.SocketClose(c.s)
So as i have already mentioned, they do connect, but dont send/receive messages.
i have checked the value in conn.recv(), and it is the same, also everything gets encoded to UTF-8 before sent, and then decoded back. I cant seem to find any other problem except that im running them all on localhost.
If anyone knows the answer to this, please tell me.
cheers!

Application freezes after socket server starts listening for socket client connection python

Application hangs after starting up the server but the socket server was properly created. so whenever i execute a client the server response properly. Why does the application hangs? Here is the sample code
Start Button - Trigger Button
ui.button.clicked.connect(start_server) # Button to start the process
Server Socket, in here I created a thread for all the connected clients to the server then the server will broadcast it to clients
def start_server():
host = "192.168.8.241"
port = 1024
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print("Socket created")
try:
soc.bind((host, port))
except:
print("Bind failed. Error : " + str(sys.exc_info()))
sys.exit()
soc.listen(5)
print("Socket now listening")
while True:
connection, address = soc.accept()
ip, port = soc.getsockname()
print("Connected with " + str(ip) + ":" + str(port))
try:
Thread(target=client_thread, args=(connection, ip, port)).start()
except:
print("Thread did not start.")
traceback.print_exc()
Client Thread
def client_thread(connection, ip, port, max_buffer_size = 5120):
is_active = True
while is_active:
client_input = receive_input(connection, max_buffer_size)
if "--QUIT--" in client_input:
print("Client is requesting to quit")
connection.close()
print("Connection " + str(ip) + ":" + str(port) + " closed")
is_active = False
else:
print("Processed result: {}".format(client_input))
connection.sendall(client_input)
def receive_input(connection, max_buffer_size):
client_input = connection.recv(max_buffer_size)
client_input_size = sys.getsizeof(client_input)
if client_input_size > max_buffer_size:
print("The input size is greater than expected {}".format(client_input_size))
decoded_input = client_input.decode("utf8").rstrip() # decode and strip end of line
result = process_input(decoded_input)
return result
def process_input(input_str):
print("Processing the input received from client")
return "Hello " + str(input_str).upper()
Client
def main():
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "192.168.8.241"
port = 1024
print("client_soc", soc)
try:
soc.connect((host, port))
except:
print("Connection error")
sys.exit()
print("Enter 'quit' to exit")
message = input(" -> ")
while message != 'quit':
soc.sendall(message.encode("utf8"))
while True:
data = soc.recv(1024)
print("Received response:" + str(data))
message = input(" -> ")
soc.send(b'--quit--')

Is there a way to ping IP address of computer to show them online (or offline) in GUI whenever they are connected to my server?

I have a working client and server chat application developed in python. I intend to make it more dynamic by showing the computers that connected or disconnected to the server in a separate GUI. What is the way to proceed ?
it is a simple chat-app. User/client registers -> logs in -> enters the IP of the server pc ->chat widow pops up -> start chatting to another user connected to the same server
Tried import os and ping but it only pings the computer. I want the sever to auto-detect the computers as soon as they connect the server. Server is created using MySQL. Running on Windows requires pymysql.
SERVER CODE:
from threading import Thread
#import MySQLdb
import struct
import pickle
import pymysql
def accept_incoming_connections():
"""Sets up handling for incoming clients."""
while True:
global client
client, client_address = SERVER.accept()
print("%s:%s has connected." % client_address)
addresses[client] = client_address
Thread(target=choice).start()
def choice():
a = client.recv(BUFSIZ).decode("utf8")
if a =='1':
Thread(target=reg_client, args=(client,)).start()
else:
Thread(target=login, args=(client,)).start()
def handle_client(client,name): # Takes client socket as argument.
"""Handles a single client connection."""
#name = client.recv(BUFSIZ).decode("utf8")
welcome = 'Welcome %s! If you ever want to quit, type {quit} to exit.' % name
client.send(bytes(welcome, "utf8"))
msg = "%s has joined the chat!" % name
broadcast(bytes(msg, "utf8"))
clients[client] = name
while True:
msg = client.recv(BUFSIZ)
if msg != bytes("{quit}", "utf8"):
broadcast(msg, name+": ")
else:
client.send(bytes("{quit}", "utf8"))
client.close()
del clients[client]
broadcast(bytes("%s has left the chat." % name, "utf8"))
break
def reg_client(client):
while True:
a = client.recv(BUFSIZ)
break;
data_arr = pickle.loads(a)
print(data_arr)
#print(mobileno)
#print(password)
name=data_arr[0]
mobileno=data_arr[1]
password=data_arr[2]
db = pymysql.connect("localhost","root","root","ChatApp" )
cursor = db.cursor()
sql="insert into user(name,mobileno,password) values(%s,%s,%s)"
values=(name,mobileno,password)
cursor.execute(sql,values)
db.commit()
cursor.close()
db.close()
Thread(target=choice).start()
def login(client):
while True:
a = client.recv(BUFSIZ)
data_arr = pickle.loads(a)
print(data_arr)
break;
mobileno=data_arr[0]
password=data_arr[1]
print (mobileno)
print(password)
db = pymysql.connect("localhost","root","root","ChatApp" )
#sql='SELECT * FROM user1 WHERE mobileno = %s and password = %s',(mobileno,password)
sql='SELECT * FROM user WHERE mobileno = %s and password = %s'
values=(mobileno,password)
cursor = db.cursor()
cursor.execute(sql,values)
data = cursor.fetchall()
for row in data:
global name
name=row[0]
print("Name=",name)
if data != None:
client.send(bytes('1', "utf8"))
print("success")
Thread(target=handle_client, args=(client,name)).start()
else:
client.send(bytes('0', "utf8"))
cursor.close()
db.close()
Thread(target=choice).start()
def broadcast(msg, prefix=""): # prefix is for name identification.
"""Broadcasts a message to all the clients."""
for sock in clients:
sock.send(bytes(prefix, "utf8")+msg)
clients = {}
addresses = {}
HOST = ''
PORT = 33000
BUFSIZ = 1024
ADDR = (HOST, PORT)
SERVER = socket(AF_INET, SOCK_STREAM)
SERVER.bind(ADDR)
if __name__ == "__main__":
SERVER.listen(5)
print("Waiting for connection...")
ACCEPT_THREAD = Thread(target=accept_incoming_connections)
ACCEPT_THREAD.start()
ACCEPT_THREAD.join()
SERVER.close()

How can Python's socket (UDP) be used to connect different machines on different WiFi?

I've been trying to set up a game to play with my friends. We all live in different places and have different IP, WiFi etc. I started coding on my own computer using socket using SOCK_DGRAM. It worked fine when I ran the server and client code on my own computer, but when my friends tried to run the client code they couldn't send anything to my server. No error was thrown, what they sent just wasn't picked up by my server.
Here is the server code:
import socket
host = "192.168.88.191"
port = 2000
connections = Connections() # Where I store my friends' way of contacting the server
player_list = [] # A list of players to be used by my Players class
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((host, port))
s.setblocking(False)
print("Server started")
while True:
try:
data, addr = s.recvfrom(1024)
got_data = True
except OSError:
got_data = False
if got_data:
if not addr in connections.addresses:
connections.addresses.append(addr) # Store all new addresses
player_list.append(Players(len(player_list))) # Append to player list (don't worry about this part)
data = data.decode("utf-8")
print("Message from " + str(addr) + ": " + data)
player_list[int(addr[1] - 2001)].move(data, player_list) # Function for game logic
message = ""
for player in player_list:
message += str(player.number) + " " + str(player.x) + " " + str(player.y) + "," # Make the message that I want to send
message = message[:-1]
print("Sending: " + message)
for address in connections.addresses:
s.sendto(message.encode("utf-8"), address)
Here is the client code:
class Sock():
def __init__(self):
self.host = "192.168.88.191"
self.port = 2000
self.server = (self.host, 2000)
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
try:
print("Trying to connect on port " + str(self.port))
self.s.bind((self.host, self.port))
except OSError:
self.port += 1
else:
self.s.setblocking(False)
print("Connected on port " + str(self.port) + "!")
break
def send_data(self, message):
print("Sending: " + message)
self.s.sendto(message.encode("utf-8"), self.server)
def recieve_data(self):
try:
data, addr = self.s.recvfrom(1024)
data = data.decode("utf-8")
print("Recieved from server: " + data)
return data
except socket.error:
pass
My IP is 192.168.88.191. I would assume that my friends need to use their IP in the client code, but where? I know that you can find your IP by doing socket.gethostbyname(socket.gethostname())
EDIT: This client code didn't actually work, it tried every port until it reached the highest port possible and threw an error. We did some adjustments to the code and got it to connect, but the server still didn't recieve anything. The client could send just fine, but the server didn't recieve. I'm not 100% about the adjustment in question, but I think we replaced: self.server = (self.host, 2000) with: self.server = (socket.gethostbyname(socket.gethostname()), 2000) although as I said I don't know if that's exacly what we did.

Stop server from client's thread / Modify server's variable from client's thread

I would like to write an application that could stop the server based on client's input. The server is multi-threaded and I do not understand how can I do this.
Basically, I described my problem here: Modify server's variable from client's thread (threading, python).
However, this is the Python solution, not the general solution I could implement in Java, C, C++, etc.
I need to close other clients, when one of them guesses the number, but the server should be still alive, ready for the new game.
Can I ask for some advices, explanations?
I tried this (still do not know how to port it to C or Java), but it lets the clients send the numbers even if one of them just guesses it. It seems to me that kill_em_all does not do it's job, it does not close all the connections and does not disconnect the other clients as it should. How to improve this?
#!/usr/bin/env python
from random import randint
import socket, select
from time import gmtime, strftime
import threading
import sys
class Handler(threading.Thread):
def __init__(self, connection, randomnumber, server):
threading.Thread.__init__(self)
self.connection = connection
self.randomnumber = randomnumber
self.server = server
def run(self):
while True:
try:
data = self.connection.recv(1024)
if data:
print(data)
try:
num = int(data)
if self.server.guess(num) :
print 'someone guessed!'
self.server.kill_em_all()
break
else :
msg = "Try again!"
self.connection.sendall(msg.encode())
except ValueError as e:
msg = "%s" % e
self.connection.sendall(msg.encode())
else:
msg = "error"
self.connection.send(msg.encode())
except socket.error:
break
self.connection.close()
def send(self, msg):
self.connection.sendall(msg)
def close(self):
self.connection.close()
class Server:
randnum = randint(1,100)
def __init__(self, ip, port):
self.ip = ip
self.port = port
self.address = (self.ip, self.port)
self.server_socket = None
def guess(self, no):
if self.randnum == no:
self.randnum = randint(1, 100)
print("New number is ", self.randnum )
result = True
else:
result = False
return result
def kill_em_all(self):
for c in self.clients:
c.send("BYE!")
c.close()
def run(self):
try:
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.bind((self.ip, self.port))
self.server_socket.listen(10)
self.clients = []
print('Num is %s' % self.randnum)
while True:
connection, (ip, port) = self.server_socket.accept()
c = Handler(connection, self.randnum, self)
c.start()
self.clients.append(c)
except socket.error as e:
if self.server_socket:
self.server_socket.close()
sys.exit(1)
if __name__ == '__main__':
s = Server('127.0.0.1', 7777)
s.run()
Client code:
import socket
import sys
port = 7777
s = None
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
s.connect(('127.0.0.1', port))
except socket.error, (value, message):
if s:
s.close()
print "Could not open socket: " + message
sys.exit(1)
while True:
data = raw_input('> ')
s.sendall(data)
data = s.recv(1024)
if data:
if data == "BYE!":
break
else:
print "Server sent: %s " % data
s.close()
Log in. Using whatever protocol you have, send the server a message telliing it to shut down. In the server, terminate your app when you get the shutdown message. That's it. It's not a problem with any OS I have used - any thread of a process can terminate that process.

Resources