Python error in client-server communication with the use of threads

Question:

I’m trying to learn the use of sockets in python by writing a simple chat program with one server and multiple clients connected. Everything works relatively well when I only have one client connected, but if I connect a second client, the first one continues to receive messages, but can no longer send them.

This is the server:

from pickle import TRUE
import socket
import threaded
from threading import Thread
import _thread
import os
import time

hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
ip = str(local_ip)
port = 55555

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((ip, port))
server.listen()

global clients
clients = []

def recive(client):
    global clients
    name = client.recv(2024)
    name = name.decode("utf-8")
    while True:
        try:
            string = client.recv(2024)
            string = string.decode("utf-8")
            if string == "!exit":
                client.close()
                print("Connection interrupted")
                break
            else:
                for client in clients:
                    client.send(bytes(string, "utf-8"))
                    print(f"{name}: {string}")
        except:
            client.close()
            print("Connection interrupted")
            break

if __name__ == "__main__":
    hostname = socket.gethostname()
    local_ip = socket.gethostbyname(hostname)
    ip = str(local_ip)
    port = 55555

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((ip, port))
    server.listen()
    print(f"Server listening on {ip} on port {port}")
    while True:
        client, address = server.accept()
        print(f"Connectione estabished - {address[0]}:{address[1]}")
        clients.append(client)
        _thread.start_new_thread(recive ,(client,))

This is the client:

from email import message
import socket
from xml.etree.ElementTree import tostring
import threaded
from threading import Thread
import _thread
import os
import time

global string
global text
string = "string"
text = "text"

hostname = socket.gethostname()
local_ip = socket.gethostbyname(hostname)
ip = str(local_ip)
port = 55555

name = str(input("Insert your name: "))

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.connect((ip, port))

def recive(server):
    global string
    global text
    while True:
        text = server.recv(2024)
        text = text.decode('utf-8')
        if text == string:
            pass
        else:
            print(f"Broadcasted: {text}")

def send(server):
    global string
    global text
    server.send(bytes(name, "utf-8"))
    while True:
        string = str(input("Enter string: "))
        if string == "!exit":
            server.send(bytes(string, "utf-8"))
            server.close()
            break
        else:
            server.send(bytes(string, "utf-8"))

_thread.start_new_thread(recive ,(server,))
send(server)

If other information is needed, I will take care to modify the request and insert them.

Asked By: Marco Tomasi

||

Answers:

In the function def recive(client): ..., the variable client holds the socket for a communication with one specific client. But in this loop:

        for client in clients:
            client.send(bytes(string, "utf-8"))
            print(f"{name}: {string}")

the client variable gets overwritten and after the loop, the function communicates with a wrong socket, i.e. wrong client. Just use a separate variable:

        for c in clients:
            c.send(bytes(string, "utf-8"))

P.S. To prevent the Address already in use error when restarting the server, add immediately before the line server.bind(...):

server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Answered By: VPfB
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.