I wanted to create a server-client chatbox room in python, where multiple clients could send messages in the chat box.
This is the server code
import threading
import socket
#setting up the local host and the local port
host = '127.0.0.1'
port = 9879
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port)) #hosting the server to the host
server.listen() #server listen to incoming connection
#list for client and their nicknames
clients = []
nicknames = []
#broadcast method to send message to all the clients connected to the server
def broadcast(message):
for client in clients:
client.send(message)
def handle (client):
while True:
try:
message = client.recv(1024)
broadcast(message)
except: #if the connection is lost, discard the client
index = clients.index(client)
clients.remove(client)
client.close()
nickname = nicknames[index]
broadcast(f'{nickname} already left the chat!'.encode('ascii'))
nicknames.remove(nickname)
break
#function to receive connection
def receive():
while True:
client, address = server.accept()
print(f"Conncected with {str(address)}")
client.send('NICKNAME'.encode('ascii'))
nickname = client.recv(1024).decode('ascii')
nicknames.append(nickname)
clients.append(client)
print(f'The nickname of the client is {nickname}')
broadcast(f'{nickname} joined the chat!'.encode('ascii'))
client.send('Connected to the server!'.encode('ascii'))
#making thread for every client
thread = threading.Thread(target = handle, args = (client,))
thread.start()
print("Server is waiting for client...")
and this is the client code
import socket
import threading
#nickname prompt
nickname = input("Input your nickname: ")
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#binding the client to the port
client.connect(('127.0.0.1', 9879))
def receive():
while True:
try:
message = client.recv(1024).decode('ascii')
if message == 'NICKNAME':
client.send(nickname.encode('ascii'))
else:
print(message)
except:
print("An error occurred!")
client.close()
break
def write():
while True:
message = f'{nickname}: {input("")}'
client.send(message.encode('ascii'))
#making the thread
receive_thread = threading.Thread(target = receive)
receive_thread.start()
write_thread = threading.Thread(target = write)
write_thread.start()
However, whenever i inputted the nickname in the command prompt there was an error
Traceback (most recent call last):
File "C:\Users\march\Documents\Programming\Pyhton\client.py", line 8, in <module>
client.connect(('127.0.0.1', 9879))
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
I wonder what's the problem because the port for both server and client are the same and the port is available.
On your server code you're missing a call to the receive function that runs the while loop and puts the server on accept for connections.
The code becomes
import threading
import socket
#setting up the local host and the local port
host = '127.0.0.1'
port = 9879
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port)) #hosting the server to the host
server.listen() #server listen to incoming connection
#list for client and their nicknames
clients = []
nicknames = []
#broadcast method to send message to all the clients connected to the server
def broadcast(message):
for client in clients:
client.send(message)
def handle (client):
while True:
try:
message = client.recv(1024)
broadcast(message)
except: #if the connection is lost, discard the client
index = clients.index(client)
clients.remove(client)
client.close()
nickname = nicknames[index]
broadcast(f'{nickname} already left the chat!'.encode('ascii'))
nicknames.remove(nickname)
break
#function to receive connection
def receive():
while True:
client, address = server.accept()
print(f"Conncected with {str(address)}")
client.send('NICKNAME'.encode('ascii'))
nickname = client.recv(1024).decode('ascii')
nicknames.append(nickname)
clients.append(client)
print(f'The nickname of the client is {nickname}')
broadcast(f'{nickname} joined the chat!'.encode('ascii'))
client.send('Connected to the server!'.encode('ascii'))
#making thread for every client
thread = threading.Thread(target = handle, args = (client,))
thread.start()
print("Server is waiting for client...")
receive() # runs the function that accepts for incoming connections
The client code should run the write() function on the main thread and not on another one, because it requires input from the stdin. You can change your code as follows in order to run the receiving routine on another thread and your "writing" function on the main one.
import socket
import threading
#nickname prompt
nickname = input("Input your nickname: ")
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#binding the client to the port
client.connect(('127.0.0.1', 9879))
def receive():
while True:
try:
message = client.recv(1024).decode('ascii')
if message == 'NICKNAME':
client.send(nickname.encode('ascii'))
else:
print(message)
except:
print("An error occurred!")
client.close()
break
def write():
while True:
message = f'{nickname}: {input("")}'
client.send(message.encode('ascii'))
#making the thread
receive_thread = threading.Thread(target = receive)
receive_thread.start()
# on the main thread
write()
The cause of the Connection refused error was due to the fact that the server code immediately exited since the receive function was never actually called.
Related
I am using a tutorial that requires some server side code, but they don't show how to permanently run it. is there any way to do this, maybe with a web server? Here is the code:
import socket, threading
host = '127.0.0.1'
port = 7976
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen()
clients = []
nicknames = []
def broadcast(message):
for client in clients:
client.send(message)
def handle(client):
while True:
try:
message = client.recv(1024)
broadcast(message)
except:
index = clients.index(client)
clients.remove(client)
client.close()
nickname = nicknames[index]
broadcast('{} left!'.format(nickname).encode('ascii'))
nicknames.remove(nickname)
break
def receive():
while True:
client, address = server.accept()
print("Connected with {}".format(str(address)))
client.send('NICKNAME'.encode('ascii'))
nickname = client.recv(1024).decode('ascii')
nicknames.append(nickname)
clients.append(client)
print("Nickname is {}".format(nickname))
broadcast("{} joined!".format(nickname).encode('ascii'))
client.send('Connected to server!'.encode('ascii'))
thread = threading.Thread(target=handle, args=(client,))
thread.start()
receive()
I am currently developping a chat program, and I have a problem.
The server can only receive one information from the client and then stop receiving information.
here's my code :
Server.py
import socket
import threading
# Some base important value
ip = '0.0.0.0'
port = 25565
encoding = 'utf-8'
# Some runtime value
clientList = []
is_server_running = True
# a class representing a client
class ClientThread(threading.Thread):
conn = None
addr = None
# Use to init the thread and the main client value
def __init__(self, conn, addr):
threading.Thread.__init__(self)
self.conn = conn
self.addr = addr
print(f"Successfully created client thread for client {self.addr[0]}:{self.addr[1]}")
# Use to receive and send data
def run(self):
while True:
try:
data = self.conn.recv(1024).decode(encoding)
print(f"Got message from client ({self.addr[0]}:{self.addr[1]}) : \"{data}\"")
except Exception as e:
print(f"Got exception in client {self.addr[0]}:{self.addr[1]} : {str(e)}")
break
clientList.remove(self)
# Create a socket and bind the correct port and ip
print("Creating Server...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((ip, port))
s.listen(5)
print(f"Server created and launched on port {port}.")
while is_server_running:
try:
# Accept the connection and create a new client thread
conn, adrr = s.accept()
print(f"Got new connection from adress {adrr[0]}:{adrr[1]}. Creating Thread for client")
client_thread = ClientThread(conn, adrr)
client_thread.start()
clientList.append(client_thread)
except Exception as e:
print(f"Got Exception in server listening runtime : {str(e)}. Server Stopped")
is_server_running = False
break
for client in clientList:
client.conn.close()
s.close()
Client.py
import socket
# base important variables
encoding = 'utf-8'
adress = 'here is the server ip'
port = 25565
# runtime variables
is_client_running = True
# Create a socket and connects to the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((adress, port))
message = "Hello !".encode(encoding)
s.sendall(message)
while is_client_running:
message = input(">>> ")
s.sendall(message.encode(encoding))
Output :
Creating Server...
Server created and launched on port 25565.
Got new connection from adress -----------:----. Creating Thread for client
Successfully created client thread for client -----------:----
Got message from client (-----------:----) : "Hello !"
And then when I input something in the client console (like : Goodbye), the server receive nothing.
Thank you for your help !
So this code broadcasts to all the clients connected to it (including itself) but rather I want to broadcast to a specific client. How do I do that?
import socket, threading #Libraries import
host = '127.0.0.1' #LocalHost
port = 7978 #Choosing unreserved port
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #socket initialization
server.bind((host, port)) #binding host and port to socket
server.listen()
clients = []
nicknames = []
def broadcast(message): #broadcast function declaration
for client in clients:
print(client, type(client))
client.send(message)
def handle(client):
while True:
try: #recieving valid messages from client
message = client.recv(1024)
broadcast(message)
except: #removing clients
index = clients.index(client)
clients.remove(client)
client.close()
nickname = nicknames[index]
broadcast('{} left!'.format(nickname).encode('ascii'))
nicknames.remove(nickname)
break
def receive(): #accepting multiple clients
while True:
client, address = server.accept()
print("Connected with {}".format(str(address)))
client.send('NICKNAME'.encode('ascii'))
nickname = client.recv(1024).decode('ascii')
nicknames.append(nickname)
clients.append(client)
print("Nickname is {}".format(nickname))
broadcast("{} joined!".format(nickname).encode('ascii'))
client.send('Connected to server!'.encode('ascii'))
thread = threading.Thread(target=handle, args=(client,))
thread.start()
receive()
If a client sends message the server will broadcast the message to all clients including the client that sent the message. Is there a way to fix this issue?
Change broadcast function to the following:
import socket, threading #Libraries import
host = '127.0.0.1' #LocalHost
port = 7978 #Choosing unreserved port
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #socket initialization
server.bind((host, port)) #binding host and port to socket
server.listen()
clients = []
nicknames = []
def broadcast(message, clientt): #broadcast function declaration
for client in clients:
if client == clientt:
continue
else:
client.send(message)
# for client in clients:
# print(client, type(client))
# client.send(message)
def handle(client):
while True:
try: #recieving valid messages from client
message = client.recv(1024)
broadcast(message, client)
except: #removing clients
index = clients.index(client)
clients.remove(client)
client.close()
nickname = nicknames[index]
broadcast('{} left!'.format(nickname).encode('ascii'), client)
nicknames.remove(nickname)
break
def receive(): #accepting multiple clients
while True:
client, address = server.accept()
print("Connected with {}".format(str(address)))
client.send('NICKNAME'.encode('ascii'))
nickname = client.recv(1024).decode('ascii')
nicknames.append(nickname)
clients.append(client)
print("Nickname is {}".format(nickname))
broadcast("{} joined!".format(nickname).encode('ascii'), client)
client.send('Connected to server!'.encode('ascii'))
thread = threading.Thread(target=handle, args=(client,))
thread.start()
receive()
I'm trying to make a chat room that works on localhost with threading and socket. Here is the code:
# Server side
import threading
import socket
host = 'localhost'
port = 11298
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen()
clients = []
nicks = []
def broadcast(msg):
for client in clients:
client.send(msg)
def handle(client):
while True:
try:
msg = client.recv(1024)
broadcast(msg)
except:
index = clients.index(client)
clients.remove(client)
client.close()
nick = nicks[index]
broadcast(f'{nick} has left.'.encode('utf-8'))
nicks.remove(nick)
break
def recv():
while True:
print('The chat room is online ...')
client, address = server.accept()
print(f'You are connected to {str(address)}')
client.send('nick'.encode('utf-8'))
nick = client.recv(1024)
nicks.append(nick)
clients.append(client)
broadcast(f'{nick} has joined.'.encode('utf-8'))
client.send('You have been connected!'.encode('utf-8'))
thread = threading.Thread(target = handle(), args = (client))
thread.start()
if __name__ == "__main__":
recv()
# Client side
import threading
import socket
nick = input('Choose a nickname: ')
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('localhost', 11298))
def cl_recv():
while True:
try:
msg = client.recv(1024).decode('utf-8')
if msg == 'nick':
client.send(nick.encode('utf-8'))
else:
print(msg)
except:
print("Something went wrong! Bummer.")
client.close()
break
def cl_send():
while True:
msg = f'{nick}: {input("")}'
client.send(msg.encode('utf-8'))
receive_th = threading.Thread(target = cl_recv)
receive_th.start
Whenever I run the code (one cmd window for the server and two for the clients to test it out) it gives me this error:
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
I'm guessing it's a problem with the client closing the server, but I'm using client.connect. I've looked at the code multiple times and can't figure out how to fix it.
This can be caused by the two sides of the connection disagreeing over whether the connection timed out or not during a keepalive. (Your code tries to reused the connection just as the server is closing it because it has been idle for too long.) You should basically just retry the operation over a new connection.
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)