socket chat room - python 3.7 - python

This is a python chat room that I've been working on and it enables to you to chat to other people on the same network through python
Host:
import socket
import sys
import time
s = socket.socket()
host = socket.gethostname()
port = 8080
s.bind((host,port))
print("")
print("Sever adress is", host)
print("")
name = input(str("Please enter your username : "))
s.listen(1)
print("")
print("Waiting for any incoming connections ... ")
print("")
conn, addr = s.accept()
print("Recieved connection")
#connection done ###
s_name = conn.recv(1024)
s_name = s_name.decode()
print("")
print(s_name, "has connected to the chat room")
print("")
conn.send(name.encode())
## messaging loop ##
while 1:
message = input(str("Please enter enter your message : "))
print("")
conn.send(message.encode())
message = conn.recv(1024)
message = message.decode()
print("")
print(name,": ",message)
print("")
Client:
import socket
import sys
import time
print("Welcome to python chat ")
print("")
print("Initiallsing....")
time.sleep(1)
s = socket.socket()
print("")
host = input(str("Please enter server adress : "))
print("")
name = input(str("Please enter your name : "))
port = 8080
print("")
time.sleep(1)
s.connect((host,port))
print("Connected...")
## Conection done ##
s.send(name.encode())
s_name = s.recv(1024)
s_name = s_name.decode()
print("")
print( s_name, "has joined the chat room ")
while 1:
message = s.recv(1024)
message = message.decode()
print("")
print(name,": ",message)
print("")
message = input(str("Please enter your enter message : "))
print("")
s.send(message.encode())
I have 2 problems, the first problem is that it only allows one person to speak at a time, what I mean by this say that if you send a message first you won't be allowed to send another message until the other person has responded. The second problem is that this code only works for 2 users, I want it so it works for multiple users
Edit:
Also could some one acutually give a proper solution instead of telling me to start all over again please because it took me so long to figure out how to make this system in the place.
Thank you

You need to create two separate threads for sending and receiving. The way you have written the loop will not work for both way communication simultaneously. Because after sending a message the loop is waiting to receive something. [If you want to run the code over internet, replace localhost with the desired IP address in the line HOST = 'localhost'] Let me share a solution (this is a sample solution I have done while TAing an undergraduate class on networking):
I have tested the code on a Linux machine (Ubuntu 18.04). I have got students who have successfully ran this on their Mac. I am not sure if it runs on a windows machine. Even if it does not work on a Windows machine, a few minor modifications should do the trick.
Server sider code (you need to run this first): chatServerDuplex.py
# Import socket module
from socket import *
import threading
import sys # In order to terminate the program
FLAG = False # this is a flag variable for checking quit
# function for receiving message from client
def recv_from_client(conn):
global FLAG
try:
# Receives the request message from the client
while True:
if FLAG == True:
break
message = conn.recv(1024).decode()
# if 'q' is received from the client the server quits
if message == 'q':
conn.send('q'.encode())
print('Closing connection')
conn.close()
FLAG = True
break
print('Client: ' + message)
except:
conn.close()
# function for receiving message from client
def send_to_client(conn):
global FLAG
try:
while True:
if FLAG == True:
break
send_msg = input('')
# the server can provide 'q' as an input if it wish to quit
if send_msg == 'q':
conn.send('q'.encode())
print('Closing connection')
conn.close()
FLAG = True
break
conn.send(send_msg.encode())
except:
conn.close()
# this is main function
def main():
threads = []
global FLAG
# TODO (1) - define HOST name, this would be an IP address or 'localhost' (1 line)
HOST = 'localhost'
# TODO (2) - define PORT number (1 line) (Google, what should be a valid port number)
# make sure the ports are not used for any other application
serverPort = 6789
# Create a TCP server socket
#(AF_INET is used for IPv4 protocols)
#(SOCK_STREAM is used for TCP)
# TODO (3) - CREATE a socket for IPv4 TCP connection (1 line)
serverSocket = socket(AF_INET, SOCK_STREAM)
# Bind the socket to server address and server port
# TODO (4) - bind the socket for HOSR and serverPort (1 line)
serverSocket.bind((HOST, serverPort))
# Listen to at most 1 connection at a time
# TODO (5) - listen and wait for request from client (1 line)
serverSocket.listen(1)
# Server should be up and running and listening to the incoming connections
print('The chat server is ready to connect to a chat client')
# TODO (6) - accept any connection request from a client (1 line)
connectionSocket, addr = serverSocket.accept()
print('Sever is connected with a chat client\n')
t_rcv = threading.Thread(target=recv_from_client, args=(connectionSocket,))
t_send = threading.Thread(target=send_to_client, args=(connectionSocket,))
# call the function to receive message server
#recv_from_server(clientSocket)
threads.append(t_rcv)
threads.append(t_send)
t_rcv.start()
t_send.start()
t_rcv.join()
t_send.join()
# closing serverScoket before exiting
print('EXITING')
serverSocket.close()
#Terminate the program after sending the corresponding data
sys.exit()
# This is where the program starts
if __name__ == '__main__':
main()
Client side code: chatClientDuplex.py
from socket import *
import threading
import sys
FLAG = False # this is a flag variable for checking quit
# function for receiving message from client
def send_to_server(clsock):
global FLAG
while True:
if FLAG == True:
break
send_msg = input('')
clsock.sendall(send_msg.encode())
# function for receiving message from server
def recv_from_server(clsock):
global FLAG
while True:
data = clsock.recv(1024).decode()
if data == 'q':
print('Closing connection')
FLAG = True
break
print('Server: ' + data)
# this is main function
def main():
threads = []
# TODO (1) - define HOST name, this would be an IP address or 'localhost' (1 line)
HOST = 'localhost' # The server's hostname or IP address
# TODO (2) - define PORT number (1 line) (Google, what should be a valid port number)
PORT = 6789 # The port used by the server
# Create a TCP client socket
#(AF_INET is used for IPv4 protocols)
#(SOCK_STREAM is used for TCP)
# TODO (3) - CREATE a socket for IPv4 TCP connection (1 line)
clientSocket = socket(AF_INET, SOCK_STREAM)
# request to connect sent to server defined by HOST and PORT
# TODO (4) - request a connection to the server (1 line)
clientSocket.connect((HOST, PORT))
print('Client is connected to a chat sever!\n')
# call the function to send message to server
#send_to_server(clientSocket)
t_send = threading.Thread(target=send_to_server, args=(clientSocket,))
# call the function to receive message server
#recv_from_server(clientSocket)
t_rcv = threading.Thread(target=recv_from_server, args=(clientSocket,))
threads.append(t_send)
threads.append(t_rcv)
t_send.start()
t_rcv.start()
t_send.join()
t_rcv.join()
print('EXITING')
sys.exit()
# This is where the program starts
if __name__ == '__main__':
main()

Your first problem is likely due to the fact that python sockets are blocking by default.
What this means is that, for example, on the line message = s.recv(1024), your program will keep listening and won't move on to the rest of your script until it receives something.
If you want two people to be able to receive and send at the same time, you might want to look into non-blocking sockets and some asynchronous programming.
This how-to from the official documentation might help you: https://docs.python.org/2/howto/sockets.html#non-blocking-sockets

System123456 the problem is that you built a client-server system when the server listens and the client connects to it. Try looking at peer-to-peer systems instead where each node is an equal. For building a chat room you might review DHT nodes.

Related

Client that communicates with multiple servers concurrently

I am trying to learn multithreading programming with Python and specifically I am trying to build a programm that 1 Client sends data to multiple servers and get some messages back. In the first version of my programm I want my client to communicate back and forth with each server that I have spawned with each thread, till I type 'bye'. Now I have 2 issues with my implementation that I don't understand how to deal with. The first one is that I don't want the connection with the server to close after I type 'bye' (I want to add extra functionality after that) and the second one is that the servers doesn't get the messages that I type at the same type but I can communicate with the second server only if the first thread terminates (which as I said, I don't want to terminate). Any suggestions would be appreciated. Cheers!
Client.py
import sys
import threading
from _thread import *
import socket
host_1 = '127.0.0.1'
port_1 = 6000
host_2 = '127.0.0.2'
port_2 = 7000
def connect_to_server(host, port):
client_socket = socket.socket() # instantiate
client_socket.connect((host, port)) # connect to the server
message = input(" -> ") # take input
while message.lower().strip() != 'bye':
client_socket.send(message.encode()) # send message
data = client_socket.recv(1024).decode() # receive response
print('Received from server: ' + data) # show in terminal
message = input(" -> ") # again take input
threads_dict = {}
th_1 = threading.Thread(target=connect_to_server, args=(host_1, port_1))
th_2 = threading.Thread(target=connect_to_server, args=(host_2, port_2))
th_1.start()
th_2.start()
th_1.join()
th_2.join()
Server.py
import socket
import sys
def server_program():
host = sys.argv[1] # '127.0.0.1', '127.0.0.2'
port = int(sys.argv[2]) # 6000, 7000
server_socket = socket.socket() # get instance
server_socket.bind((host, port)) # bind host address and port together
# configure how many client the server can listen simultaneously
server_socket.listen(2)
conn, address = server_socket.accept() # accept new connection
print("Connection from: " + str(address))
while True:
# receive data stream. it won't accept data packet greater than 1024 bytes
data = conn.recv(1024).decode()
if not data:
# if data is not received break
break
print("from connected user: " + str(data))
data = input(' -> ')
conn.send(data.encode()) # send data to the client
if __name__ == '__main__':
server_program()

Converting Python Chat Application from using Socket to Websocket

I have been able to successfully create a chat application that works within a local network. I am wanting to deploy the server script to Heroku to enable connections from outside of the local network. Obviously I cannot use sockets on Heroku and will need to convert my code to utilize Websockets instead. I could re-write the entire script but wanting to see if there is a "path of least resistance" using the code I already have.
So the question: Is there a simple way to convert the Code I have to utilize websockets instead of sockets?
Server Side Code
import socket
from threading import Thread
# server's IP address
SERVER_HOST = "54.243.238.66"
SERVER_PORT = 5002 #port we want to use
separator_token = "<SEP>" # use this to separate the client name and message
#initialize list/set of all connected client's sockets
client_sockets = set()
#create a TCP socket
s = socket.socket()
#make the port reuseable
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#bind the socket to the address we spedified
s.bind((SERVER_HOST, SERVER_PORT))
#listen for upcoming connections
s.listen(5)
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
def listen_for_client(cs):
"""
This function keeps listening for a message from 'cs' socket
Whenever a message is received, broadcast it to all other connected clients
"""
while True:
try:
#keep listening for a message from 'cs' socket
msg = cs.recv(1024).decode()
except Exception as e:
#Client no longer connected
#remove client from the set
print(f"[!] Error: {e}")
client_sockets.remove(cs)
else:
#if we received a message, replace the <SEP> token with ": " for nice printing
msg = msg.replace(separator_token, ": ")
for client_socket in client_sockets:
client_socket.send(msg.encode())
while True:
client_socket, client_address = s.accept()
print(f"[+] {client_address} connected.")
client_sockets.add(client_socket)
t = Thread(target=listen_for_client, args=(client_socket,))
t.daemon = True
t.start()
for cs in client_sockets:
cs.close()
s.close()
Client Side Code
import sys
import subprocess
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'colorama'])
import socket
import random
from threading import Thread
from datetime import datetime
from colorama import Fore, init, Back
init()
colors = [Fore.BLUE, Fore.CYAN, Fore.GREEN, Fore.LIGHTBLACK_EX,
Fore.LIGHTBLUE_EX, Fore.LIGHTCYAN_EX, Fore.LIGHTGREEN_EX,
Fore.LIGHTMAGENTA_EX, Fore.LIGHTRED_EX, Fore.LIGHTWHITE_EX,
Fore.LIGHTYELLOW_EX, Fore.MAGENTA, Fore.RED, Fore.WHITE, Fore.YELLOW
]
client_color = random.choice(colors)
SERVER_HOST = "54.243.238.66"
SERVER_PORT = 5002
separator_token = "<SEP>"
s = socket.socket()
print(f"[*] Connecting to {SERVER_HOST}:{SERVER_PORT}...")
s.connect((SERVER_HOST, SERVER_PORT))
print("[+] Connected.")
name = input("Enter your name: ")
print("To exit, type 'q' at any time and press enter.")
def listen_for_messages():
while True:
message = s.recv(1024).decode()
print("\n" + message)
# make a thread that listens for messages to this client & print them
t = Thread(target=listen_for_messages)
# make the thread daemon so it ends whenever the main thread ends
t.daemon = True
# start the thread
t.start()
while True:
# input message we want to send to the server
to_send = input()
# a way to exit the program
if to_send.lower() == 'q':
break
# add the datetime, name & the color of the sender
date_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
to_send = f"{client_color}[{date_now}] {name}{separator_token}{to_send}{Fore.RESET}"
# finally, send the message
s.send(to_send.encode())
# close the socket
s.close()

Threading - How to recieve and reply at the same time using the socket module?

I am trying to make a simple LAN instant messager where many clients connect to the server and the server replies back and can see what the client is saying. I have tried but my lack of knowledge using the threading module has limited me. At the moment, however, the server only gets a message and has to reply to get the next one. I am trying to make it so the server can see all the messages it receives instantly and can reply whenever he need to. How?
Server Code:
from threading import *
import socket
s = socket.socket()
host = socket.gethostbyname(socket.gethostname())
port = 1337
s.bind((host, port))
s.listen(5)
def getMainThread():
for thread in enumerate(): # Imported from threading
if thread.name == 'MainThread':
return thread
if thread.name == 'Thread':
return thread
return None
class client(Thread):
def __init__(self, socket, address):
Thread.__init__(self)
self.socket = socket
self.address = address
self.start() # Initated the thread, this calls run()
def reply(self):
reply = getThread()
while reply and reply.isAlive():
sent = input("Enter Message: ")
self.socket.send(bytes(sent, 'UTF-8'))
def run(self):
main = getMainThread()
while main and main.isAlive():
message = self.socket.recv(8192).decode('utf-8')
self.socket.send(b"Got your message.. send another one!")
print('Someone:',message)
sent = input("Enter Message: ")
self.socket.send(bytes(sent, 'UTF-8'))
self.socket.close()
while True:
c, addr = s.accept()
client(c, addr)
Client Code:
import socket
host = socket.gethostbyname(socket.gethostname())
print("""
================================================================================
Welcome to Coder77's local internet message for avoiding surveillance by the NSA
================================================================================
The current soon to be encrypted server is {0}
""".format(host))
#host = input("Please select the IP you would like to communicate to: ")
print("Now connecting to {0}....".format(host))
sock = socket.socket()
try:
sock.connect((host, 1337))
while True:
message = input("Enter Message: ")
if message == 'quit':
break
sock.send(bytes(message, 'UTF-8'))
recieved = sock.recv(8192).decode('utf-8')
print('Server responded with:', recieved)
except socket.error:
print ("Host is unreachable")
sock.close()
Also, is it possible using Threading so that 2 while statements can run at the same time? If so, can someone give me an example?
Boosting this to try and get an answer. Anyone?

Python Messager LAN [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Trying to make a simple python messager, getting quite aconnection unreachable error. I am trying to make it peer2peer. Could anyone also suggest how to make it better, I was thinking of adding a loop of some sort to ask the user for the next message, not sure how to go about doing this however.
Server.py
import socket
s = socket.socket()
host = socket.gethostbyname(socket.gethostname())
port = 1337
s.bind((host, port))
s.listen(5)
while True:
c, addr = s.accept()
print ("Got connection from", addr)
c.send("Thank you for connecting to {0}".format(host).encode())
msg1 = input("Enter Message: ")
c.send(msg1.encode())
msg2 = input("Enter Message: ")
c.send(msg1.encode())
msg3 = input("Enter Message: ")
c.send(msg1.encode())
msg4 = input("Enter Message: ")
c.send(msg1.encode())
c.close()
Client.py
import socket
s = socket.socket()
host = ""
port = 1337
s.bind((host, port))
print("""
================================================================================
Welcome to Coder77's local internet message for avoiding surveillance by the NSA
================================================================================
The current soon to be encrypted server is {0}
""".format(host))
host = input("Please select the IP you would like to communicate to: ")
print("Now connecting to {0}....".format(host))
try:
s.connect((host, port))
s.listen(5)
while True:
c, addr = s.accept()
msg1 = input("Enter Message: ")
c.send(msg1.encode())
msg2 = input("Enter Message: ")
c.send(msg1.encode())
msg3 = input("Enter Message: ")
c.send(msg1.encode())
msg4 = input("Enter Message: ")
c.send(msg1.encode())
except socket.error:
print ("Host is unreachable")
input("Enter to lose")
s.close()
Thanks.
Simple server (reworked your code a bit):
from threading import *
import socket
s = socket.socket()
host = socket.gethostbyname(socket.gethostname())
port = 1337
s.bind((host, port))
s.listen(5)
def getMainThread():
for thread in enumerate(): # Imported from threading
if thread.name == 'MainThread':
return thread
return None
class client(Thread):
def __init__(self, socket, address):
Thread.__init__(self)
self.socket = socket
self.address = address
self.start() # Initated the thread, this calls run()
def run(self):
main = getMainThread()
while main and main.isAlive():
message = self.socket.recv(8192).decode('utf-8')
self.socket.send(b"Got your message.. send another one!")
self.socket.close()
while True:
c, addr = s.accept()
client(c, addr)
This server (altho yet basic) will handle multiple clients.
And here's a working client solution:
import socket
print("""
================================================================================
Welcome to Coder77's local internet message for avoiding surveillance by the NSA
================================================================================
The current soon to be encrypted server is {0}
""".format(host))
host = input("Please select the IP you would like to communicate to: ")
print("Now connecting to {0}....".format(host))
sock = socket.socket()
try:
sock.connect((host, 1337))
while True:
message = input("Enter Message: ")
if message == 'quit':
break
sock.send(bytes(message, 'UTF-8'))
recieved = sock.recv(8192).decode('utf-8')
print('Server responded with:', recieved)
except socket.error:
print ("Host is unreachable")
sock.close()
Short about the server.
The point of a server is to handle multiple clients, this one will thanks to some basic threads.
Each client that connects, gets accepted and then thrown into a thread (when you call client() it will initate it's own thread and the rest of the application will continue along side of that clients thread).
All client threads should die when the main thread dies, for instance if you throw a CTRL+C it shouold break but the error handling there needs more work, and you'll most likely end up with a "Socket already in use" because of lack of perfection in the cleanup department.
But you get the idea and you'll have to learn to do some work yourself :)
The client,
as long as you don't write "quit" it will first and for more connect to a server in the cleanest way possible, and will forever SEND+Recieve messages to and from the server, until (as mentioned) you write "quit". That will disconnect and end your program.
Now, All this does, is send a message to the server and it auto-replies.
Consider creating something such as:
clients = {}
...
clients[self.addr[0]] = self.socket
or even
clients['Torxed'] = self.socket
Enabling yo to do stuff like:
message = self.socket.recv(8192).decode('utf-8')
toWho = message.split(': ', 1)[0]
if toWho in clients:
clients[toWho].send(bytes(message, 'UTF-8'))
So that when a client writes 'Torxed: Hey whats up mate?' it will get redirected to that client socket. That's just a completely simple and plain idea to show you what you should or at least could do.
Things that might be confusing
I noticed you wrote s = ... and c = ... quite a lot.
And you had some double-socket thing going on in the client..?
Calling things for what they are is usually good practice.. for instance,
In the server you could call the socket server but never s.
Or you just keep it clean and simple and call it socket in both ends except in some rair occations where you might create multiple server-instance sockets for whatever reason (bridging servers and what not).
And remember, the easier and short the solution is.. The more probable it is that you'll remember why and how you solved it. Don't go overboard on solutions.
Your server for instance, had about the same number of lines of code as my solution had (mine is not perfect i know), but i managed to squeeze in threading and if i/you wnated to also a "friendslist"..
Take good use of loops, functions and stuff.. They'll save your life :)
Also note
That if you intend to use the socket as a client, you don't need to do s.bind(()) or s.listen(5), that's server-side properties.

How can I know the number of clients connected to the server and return the number of the connected clients to the user?

I want to know these for I am getting crazy with this:
How can I do these:
1-If the server terminates the clients should terminate also. Your server should allow the administrator to close all connections (i.e. the server must wait for the user to terminate the program preferably through a menu interface)
2-In order to know the number of clients connected you will need to identify each client uniquely – this can be accomplished by using the pid that is uniquely assigned for each client connection (store these in a global list). These connections can change dynamically (i.e. clients can disconnect and reconnect) so you must maintain this list on the server.
This is my server side code:
Thanks in advance
import _thread
import socket
import sys
from datetime import datetime
def serveclient(c):
global v, nclient, vlock, nclientlock
while(True):
k=(c.recv(1)).decode('utf-8')
if(k==''):
break
if(k=='D'):
today = str(datetime.now().strftime('%Y-%m-%d'))
c.send(today.encode('utf-8'))
if(k=='T'):
tme = str(datetime.now().strftime('%H:%M:%S'))
c.send(tme.encode('utf-8'))
if(k=='X'):
<<<< # Here I should put the number of clients connected and echo back the number like the above code
vlock.acquire()
v+=k
vlock.release()
#Echo back
c.send(v.encode('utf-8'))
c.close() #End connection
nclientlock.acquire()
nclient-=1
nclientlock.release()
#Main driver code
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = int(sys.argv[1])
listener.bind(('',port))
listener.listen(5)
#Initialize global data
v=''
vlock=_thread.allocate_lock()
nclient=10 #Max number of clients
nclientlock=_thread.allocate_lock()
#accept calls from clients
for i in range(nclient):
(client, ap) = listener.accept()
_thread.start_new_thread(serveclient, (client,))
listener.close()
while nclient >0:
pass #do nothing, just wait for client count to drop to zero
print('The final string is: ', v)
<<<<<<<<<<<<<<<<<<<<<<<<<This the Client Code>>>>>>>>>>>>>>>>>>>>>>>
#Client Program. Sends a single char at a time to the server until the client
#sends a '', this will terminate the client.
#
#usage: python server port
import socket
import sys
#create the socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = sys.argv[1] #Server info from cmd line
port = int(sys.argv[2]) #Port from cmd line
#Conncet to server
s.connect((host, port))
while(True):
#get letter
k = input('enter a letter: ')
s.send(k.encode('utf-8'))
if(k==''):
break
v=s.recv(1024) #receive upto 1024 bytes
print(v.decode('utf-8'))
s.close()
Just increment a count every time you accept a socket, and decrement it every time you close an accepted socket.

Categories

Resources