Chat Python - Errno 9 - Bad File Descriptor

Asked

Viewed 1,006 times

10

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

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:

inserir a descrição da imagem aqui

  • 1

    Ola Bruno, excellent first question. You would be kind enough to edit your question and paste the error in a textual way (screenshoots are always complicated).

  • I recently made a simple chat in python 3.5.2 , I now put it in git Hug: github.com/Miguel-Frazao/simple-chat-python3, see what you think. It can greatly reduce the server-side code by deleting the prints it does, in fact it is not necessary, it is more to track what is going on

  • As mentioned in a comment, the textual form error would be better to analyze, but see if that answer does not apply to your case.

1 answer

1

The problem is quite simple. Once 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 right after you create the thread (thread = minhaThread(_id, message2, conn).start()), you close the connection (conn.close()). Soon the thread tries to work with an already closed socket - which makes communication impossible.

You will need to reshape your code so that the thread ends the connection, simple like this :)

Code probably correct (since I didn’t, I won’t 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 away is the access in the variables "clientes_conn" and "clientes_name", which should be modified, since simultaneous access errors can happen for multiple threads (the time clients disconnect at the same time).

Hugs

Browser other questions tagged

You are not signed in. Login or sign up in order to post.