Search code examples
pythonsocketssendrecv

Send/Receive messages at the same time socket python


I have been working on a simple python socket chat room where the client and server can send messages to each other. The issue that I came across was that the server and client can only send one message at a time. I want it to work like any other chat room, where I could receive a message when I am sending a message, any help will help greatly

Server.py

import socket
import sys

s = socket.socket()
host = socket.gethostname()
print(" server will start on host : ", host)
port = 8080
s.bind((host,port))
name = input(str("Please enter your username: "))
print("")
print("Server is waiting for incoming connections")
print("")
s.listen(1)
conn, addr = s.accept()
print("Recieved connection")
print("")
s_name = conn.recv(1024)
s_name = s_name.decode()
print(s_name, "has joined the chat room")
conn.send(name.encode())

while 1:
    message = input(str("Please enter your message: "))
    conn.send(message.encode())
    print("Sent")
    print("")
    message = conn.recv(1024)
    message = message.decode()
    print(s_name, ":" ,message)
    print("")

Client.py

import socket
import sys

s = socket.socket()
host = input(str("Please enter the hostname of the server : "))
port = 8080
s.connect((host,port))
name = input(str("Please enter your username : "))
print(" Connected to chat server")

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(s_name, ":" ,message)
    print("")
    message = input(str("Please enter your message: "))
    message = message.encode()
    s.send(message)
    print("Sent")
    print("")

Solution

  • CaSper has given me the server code where multiple clients can connect to the server but the problem now is that the clients can not talk to each other …

    That's primarily because your client wants s_name = s.recv(1024), while CaSper's server doesn't send its name. Here's a variant of your client (expecting host and port as command arguments) which works with CaSper's server and also addresses your original issue (client can only send one message at a time) by using separate threads:

    import socket
    import sys
    
    s = socket.socket()
    s.connect((sys.argv[1], int(sys.argv[2])))
    name = input(str("Please enter your username : "))
    print(" Connected to chat server")
    s.send(name.encode())
    
    def receive_and_print():
        for message in iter(lambda: s.recv(1024).decode(), ''):
            print(":", message)
            print("")
    import threading
    background_thread = threading.Thread(target=receive_and_print)
    background_thread.daemon = True
    background_thread.start()
    
    while 1:
        s.send(input("Please enter your message: ").encode())
        print("Sent")
        print("")
    

    Note that CaSper's server has a series of deficiencies:

    1. Even now that your clients can send messages at any time, the server waits for a message from one by one client, i. e. when it waits for client A, client B can send a message, but the server receives and broadcasts it only after client A has sent something.
    2. It doesn't handle client disconnects.
    3. It goes into a busy loop when all clients disconnected.

    For a better server example, see the question Handle multiple requests with select.

    … could you possibly change my server so that it works …

    Here's a variant of your server which works with this client, also using separate threads for input and reception:

    import socket
    import sys
    
    s = socket.socket()
    host = socket.gethostname()
    print(" server will start on host : ", host)
    port = 8080
    s.bind((host,port))
    name = input(str("Please enter your username: "))
    print("")
    print("Server is waiting for incoming connections")
    print("")
    s.listen(1)
    conn, addr = s.accept()
    print("Recieved connection")
    print("")
    s_name = conn.recv(1024)
    s_name = s_name.decode()
    print(s_name, "has joined the chat room")
    
    def input_and_send():
        while 1:
            message = name+" : "+input(str("Please enter your message: "))
            conn.send(message.encode())
            print("Sent")
            print("")
    import threading
    background_thread = threading.Thread(target=input_and_send)
    background_thread.daemon = True
    background_thread.start()
    
    for message in iter(lambda: conn.recv(1024).decode(), ''):
        print(s_name, ":", message)
        print("")