2

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()
bigl
  • 147
  • 1
  • 2
  • 7

1 Answers1

3

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()
laike9m
  • 18,344
  • 20
  • 107
  • 140
  • Hi, I've implemented this solution and I connect fine to the server but upon joining, the server sends a greeting. This greeting does not display but it is sent. I will edit the new client code. Can you advise? First time with threads :) – bigl Mar 05 '15 at 15:16
  • Did you get the greeting on client side? – laike9m Mar 05 '15 at 15:17
  • No greeting was received on the client side. – bigl Mar 05 '15 at 15:18
  • You mean `Welcome to the server. Type something and hit enter\n` is not received? – laike9m Mar 05 '15 at 15:23
  • nothing is received client side and i when I type a message on the client it is not sent back to the client(s) – bigl Mar 05 '15 at 15:25
  • @bigl You'd better show how `start_new_thread` is defined and make sure `conn.send("Welcome to the server. Type something and hit enter\n".encode('utf-8'))` is called. I'm going to sleep now, if you still have question I'll look at it then. – laike9m Mar 05 '15 at 15:34