2

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()
abarnert
368k54 gold badges627 silver badges692 bronze badges
asked May 27, 2015 at 6:05
4
  • Are you implementing a Chat Server application? Commented May 27, 2015 at 6:07
  • For future reference: You need a blank line between normal text and indented code, or the code isn't formatted as code. I fixed this one for you. Commented May 27, 2015 at 6:19
  • One obvious problem is that you're not calling select inside the loop, you're just calling it once, and then assuming that because the socket was readable one time it'll be readable forever. Commented May 27, 2015 at 6:21
  • In general, using bare except: clauses makes your code very hard to debug, because you can't see the actual exceptions happening. For example, when you get into the "offline" code in the server, it isn't always because the client disconnected, but because you ignore the actual exception, you can't tell that. Commented May 27, 2015 at 6:37

1 Answer 1

1

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).
answered May 27, 2015 at 6:25
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.