pythonsocketschatserversocketbroken-pipe

BrokenPipeError on socket


I created a messenger using Python Socket, when I use two clients, for example, when one user leaves the chat, the second user can send 1-2 more messages and after that the server stops accepting messages from other users, that is there is a well-known error Broken pipe 32. I understand the terminology of the error, perhaps the error lies on my server in a While True loop (a loop that includes all the actions that users carry out among themselves), because there is a fabulous code in the form:

if not data:
    print(f'User {name1} leave')
    break

but I need it, because without it the server will fly away in a straight word, and if a similar mechanism is made, the server will still be able to receive information from users.

Hope for mutual understanding, any help would be accepted and appreciated. Server and client code is below:

server: 

import socket
import threading
import time

HOST = '127.0.0.1'
PORT = 8888

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))

server.listen(15)
print(f'Server {HOST}:{PORT} start.')

users = [] 
sort = []


def crypto(text, key):
    encrypt = ''

    for i in text:
        encrypt += chr(ord(i) + key)

    return encrypt   


def listen_decode(user, addr):
    print(f'User IP-address {addr[0]} login..')
    sort.append(user) 
    user.send('Encode'.encode('utf-8'))
    user.send('Name'.encode('utf-8'))
    name1 = user.recv(1024).decode('utf-8')
    users.append(name1)

    
    while True:
        data = user.recv(1024).decode('utf-8')
        b1 = time.ctime()
        atribute = ' | '
        data_crypto = crypto(data, 4)
        print(f'{name1} sent message: {data_crypto} ' + atribute + '' + b1 + ' ')

        for i in sort:
            if(i != server and i != user):
                i.sendall(f'{name1} > {data}'.encode('utf-8'))
    
        if not data:
            print(f'User {name1} leave')
            break


def start_server():
    
    while True:
       user_socket, addr = server.accept()
       potok_info = threading.Thread(target=listen_decode, args=(user_socket, addr))
       potok_info.start()


if __name__ == '__main__':
    start_server()

client:

from tkinter import messagebox
from tkinter import *
import _tkinter 
import socket
import threading
import os


window = Tk()

window.title('Login')
window.geometry('320x200')
window.resizable(True, True)

HOST = '127.0.0.1'
PORT = 8888

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST, PORT))

name = StringVar()
password = StringVar()

def encrypt(text, key):
    encrypt1 = ''

    for i in text:
        encrypt1 += chr(ord(i) - key)

    return encrypt1

def send_message():

    while True:
        data = client.recv(1024)
        print('\r\r' + data.decode('utf-8') + '\n' + f'you: ', end='')


def chat():

    string_name = name.get()

    if('Name' in client.recv(1024).decode('utf-8')):
        name1 = string_name
        client.send(name1.encode('utf-8'))

        potok = threading.Thread(target=send_message)
        potok.start()


        while True:
            msg = input('you: ')
            client.send(msg.encode('utf-8'))



def crypt():     
    
    string_name = name.get()
    string_password = password.get()

    try:
        user_encryption_selection = (encryption_listbox.get(encryption_listbox.curselection()))
    except _tkinter.TclError:
        messagebox.showerror('Error', 'Enter type message')



    if string_name == 'John':
        if string_password == '5555':
            if user_encryption_selection == 'Use Encrypted':
                window.after(1000, lambda: window.destroy())

                menu = Tk()

                menu.title('Menu Chat')
                menu.geometry('500x350')
                menu.resizable(False, False)

                menu_button = Button(menu, text='Global chat', command=chat, height=1, width=18)
                menu_button.grid(padx=150)

                menu.mainloop()
        else:
            messagebox.showerror('Error', 'Error password')
    else:
        messagebox.showerror('Error', 'Error name')

    
entry = Entry(window, textvariable=name, width=10)
entry.grid(column=1, pady=7, padx=4)

label = Label(window, text='Enter name: ')
label.grid(row=0, padx=1)

entry1 = Entry(window, textvariable=password, width=10)
entry1.grid(column=1, pady=7, padx=2)

label1 = Label(window, text='Enter password: ')
label1.grid(row=1, padx=1)

listbox = Listbox(window, selectmode=SINGLE, width=12, height=2)
listbox.grid(column=1, row=2, pady=7, padx=2)



encryption_options = ['Use Encrypted']
encryption_listbox = Listbox(window, selectmode=SINGLE, width=10, height=1)
encryption_listbox.grid(column=1, row=2, pady=7, padx=2)
for i in encryption_options:
    encryption_listbox.insert(END, i)  

label_crypto = Label(window, text='Type message: ', bg='black', fg='red')
label_crypto.grid(row=2)

button = Button(window, text='Enter', command=crypt)
button.grid(pady=30)



window.mainloop()

Solution

  • perhaps the error lies on my server in a While True loop (a loop that includes all the actions that users carry out among themselves), because there is a fabulous code in the form:

    if not data:
        print(f'User {name1} leave')
        break
    

    You already spotted the place of the error's cause. The error occurs because the server keeps trying to send to a disconnected client (in the loop immediately above that code). To stop the server trying this, you just have to remove the client from sort (the list of connected clients) at that place where you recognize the disconnection, i. e. insert sort.remove(user) before the break.