bigl
bigl

Reputation: 177

multiple clients cannot listen and write at the same time

I'm writing a very basic chat room in python. Clients connect and any message from a client is relayed to all clients. The problem I'm having is getting the client to listen and send messages at the same time. It seems to only do either one. I've set up a separate listening client and confirmed that the message is received but the listening server cannot send anything.

Currently the client has to send data before getting a response from the server, but I want clients to be able to receive data before sending - otherwise the chat room won't work. I attempted using clientsock.settimeout() and then use recv but it did not solve the issue as it did not move past the input part.

server.py

#!/usr/bin/python

#socket server using threads

import socket, sys, threading
from _thread import *

HOST = 'localhost'
PORT = 2222

lock = threading.Lock()
all_clients = []

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print ("Socket created")

#bind socket to local host and port
try:
    s.bind((HOST, PORT))
except socket.error as msg:
    print ("Bind failed. Error code: " + str(msg[0]) + ' Message ' + msg[1])
    sys.exit(0)

print ("Socket bind complete")

#Start listening on socket
s.listen(5)
print ("Socket now listening")

#function for handling connections. This will be used to create threads
def clientthread(conn):
    #sending message to connected client
    conn.send("Welcome to the server. Type something and hit enter\n".encode('utf-8'))

    #infinite loop so that function does not terminate and thread does not end
    while True:
        #receiving data from client
        data = conn.recv(1024)
        reply = "OK..." + str(data, "utf-8")
        if not data:
            break
        with lock:
            for c in all_clients:
                c.sendall(reply.encode('utf-8'))

    #came out of loop
    conn.close()

#keep talking with the client
while 1:
    #wait to accept a connection - blocking call
    conn, addr = s.accept()
    with lock:
        all_clients.append(conn)
    print ("Connected with " + addr[0] + ":" + str(addr[1]))

    #start new thread takes 1st argument as a function name to be run, second
    #is the tuple of arguments to the function
    start_new_thread(clientthread ,(conn,))

s.close()

client.py

#!/usr/bin/python

import socket, sys

#client to transfer data

def main():
    #create tcp stocket
    clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #connect the socket to the server open port
    server_address = ('localhost', 2222)
    print ("connecting to %s port %s" % server_address)
    clientsock.connect(server_address)

    #receive data
    data = clientsock.recv(1024)
    print(str(data, "utf-8"))
    while 1:
        #send data
        message = "sean: " + input()
        clientsock.send(message.encode('utf-8'))

        #look for the response
        amount_received = 0
        amount_expected = len(message)

        while amount_received < amount_expected:
            data = clientsock.recv(1024)
            amount_received += len(data)
            print ("received %s " % data)

    print ("closing socket")
    clientsock.close()
main()

new_client.py

#!/usr/bin/python

import socket, sys
from threading import Thread

#client for chat room

def send_msg(sock):
    while True:
        data = input()
        sock.send(data.encode('utf-8'))

def recv_msg(sock):
    while True:
        stuff = sock.recv(1024)
        sock.send(stuff)

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 2222)
sock.connect(server_address)
print("Connected to chat")
Thread(target=send_msg, args=(sock,)).start()
Thread(target=recv_msg, args=(sock,)).start()

Upvotes: 2

Views: 4623

Answers (1)

laike9m
laike9m

Reputation: 19368

Create two threads, one for receiving the other for sending. This is the simplest way to do.

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect("address")

def send_msg(sock):
    while True:
        data = sys.stdin.readline()
        sock.send(data)

def recv_msg(sock):
    while True:
        data, addr = sock.recv(1024)
        sys.stdout.write(data)

Thread(target=send_msg, args=(sock,)).start()  
Thread(target=recv_msg, args=(sock,)).start()

Upvotes: 3

Related Questions