Python Chatroom: Sending messages while receving messages - python

I have created two chatroom programs. The idea is that the server and client(s) can transfer messages between each other.
The current situation is that the server cannot receive messages whilst entering messages neither can client type messages whilst waiting for server to send.
I have been looking at threading to solve this problem but haven't got a clue to implement it.
Server code:
#Chatroom Server
import socket
import threading
host = socket.gethostname()
ip = socket.gethostbyname(host)
print('Host name:', host)
print('Host IP:' , ip)
port = 8080
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((ip,port))
name = input('Enter host name:')
s.listen(3)#Allows maximum 3 connections to server
conn,addr = s.accept()
print('Connection established with: ', addr[0])
client = (conn.recv(1024)).decode()
print(client + ' connected')
conn.send(name.encode())
while True:
msg = input('You:')
choice = False
while True:
choice = input('Do you want to enter another line? (Y/N)')
if choice.upper() == 'Y':
add_msg= input("You:")
msg = msg + '\n' +add_msg
else:
break
conn.send(msg.encode())
msg = conn.recv(1024)
msg = msg.decode()
print(client+':'+msg)
Client code:
#Chatroom Client
import socket
hip = 'xxx.xx.xx.xx' #hip = host ip
port = 8080
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((hip,port))
name = input('Enter username:')
s.send(name.encode())
hname = s.recv(1024)
hname = hname.decode()
while True:
smsg = (s.recv(1024).decode())
print(hname+':'+smsg)
msg = input('You:')
choice = False
while True:
choice = input('Do you want to enter another line? (Y/N)')
if choice.upper() == 'Y':
add_msg= input("You:")
msg = msg + '\n' +add_msg
else:
break
s.send(msg.encode())

Related

Echo server chat application having issues connecting

I'm a novice when it comes to networking, but for my distributed systems project I'm attempting to create a simple application that allows any computer on the same network with python to send messages to a server. I cannot get my computer and laptop to connect successfully, and I get a timeout error on the client side:
Here is my server code:
import socket
import select
HEADER_LENGTH = 10
IP = "127.0.0.1"
PORT = 1234
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((IP, PORT))
server_socket.listen()
sockets_list = [server_socket]
clients = {}
def receive_message(client_socket):
try:
message_header = client_socket.recv(HEADER_LENGTH)
if not len(message_header):
return False
message_length = int(message_header.decode("utf-8").strip())
return {"header": message_header, "data" : client_socket.recv(message_length)}
except:
return False
while True:
read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
for notified_socket in read_sockets:
if notified_socket == server_socket:
client_socket, client_address = server_socket.accept()
user = receive_message(client_socket)
if user is False:
continue
sockets_list.append(client_socket)
clients[client_socket] = user
print(f"Accepted new connection from {client_address[0]}:{client_address[1]} username:{user['data'].decode('utf-8')}")
else:
message = receive_message(notified_socket)
if message is False:
print(f"Closed connection from {clients[notified_socket]['data'].decode('utf-8')}")
sockets_list.remove(notified_socket)
del clients[notified_socket]
continue
user = clients[notified_socket]
print(f"Received message from {user['data'].decode('utf-8')}: {message['data'].decode('utf-8')}")
for client_socket in clients:
if client_socket != notified_socket:
client_socket.send(user['header'] + user['data'] + message['header'] + message['data'])
for notified_socket in exception_sockets:
sockets_list.remove(notified_socket)
del clients[notified_socket]
Here is my client code
import socket
import select
import errno
import sys
HEADER_LENGTH = 10
IP = "127.0.0.1"
PORT = 1234
my_username = input("Username: ")
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((IP, PORT))
client_socket.setblocking(False)
username = my_username.encode("utf-8")
username_header = f"{len(username):<{HEADER_LENGTH}}".encode("utf-8")
client_socket.send(username_header + username)
while True:
message = input(f"{my_username} > ")
if message:
message = message.encode("utf-8")
message_header = f"{len(message):<{HEADER_LENGTH}}".encode("utf-8")
client_socket.send(message_header + message)
try:
while True:
#receive things
username_header = client_socket.recv(HEADER_LENGTH)
if not len(username_header):
print("connection closed by the server")
sys.exit()
username_length = int(username_header.decode("utf-8").strip())
username = client_socket.recv(username_length).decode("utf-8")
message_header = client_socket.recv(HEADER_LENGTH)
message_length = int(message_header.decode("utf-8").strip())
message = client_socket.recv(message_length).decode("utf-8")
print(f"{username} > {message}")
except IOError as e:
if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
print('Reading error', str(e))
sys.exit()
continue
except Exception as e:
print('General error', str(e))
sys.exit()
On the same machine, it works as expected since I'm using the hostname for both the server and client, but obviously, it will not work on separate devices.
How may I change this code so that I can get my laptop to act as a client, and my computer to act as a server? I only need to connect to devices on the same network. Thank you for any answers.
I found the solution myself, I just had to set the 'IP' in client to that of the server local IP, and lastly run both in IDLE so I would get the prompt to bypass the firewall, as I was running cmd previously and was not getting the option to bypass.

Why am I getting a timeout error while trying to send TCP packets over the internet?

I wanted to demonstrate Asynchronous Non-Blocking threads through an EventLoop using a chatroom that I coded out in Python.
The chatroom is working fine when I simulate a server and clients on my desktop, but whenever I want to send packets over the internet to my friends who stay at a geographically distant location, I receive Timeout errors.
Obviously, I change the IP_ADDR accordingly while doing so. In fact, I have tried both IPv4 and IPv6. The firewall is off, and there are no anti-viruses installed.
I tried setting the timeout options as well, but the problem still exists.
Over a small geographical distance, the connection works.
I have also checked whether I am even able to send packets over the Internet at all to the target computer using the tracert command, and it seems like I can.
Server.py
import sys
import select
import msvcrt
import socket
IP_ADDR = socket.gethostbyname(socket.gethostname())
PORT = 5555
HEADER_SIZE = 10
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((IP_ADDR, PORT))
def add_header(username, msg):
username = f'{len(username) :< {HEADER_SIZE}}' + username
msg_len = len(msg)
msg = username + f'{msg_len :< {HEADER_SIZE}}' + msg
return msg.encode("utf-8")
sock_list = [server]
sock_dict = {server : 'Server'}
def broadcast_message(client, broadcast_msg):
try: #EAFP
client.send(broadcast_msg)
except:
username = sock_dict[client]
del sock_dict[client]
sock_list.remove(client)
broadcast_msg = add_header(sock_dict[server], f"{username} has left the group!!")
for clients in sock_list:
if clients is server:
print(f"{username} has left the group!!")
else:
broadcast_message(clients, broadcast_msg)
server.listen()
while True:
readers, _, err_sockets = select.select(sock_list, [], [], 1)
if(msvcrt.kbhit()):
msg = input("[:] >> ")
#msg = sys.stdin.readline()[:-1]
msg = add_header(sock_dict[server], msg)
for client in sock_list:
if client is server:
continue
else:
broadcast_message(client, msg)
for reader in readers:
if reader is server:
client_socc, client_addr = server.accept()
try:
client_username = client_socc.recv(1024).decode("utf-8")
if not len(client_username):
continue
else:
print(f"Connection accepted from {client_username[HEADER_SIZE : ].title()} : {client_addr[0]} : {client_addr[1]}")
sock_dict[client_socc] = client_username[HEADER_SIZE : ].title()
sock_list.append(client_socc)
broadcast_msg = add_header(sock_dict[server], f"{sock_dict[client_socc]} has joined the group!!")
for client in sock_list:
if client is server or client is client_socc:
continue
else:
broadcast_message(client, broadcast_msg)
except:
continue
else:
try:
client_msg = reader.recv(1024).decode("utf-8")
if not len(client_msg):
del sock_dict[reader]
sock_list.remove(reader)
else:
while len(client_msg):
broadcast_msg = add_header(sock_dict[reader], client_msg[HEADER_SIZE : HEADER_SIZE + int(client_msg[:HEADER_SIZE])])
print(f"{sock_dict[reader]} >> {client_msg[HEADER_SIZE : HEADER_SIZE + int(client_msg[:HEADER_SIZE])]}")
client_msg = client_msg[HEADER_SIZE + int(client_msg[:HEADER_SIZE]) : ]
for client in sock_list:
if client is server or client is reader:
continue
else:
broadcast_message(client, broadcast_msg)
except:
continue
Client.py
import sys
import select
import socket
import msvcrt
IP_ADDR = socket.gethostbyname(socket.gethostname())
PORT = 5555
HEADER_SIZE = 10
class Connection():
def __init__(self, default = (IP_ADDR, PORT)):
self.client_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(f"Trying to connect to {default[0]} : {default[1]}")
self.client_conn.connect(default)
print("Connection succesful!")
username = input("Enter your username : ")
username = f'{len(username) :< {HEADER_SIZE}}' + username
self.client_conn.send(username.encode("utf-8"))
def fileno(self):
return self.client_conn.fileno()
def on_read(self):
msg = self.client_conn.recv(1024).decode("utf-8")
self.decode_message(msg)
def decode_message(self, msg):
while len(msg):
username = msg[HEADER_SIZE : HEADER_SIZE + int(msg[: HEADER_SIZE])]
msg = msg[HEADER_SIZE + int(msg[: HEADER_SIZE]) : ]
user_msg = msg[HEADER_SIZE : HEADER_SIZE + int(msg[: HEADER_SIZE])]
msg = msg[HEADER_SIZE + int(msg[: HEADER_SIZE]) : ]
print(f"{username} >> {user_msg}")
class Input():
def __init__(self, client):
self.client = client.client_conn
def fileno(self):
return sys.stdin.fileno()
def on_read(self):
#msg = sys.stdin.readline()[:-1]
msg = input("[:] >> ")
msg_len = len(msg)
msg = f'{msg_len :< {HEADER_SIZE}}' + msg
self.client.send(msg.encode("utf-8"))
connection = Connection()
read_input = Input(connection)
while True:
readers, _, _ = select.select([connection], [], [], 1)
if(msvcrt.kbhit()):
readers.append(read_input)
for reader in readers:
reader.on_read()

Socket python can't send information to the server "client.send(name)"

I'm working on a game project with tkinter and Python 3.7 and i can't send the name of the player that i'm typing to the server.
Server
server = None
HOST_ADDR = "192.168.1.13"
HOST_PORT = 5555
client_name = ""
clients = []
clients_names = []
player_data = []
def start_server():
global server, HOST_ADDR, HOST_PORT # code is fine without this
btnStart.config(state=tk.DISABLED)
btnStop.config(state=tk.NORMAL)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("socket.AF_INET")
print("socket.SOCK_STREAM")
server.bind((HOST_ADDR, HOST_PORT))
server.listen(5) # server is listening for client connection
threading._start_new_thread(accept_clients, (server, " "))
lblHost["text"] = "Address: " + HOST_ADDR
lblPort["text"] = "Port: " + str(HOST_PORT)
def accept_clients(the_server, y):
while True:
if len(clients) < 2:
client, addr = the_server.accept()
clients.append(client)
# use a thread so as not to clog the gui thread
threading._start_new_thread(send_receive_client_message, (client, addr))
Client.py
client = None
HOST_ADDR = "192.168.1.13"
HOST_PORT = 5555
def connect():
global your_details
if len(ent_name.get()) < 1:
tk.messagebox.showerror(title="ERROR!!!", message="You MUST enter your first name <e.g. John>")
else:
your_details["name"] = ent_name.get()
connect_to_server(ent_name.get())
def connect_to_server(name):
global client, HOST_PORT, HOST_ADDR
try:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST_ADDR, HOST_PORT))
print('test') # OK, i can receive the print
client.send(name)
print('test') # can't receive the print
threading._start_new_thread(receive_message_from_server, (client, "m"))
top_welcome_frame.pack_forget()
top_frame.pack(side=tk.TOP)
window_main.title("Tic-Tac-Toe Client - " + name)
except Exception as e:
tk.messagebox.showerror(title="ERROR!!!", message="Cannot connect to host: " + HOST_ADDR + " on port: " + str(
HOST_PORT) + " Server may be Unavailable. Try again later")
Each time i enter a name, it doesn't send the name that i typed client.send(name) and it goes in the else.
If someone can help me with that.
Thank you for your help !

two different remote server communication using python

this is a server code that i am running on remote server.
serv.py
import time, socket, sys
print('Setup Server...')
time.sleep(1)
#Get the hostname, IP Address from socket and set Port
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host_name = socket.gethostname()
ip = socket.gethostbyname(host_name)
port = 1234
soc.bind((host_name, port))
print(host_name, '({})'.format(ip))
name = input('Enter name: ')
soc.listen(1) #Try to locate using socket
print('Waiting for incoming connections...')
connection, addr = soc.accept()
print("Received connection from ", addr[0], "(", addr[1], ")\n")
print('Connection Established. Connected From: {}, ({})'.format(addr[0], addr[0]))
#get a connection from client side
client_name = connection.recv(1024)
client_name = client_name.decode()
print(client_name + ' has connected.')
print('Press [bye] to leave the chat room')
connection.send(name.encode())
while True:
message = input('Me > ')
if message == 'bye':
message = 'Good Night...'
connection.send(message.encode())
print("\n")
break
connection.send(message.encode())
message = connection.recv(1024)
message = message.decode()
print(client_name, '>', message)
This is client code that i am running on local system.
clie.py
import time, socket, sys
print('Client Server...')
time.sleep(1)
#Get the hostname, IP Address from socket and set Port
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
shost = socket.gethostname()
ip = socket.gethostbyname(shost)
#get information to connect with the server
print(shost, '({})'.format(ip))
server_host = input('Enter server\'s IP address:')
name = input('Enter Client\'s name: ')
port = 1234
print('Trying to connect to the server: {}, ({})'.format(server_host, port))
time.sleep(1)
soc.connect((server_host, port))
print("Connected...\n")
soc.send(name.encode())
server_name = soc.recv(1024)
server_name = server_name.decode()
print('{} has joined...'.format(server_name))
print('Enter [bye] to exit.')
while True:
message = soc.recv(1024)
message = message.decode()
print(server_name, ">", message)
message = input(str("Me > "))
if message == "bye":
message = "Leaving the Chat room"
soc.send(message.encode())
print("\n")
break
soc.send(message.encode())
Now if the host server is different the connection is not established. but if the host is same then it's working properly and sending texts properly. i want run this code in different server how to do please help me anyone.
In the server script, you use :
host_name = socket.gethostname()
This will probably give you "127.0.0.1".
What you need is for the server to listen to "0.0.0.0" to accept connections from everywhere.
So this will probably do :
host_name = "0.0.0.0"

Real time output whilst running Python

I'm making a basic chatroom and I want the received messages to show up when I'm also typing a message. I've looked it up, but from what I can tell it only works with a GUI, and I would prefer not to write a GUI.
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
str_return = ("")
str_send = ("blep")
old = ("blep")
port = input("Enter Port ")
try:
s.connect(("localhost", int(port)))
print("Connecting")
while True:
str_send = input("Enter message: ")
if str_send == ("exit"):
break
s.send(bytes(str_send, 'utf-8'))
str_recv = s.recv(1024)
print(str_recv.decode('utf-8'))
s.close()
except:
print("setting up server")
s.bind(('localhost', int(port)))
s.listen(5)
connect, addr = s.accept()
connect.sendto(bytes(str_return, 'utf-8'), addr)
print("Connection Address:" + str(addr))
while True:
str_send = input("Enter message: ")
if str_send == ("exit"):
break
connect.sendto(bytes(str_send, 'utf-8'), addr)
str_recv, temp = connect.recvfrom(1024)
print(str_recv.decode('utf-8'))
print("bye")
How can I make this work?

Categories