1

I'm trying to create a multiuser chat interface in Python3 using tkinter. I am running into the error EOFError: Ran out of input with pickle data. Has anyone run into a similar error or has an idea of how to fix the problem? I have tried to increase bit number with no result.

The code uses four scrips which I have attached below. The server runs in the background while the client script is run twice on parallel run.

chat_server.py

import socket
from _thread import *
from ipv4 import get_ipv4
import pickle
from chat_main import Chat


server = get_ipv4()
port = 5555

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

try:
    s.bind((server, port))
except socket.error as e:
    print(e)

s.listen(2)
print("Waiting for connection, server started")

connected = set()
rooms = {}  # track id to object defined by class Main
id_count = 0  # how many people connected to server
HEADERSIZE = 10



def threaded_client(connection, u, room_id):
    """
    :param connection:
    :param u: [0, 1] --> user number
    :param room_id:
    :return:
    """
    global id_count
    connection.send(str.encode(str(u)))  # send starting data --> 0 or 1 (user number)

    while True:
        """
        reset: update no new information from other user
        get: client sends text, update server, send any updates from other user back to client"
        """
        try:

            data = connection.recv(2048*2).decode()  # pull any ready info from server

            if room_id in rooms:
                room = rooms[room_id]  # make sure room is still there

                if not data:  # if no data to read, break
                    break
                else:
                    if data == "reset1":  # reset that user one went
                        room.reset_sent(0)
                    elif data == "reset2":  # reset that user two went
                        room.reset_sent(1)
                    elif data != "get":  # get the room from server
                        room.send(u, data)

                    connection.sendall(pickle.dumps(room))  # send the updated room object back to server
            else:
                break
        except Exception as e:
            print(f"Error {e}")
            break

    print("Lost connection")

    try:
        del rooms[room_id]
        print(f"Room {room_id} terminated")
    except:
        pass
    id_count -= 1
    connection.close()


while True:
    conn, addr = s.accept()  # --> accepts incoming connection and address
    print(f"Connected to {addr}")  # lets user know the connection was sucessful

    id_count += 1  # user count += 1
    user_id = (id_count - 1)//2  # create unique game code based on number of users
    if id_count % 2 == 1:
        u = 0  # user 1
        # create a new game
        rooms[user_id] = Chat(user_id)  # id = game
        print("Creating a new game...")
    else:
        u = 1  # user two
        rooms[user_id].ready = True  # ready to launch chat!

    start_new_thread(threaded_client, (conn, u, user_id))  # start thread

chat_client.py

import tkinter as tk
from chat_network import Network


def tk_main(data, net):
    window = tk.Tk()
    window.update()

    window.title("Room")
    window.update()

    window.geometry("500x500")
    window.update()

    window.resizable(True, True)
    window.update()

    data = data
    data_str = ""
    for item in data:
        data_str += f"{item}\n\n"
    window.update()

    main_frame = tk.LabelFrame(window, text="Welcome to Dollartree Discord - HAVE FUN!")
    window.update()

    main_frame.pack(fill="both", expand="yes", padx=10, pady=10)

    window.update()

    chat_frame = tk.Frame(master=main_frame, bg="#d1d1d1")
    window.update()

    chat_frame.pack(expand="yes", fill="both", padx=5, pady=5)
    window.update()

    scroll = tk.Scrollbar(master=chat_frame)
    window.update()

    scroll.grid(sticky="nws", column=1, row=0, padx=0, pady=5)
    window.update()

    listbox = tk.Listbox(master=chat_frame, yscrollcommand=scroll.set)
    window.update()

    listbox.grid(column=0, row=0, sticky="nsew", padx=5, pady=5)
    window.update()

    for item in data:
        listbox.see(tk.END)
        listbox.insert(tk.END, item)
    window.update()

    scroll.config(command=listbox.yview)
    window.update()

    input_frame = tk.Frame(master=chat_frame, bg="#d1d1d1")
    window.update()

    text_input = tk.Entry(master=input_frame)
    window.update()

    button = tk.Button(master=input_frame, text="Send Message", command=lambda: send(text_input, window, listbox, scroll, data, net))
    window.update()

    text_input.grid(row=1, column=0, sticky="ew", padx=5, pady=5)
    window.update()

    button.grid(column=1, row=1, sticky="w", padx=5, pady=5)
    window.update()

    input_frame.grid(row=1, sticky="nwe")
    window.update()

    chat_frame.columnconfigure(tuple(range(1)), weight=2)
    window.update()

    chat_frame.rowconfigure(tuple(range(1)), weight=2)
    window.update()

    input_frame.columnconfigure(tuple(range(1)), weight=2)
    window.update()

    input_frame.rowconfigure(tuple(range(1)), weight=2)

    window.update()
    return window, listbox


def send(text_input, window, listbox, scroll, data, net):

    if (text_input.get()).strip() != "":
        message = text_input.get()
        window.update()

        data.append(message)
        window.update()

        text_input.delete(0, "end")
        window.update()

        listbox.insert("end", message)
        window.update()

        net.send_old(message)

        if not scroll.get()[1] < 1:
            listbox.see(tk.END)
        window.update()


def main():
    run = True
    n = Network()
    user = int(n.get_user())
    print("You have entered the chat room.")
    print(f"You are user {user}.")

    t, l = tk_main(["You have entered the chat", f"You are user {user}"], n)
    t.update()

    try:
        while run:
            try:
                room = n.send_old("get")
            except Exception as e:
                print(f"Could not get room, error: {e}")
                break
            t.update()

            if user == 0 and room.u2_went():
                l.insert(room.get_user_text(1))
                t.update()

                n.send_old("reset2")
                t.update()
            elif user == 1 and room.u1_went():
                l.insert(room.get_user_text(1))
                t.update()

                n.send_old("reset1")
                t.update()
    except Exception as e:
        print(f"Error: {e}")


main()

chat_network.py

import socket
from ipv4 import get_ipv4
import pickle


class Network:
    def __init__(self):
        self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # don't understand line
        self.server = get_ipv4()
        self.port = 5555
        self.addr = (self.server, self.port)  # don't understand line
        self.u = self.connect()

    def get_user(self):
        """
        :return: user
        """
        return self.u

    def connect(self):
        """
        :return: [0, 1] user number
        """
        try:
            self.client.connect(self.addr)
            return self.client.recv(2048).decode()
        except:
            pass

    def send_old(self, data):
        """
        :param data: text message
        :return: any updates to room object
        """
        try:
            self.client.send(str.encode(data))  # send data over server
            return pickle.loads(self.client.recv(2048*2))  # get any data from server in object form, load with pickle
        except socket.error as e:
            print(e)

chat_main.py

class Chat:
    def __init__(self, room_id):
        """
        :param room_id: code to get into specified room
        """
        self.user1_went = False
        self.user2_went = False
        self.ready = False
        self.id = room_id
        self.texts = [[["past"], None], [["past"], None]]

    def get_user_text(self, user):
        """
        :param user: [0, 1] user number
        :return: user text
        """
        return self.texts[user][1]

    def send(self, user, text):
        """
        :param user: [0, 1]
        :param text: string, text sent
        :return: no return value
        """
        self.texts[user][-1] = text
        if user == 0:
            self.user1_went = True
        else:
            self.user2_went = True

    def connected(self):
        """
        :return: True or False --> make sure both users are connected to server
        """
        return self.ready

    def u1_went(self):
        return self.user1_went

    def u2_went(self):
        return self.user2_went

    def sent(self, user, text):
        """
        :param user: [0, 1] user number
        :param text: text input
        :return: none, update user text in texts list
        """
        self.texts[user][0].append(text)
        self.texts[user][-1] = None

    def reset_sent(self, user):
        """
        :param user: [0, 1]
        :return: no return value
        """

        if user == 0:
            self.user1_went = False
            if self.texts[user][1] is not None:
                self.texts[user][0].append(str(self.texts[user][1]))
                self.texts[user][1] = None
        else:
            self.user2_went = False
            if self.texts[user][1] is not None:
                self.texts[user][0].append(str(self.texts[user][1]))
                self.texts[user][1] = None
Nina
  • 11
  • 2

0 Answers0