user4884072
user4884072

Reputation: 81

python3 - broken pipe error when using socket.send()

I am programming a client-server instant message program. I created a similar program in Python 2, and am trying to program it in Python 3. The problem is when the server takes the message and tries to send it to the other client, it gives me "[Errno 32] Broken Pipe" and exits.

I have done some research, and found that this occurs when the client disconnects, so I did some more testing but could not find when the client disconnects. (I am using Ubuntu 14.04 and Python 3.4)

Here is the server code:

import socket, select, sys

def broadcast(sock, messaged):
    for socket in connection_list:
        if socket != s and socket != sock:
        # Here is where it gives me the broken pipe error
            try:
                s.send(messaged.encode("utf-8"))
            except BrokenPipeError as e:
                print(e)
                sys.exit()
connection_list = []
host = ''
port = 5558

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(5)

connection_list.append(s)
read_sockets,write_sockets,error_sockets = select.select(connection_list,[],[])
while True:
    for sock in read_sockets:
        if sock == s:
            conn, addr = s.accept()
            connection_list.append(conn)
            client = "Client (%s,%s) connected" % addr
            print(client)
            broadcast(sock,client)

        else:
            try:
                data = sock.recv(2048)
                decodeddata = data.decode("utf-8")
                if data:
                    broadcast(sock, decodeddata)
            except:
                offline = "Client " + addr + "is offline"
                broadcast(sock, offline)
                print(offline)
                connection_list.remove(sock)
                sock.close()
                continue

And the client code:

import socket, select, string, sys, time

def prompt(data) :
     print("<You> " + data)
def Person(data) :
    print("<Receiver> " + data)

if __name__ == "__main__":

    host = "localhost"
    port = 5558

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(2)

    try:
        s.connect((host,port))
    except:
        print('Unable to connect')
        sys.exit()
    print('Connected.')
    socket_list = [s]
    read_sockets,write_sockets,error_sockets = select.select(socket_list,[],[])
    while 1:
        for sock in read_sockets:
            if sock == s:
                try:
                    time.sleep(1)
                    data = sock.recv(1024)             
                    Person(data.decode("utf-8"))
                except:
                    msg = input("Send a message: ")
                    try:
                        s.send(str.encode(msg))
                    except:
                        print("Server is offline")
                        sys.exit()


            else:
                print("Server is offline")
                sys.exit()

Upvotes: 2

Views: 6261

Answers (1)

abarnert
abarnert

Reputation: 365657

There are two problems that you have to fix to make this work.

First, on both the client side and the server side, you have to put the select inside the loop, not outside. Otherwise, if there was something to read before you got to the loop, you'll recv over and over, and if there wasn't, you'll never recv. Once you fix this, you can get rid of the time.sleep(1). (You should never need a sleep to solve a problem like this; at best it masks the problem, and usually introduces new ones.)

Meanwhile, on the server side, inside broadcast, you're doing s.send. But s is your listener socket, not a connected client socket. You want socket.send here, because socket is each socket in connection_list.


There are a number of unrelated problems in your code as well. For example:

  • I'm not sure what the except: in the client is supposed to be catching. What it mainly seems to catch is that, about 50% of the time, hitting ^C to end the program triggers the send prompt. But of course, like any bare except:, it also masks any other problems with your code.
  • There's no way to send any data back and forth other than the "connected" message except for that except: clause.
  • addr is a tuple of host and port, so when someone goes offline, the server raises a TypeError from trying to format the offline message.
  • addr is always the last client who connected, not the one who's disconnecting.
  • You're not setting your sockets to nonblocking mode.
  • You're not checking for EOF on the recv. This means that you don't actually detect that a client has gone offline until you get an error. Which normally happens only after you try to send them a message (e.g., because someone else has connected or disconnected).

Upvotes: 1

Related Questions