Python Chat - Errno 9 - Bad File Descriptor

7

I am developing (for study only) a code for a python chat, and I came across an error during the client-server communication, I would like some guidance about it, since I can not identify a solution. Here is the code and the image of the error.

Server:

import threading # threads
from socket import * # sockets

clientes_conn = [] # Lista de conexões/clientes
clientes_name = [] # Lista dos nomes das conexões

class minhaThread (threading.Thread):
    def __init__(self, threadID, threadName, conn):
        threading.Thread.__init__(self)
        self.id = threadID
        self.name = threadName
        self.conn = conn
    def run(self):
        chat_geral(self.conn,self.name)

'''
param == 1 => Mensagem do sistema
param == 2 => Mensagem do cliente
'''
def enviar_mensagem(msg, name, param):
    if param == 1:
        for conn in clientes_conn:
            conn.send(msg)
        print msg 
    else:
        for conn in clientes_conn:
            conn.send("("+name+"): "+msg)
        print "("+name+"): "+msg 

def adicionar_cliente(conn, _id):
    while 1:
        message2 = conn.recv(1024)
        if message2 == "":
            continue
        if message2 in clientes_name:
            serverSocket.send("O nome informado está sendo usado por um cliente atualmente.\n")
            continue
        clientes_conn.append(conn)
        clientes_name.append(message2)
        success = "Cliente '"+str(message2)+"' conectado com sucesso!"
        enviar_mensagem(success, message2, 1)

        # Entra no terceiro while 1
        thread = minhaThread(_id, message2, conn).start()

        clientes_conn.remove(conn)
        clientes_name.remove(message2)
        conn.close()
        break

def chat_geral(conn, name):
    while 1:
        msg = conn.recv(1024)
        if msg == "Sair" or msg == "sair":
            sair = "Cliente "+name+" está saindo do chat."
            enviar_mensagem(sair, name, 1)
            break
        enviar_mensagem(msg, name, 2)

serverName = 'localhost'
serverPort = 8080
serverSocket = socket(AF_INET,SOCK_STREAM)
serverSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serverSocket.bind((serverName,serverPort))
serverSocket.listen(1)
print "Servidor TCP esperando conexoes na porta %d ..." % (serverPort)

id_padrao = 0
while 1:
    connectionSocket, address = serverSocket.accept()
    print "Cliente "+str(address[1])+" tentando se conectar..."
    adicionar_cliente(connectionSocket, id_padrao)
    id_padrao += 1
serverSocket.close()

Client:

from socket import * # sockets
import threading # threads

class minhaThread (threading.Thread):
    def __init__(self, threadName, conn):
        threading.Thread.__init__(self)
        self.name = threadName
        self.conn = conn
    def run(self):
        chat_geral(self.name,self.conn)

def conectar_chat(conn):
    while 1:
        msg = raw_input("Digite seu nome: ")
        conn.send(msg)
        message = conn.recv(1024)
        print message
        if message.find("conectado com sucesso") != -1:
            thread = minhaThread(msg,conn).start()
            break

def chat_geral(name,conn):
    while 1:
        msg = raw_input("Digite (mensagem/comando): ")
        conn.send(msg)
        msg2 = conn.recv(1024)
        if msg2 == "saindo do chat" and msg.find(name) != -1:
            print "Desconectando do server."
            break
        print msg2

serverName = 'localhost'
serverPort = 8080
clientSocket = socket(AF_INET,SOCK_STREAM)
clientSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
clientSocket.connect((serverName,serverPort))

conectar_chat(clientSocket)

clientSocket.close()

Error:

    
asked by anonymous 22.11.2016 / 17:58

1 answer

0

The problem is very simple. As soon as a client connects, you use the following method / function:

def adicionar_cliente(conn, _id):
    while 1:
        message2 = conn.recv(1024)
        if message2 == "":
            continue
        if message2 in clientes_name:
            serverSocket.send("O nome informado está sendo usado por um cliente atualmente.\n")
            continue
        clientes_conn.append(conn)
        clientes_name.append(message2)
        success = "Cliente '"+str(message2)+"' conectado com sucesso!"
        enviar_mensagem(success, message2, 1)

        # Entra no terceiro while 1
        thread = minhaThread(_id, message2, conn).start()

        clientes_conn.remove(conn)
        clientes_name.remove(message2)
        conn.close()
        break

The problem is that shortly after you create the thread ( thread = minhaThread(_id, message2, conn).start() ), you close the connection ( conn.close() ). So the thread tries to work with an already closed socket - which makes communication impossible.

You'll need to reshape your code, so the thread terminates the connection, simple like this:)

Probably correct code (since I did not go around, I will not give guarantees):

import threading # threads
from socket import * # sockets

clientes_conn = [] # Lista de conexões/clientes
clientes_name = [] # Lista dos nomes das conexões

class minhaThread (threading.Thread):
    def __init__(self, threadID, threadName, conn):
        threading.Thread.__init__(self)
        self.id = threadID
        self.name = threadName
        self.conn = conn
    def run(self):
        chat_geral(self.conn,self.name)

'''
param == 1 => Mensagem do sistema
param == 2 => Mensagem do cliente
'''
def enviar_mensagem(msg, name, param):
    if param == 1:
        for conn in clientes_conn:
            conn.send(msg)
        print msg 
    else:
        for conn in clientes_conn:
            conn.send("("+name+"): "+msg)
        print "("+name+"): "+msg 

def adicionar_cliente(conn, _id):
    while 1:
        message2 = conn.recv(1024)
        if message2 == "":
            continue
        if message2 in clientes_name:
            serverSocket.send("O nome informado está sendo usado por um cliente atualmente.\n")
            continue
        clientes_conn.append(conn)
        clientes_name.append(message2)
        success = "Cliente '"+str(message2)+"' conectado com sucesso!"
        enviar_mensagem(success, message2, 1)

        # Entra no terceiro while 1
        thread = minhaThread(_id, message2, conn).start()
        break

def chat_geral(conn, name):
    while 1:
        msg = conn.recv(1024)
        if msg == "Sair" or msg == "sair":
            sair = "Cliente "+name+" está saindo do chat."
            enviar_mensagem(sair, name, 1)
            break
        enviar_mensagem(msg, name, 2)

    # O cliente desconectou
    clientes_conn.remove(conn)
    clientes_name.remove(message2)
    conn.close()

serverName = 'localhost'
serverPort = 8080
serverSocket = socket(AF_INET,SOCK_STREAM)
serverSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serverSocket.bind((serverName,serverPort))
serverSocket.listen(1)
print "Servidor TCP esperando conexoes na porta %d ..." % (serverPort)

id_padrao = 0
while 1:
    connectionSocket, address = serverSocket.accept()
    print "Cliente "+str(address[1])+" tentando se conectar..."
    adicionar_cliente(connectionSocket, id_padrao)
    id_padrao += 1
serverSocket.close()

One problem I see right now is the access in the variables "clients_conn" and "clients_name", which must be modified, since simultaneous access errors can occur across multiple threads (at the time clients disconnect at the same time ).

Hugs

    
06.03.2017 / 16:18