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()
Related
I have written a simple server and client py using UDP. The base is working, however I want that every time a user (client) joins, he would receive a chatlog of everything that has been said.
This is my code until now:
Server:
import socket
import threading
import queue
import pickle
messages = queue.Queue()
clients = []
# AF_INET used for IPv4
# SOCK_DGRAM used for UDP protocol
ip = "localhost"
port = 5555
chatlog=[]
UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
# binding IP and port
UDPServerSocket.bind((ip, port))
def receive():
while True:
try:
message, addr = UDPServerSocket.recvfrom(1024)
messages.put((message, addr))
chatlog.append((message,addr))
except:
pass
def broadcast():
while True:
while not messages.empty():
message, addr = messages.get()
print(message.decode())
if addr not in clients:
clients.append(addr)
for client in clients:
try:
if message.decode().startswith("SIGNUP_TAG:"):
name = message.decode()[message.decode().index(":") + 1:]
UDPServerSocket.sendto(f"{name} joined!".encode(), client)
if len(chatlog)>0:
sending= pickle.dumps(chatlog)
UDPServerSocket.sendto(sending, client)
else:
pass
else:
UDPServerSocket.sendto(message, client)
except:
clients.remove(client)
t1 = threading.Thread(target=receive)
t2 = threading.Thread(target=broadcast)
t1.start()
t2.start()
And the client
import socket
import threading
import random
client= socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client.bind(("localhost", random.randint(7000, 8000))) # random port for every client
name = "Henk" #test name
def receive():
while True:
try:
message, _ = client.recvfrom(1024)
print(message.decode())
except:
pass
t= threading.Thread(target= receive)
t.start()
#this gives the server the name of the people who have entered the server
client.sendto(f"SIGNUP_TAG: {name}".encode(), ("localhost", 5555))
while True:
message= input("")
if message=="!q":
exit()
else:
client.sendto(f'[{name}]: {message}'.encode(), ("localhost",5555))
So I am actually a bit stuck on how I will approach this. Shall create a text file where every time that a message is written it gets written on the file as well? Or shall I create some kind of string list/database where every message is stored :/
i have made a broadcast server and client both and i have used a message as command like #private to work as a command and and that will list all users and then i want that it should select one of them and then it can only chat with those client only which he as selected and on the backend broadcast also work for others
server()
# import socket programming library
import socket
import time
# import thread module
from _thread import *
import threading
def chatwithtwo(c,username,numusr,data):
c.send("choose to which one you wanna chat".encode())
for i in range(len(username)):
select=f"{i}. {username[i]}\n"
c.send(select.encode())
#here the thread gives problem
select_username=c.recv(1024)
print("select:",select_username.decode())
try:
if username[int(select_username)] in username:
chat_two_display(numusr,c,clients[int(select_username)])
else:
c.send("wrong selection".encode())
except:
c.send("wrong input".encode())
lock.release()
def chat_two_display(numusr,c,recver):
sendcheck={}
while True:
data = c.recv(1024)
sendcheck[numusr]=c
for i in range(len(clients)):
if clients[i]==recver:
send_to=usernames[i]
print(f"[+] {numusr} --> {send_to}:- {data.decode()}")
chat_two_send(numusr,data.decode(),recver)
def chat_two_send(numusr,data,recver):
sendingtoall=f"[+] {numusr} (private):- {data}"
recver.send(sendingtoall.encode())
def send_data(numusr,senddata,clients,sendcheck):
lock.release()
for i in range(len(clients)):
if not clients[i]==sendcheck[numusr]:
sendingtoall=f"[+] {numusr}:- {senddata}"
clients[i].sendall(sendingtoall.encode())
def display_data(c,numusr):
global lock
lock=threading.Lock()
sendcheck={}
while True:
time.sleep(0.5)
data = c.recv(1024)
sendcheck[numusr]=c
print(f"[+] {numusr}:- {data.decode()}")
lock.acquire()
if data.decode()=="#private":
#thread.acquire()
chatwithtwo(c,usernames,numusr,data)
else:
send_data(numusr,data.decode(),clients,sendcheck)
# thread function
def threaded(clients,username):
for i in range(len(clients)):
threading.Thread(target=display_data,args=(clients[i],username[i])).start()
def username_check(c):
while True:
uname=c.recv(1024)
if uname.decode() not in usernames:
datatosend=f"your username is {uname.decode()}"
usernames.append(uname.decode())
clients.append(c)
c.sendall(datatosend.encode())
break
else:
c.send("[-] This username is alredy in use!!!".encode())
def Main():
host = "127.0.0.1"
# reserve a port on your computer
# in our case it is 12345 but it
# can be anything
port = 8000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
print("socket binded to port", port)
# put the socket into listening mode
s.listen(5)
print("socket is listening")
global clients
global usernames
global threads
clients=[]
usernames=[]
threads=[]
connectio(s)
def connectio(s):
while True:
# establish connection with client
c, addr = s.accept()
# lock acquired by client
print('Connected to :', addr[0], ':', addr[1])
username_check(c)
# Start a new thread and return its identifier
threaded(clients,usernames)
if __name__ == '__main__':
Main()
client()
import socket
import threading
import time
def send_data(s):
while True:
message=input("")
s.send(message.encode('ascii'))
time.sleep(0.5)
if message=="close":
s.close()
def display_data(s):
while True:
data = s.recv(1024)
print(str(data.decode('ascii')))
time.sleep(0.5)
def Main():
# local host IP '127.0.0.1'
host = '127.0.0.1'
# Define the port on which you want to connect
port = 8000
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# connect to server on local computer
s.connect((host,port))
while True:
username=input("enter your username which should be unique:-")
s.send(username.encode())
username_check=s.recv(1024)
print(username_check.decode())
if username_check:
if username_check.decode()!="Try again":
break
# message you send to server
threading.Thread(target=send_data,args=(s,)).start()
threading.Thread(target=display_data,args=(s,)).start()
# close the connection
if __name__ == '__main__':
Main()
i have called a function for it that is chatwithtwo() but the problem is when select_username variable is receiving the value other threads also work at the same time all that get messed up please help me out in that
Just remove your for i in range(len(clients)): this from threaded function and all done
it will run your thread every time a client will connect to the server like if one client is connected then it will run for 1 time threads=1 running then the second time will run then its value will be 2 and the loop will run twice and the thread value fill get added to the last one like now running thread is 1 and after loop 2 more will be added and now threads are 3 and so on.
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()
I am trying to create a simple chat program using Python and Socket. The server handles the connection between two clients. Whenever I run the program, for one of the clients, every message after the first one does not send. The message does not even reach the server.
This is on Windows, Python3. I've integrated threading so messages can be sent and received at the same time; however, the problem persists.
Server.py
conns = [] # list that stores both connections
def accept(sk):
while True:
conn, addr = sk.accept()
conns.append(conn)
print(addr, "has connected")
t = threading.Thread(target=accept, args=(sk,))
t.start() #start accept thread
def send(conn):
while True:
message = conn.recv(2048)
print(message)
for conn in conns:
conn.send(message) #sends message to every connection
print("Sent message")
t = threading.Thread(target=send, args=(conn,))
t.start() #start threading for send
Client.py
def recvMessages(s):
while True:
message = s.recv(2048)
print(message)
message = message.decode()
messages.append(message)
os.system("cls")
for message in messages:
print(message)
def sendMessage(s):
while True:
message = input()
message = message.encode()
s.send(message)
s = socket.socket()
host = socket.gethostname()
port = 8080
s.connect((host, port))
messages = []
print("Connected")
connected = True
threading.Thread(target=sendMessage, args=(s,)).start()
threading.Thread(target=recvMessages, args=(s,)).start()
All the messages should be sent from both clients, but one client can never send multiple messages, the other works fine.
Your server code is missing it's socket, and accept is not being run in your example, you also have invalid indentation as James pointed out, next time provide a minimal reproducible example.
I also cleaned up your files a bit, as you followed some bad practice, specifically with broadcasting the messages to all clients "def send" which actually receives, avoid confusing naming :)
in your server code you also sent only to one connection (which in your example doesn't exist) which it should be running the receive and send each time a new message is received
server.py
import socket
import threading
conns = [] # list that stores both connections
def accept(sk):
while True:
conn, addr = sk.accept()
conns.append(conn)
print(addr, "has connected")
# receive from new client
receive_t = threading.Thread(target=receive, args=(conn,))
receive_t.start() # start threading for send
def send(s, msg):
# change message ..
s.send(msg)
def broadcast(msg):
for conn in conns:
send(conn, msg)
def receive(conn):
try:
while True:
message = conn.recv(2048)
if not message: # detects if socket is dead, by testing message
print("client sent Nothing, removing")
conns.remove(conn)
break
broadcast(message) # send to all clients
except ConnectionResetError as e:
print('Could not send must be disconnected ')
conns.remove(conn) # remove dead socket
# added missing socket
sock = socket.socket()
sock.bind(('127.0.0.1', 8080))
sock.listen(1) # needs to bind and listen
t = threading.Thread(target=accept, args=(sock,))
t.start() # start accept thread
client.py
import os
import socket
import threading
messages = []
def recvMessages(s):
while True:
message = s.recv(2048)
message = message.decode()
print('new message= ', message)
messages.append(message)
os.system("cls")
for message in messages:
print(message)
def send_message(s):
while True:
message = input()
message = message.encode()
s.send(message)
s = socket.socket()
host = '127.0.0.1'
port = 8080
s.connect((host, port))
print("Connected")
connected = True
# added missing receive
receive = threading.Thread(target=recvMessages, args=(s,)) # missed receive thread in example
receive.start()
send_message(s)
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?