-1

Python socket programming:A client can only receive one message in my chat program...

This is my Code: I found it strange that after the window3 is displaying,you can send each other messages through ms!{target_id}|{message} and the server will send sm!{message} to the target.And the another person should get the message. However,i found it strange that one person can only receive the message the other send once. enter image description here However the server is able to received all the messages and tried to send to the targets.However,one of them can only receive one message.

import os
import threading
import PySimpleGUI as gui
from rsa_controller import decryptwithPrivatekey, loadPublicKey, loadPrivateKey

id = 0
target_id = 0
prikey = None
window2_active = False  # Indicates whether the second window is open
window = None
window2 = None
window3 = None
exit_flag = False  # Indicates whether the program should exit
pubkey = None
prikey = None
target_pubkey = None
restart_thread = False

def popout(title):
    gui.popup(title)

def read_keys():
    global pubkey, prikey
    print("Opening key files" + os.getcwd() + "\\keys\\")
    pubkey = loadPublicKey(os.getcwd() + "\\keys\\public.pem")
    prikey = loadPrivateKey(os.getcwd() + "\\keys\\private.pem")

def recv_msg():
    global target_id, window2_active, exit_flag
    global target_pubkey
    from main import s
    while not exit_flag:
        try:
            print("BEAT")
            data = s.recv(1024)
            if not data:
                break
            decoded_data = data.decode('utf-8')
            print("Received message:", decoded_data)
            if decoded_data == 'target_connected_Success':
                print("Received message:", decoded_data)
            elif decoded_data.startswith("!+@"):
                target_id = decoded_data[3:]
                if not window2_active:
                    window.write_event_value('open_window2', None)
            elif decoded_data == 'target_connect_denied':
                gui.popup('Connection request denied')
                exit_flag = True
            elif decoded_data.startswith("pu!"):
                parts = decoded_data.split("|")
                target_id = parts[0][3:]
                target_pubkey = parts[1]
                print("Received the public key of the other party:", target_pubkey)
                window.write_event_value('open_window3', None)
            elif decoded_data.startswith("sm!"):
                message = decoded_data[3:]
                window3['text_output'].print("{}:{}".format(target_id, message))
                continue
            else:
                msg_to_recv = decryptwithPrivateKey(decoded_data, prikey)
                print("Received message:", msg_to_recv)
        except Exception as e:
            print("Exception occurred while receiving message:", e)

def window2_event_handler(event):
    global window2_active, exit_flag
    global pubkey
    from main import s
    if event == 'denied':
        print("Connection denied")
        s.send('!x!{}'.format(target_id).encode('utf-8'))
        window2_active = False
        exit_flag = True
    elif event == 'accept':
        print("Confirm sharing my public key and establish connection")
        # Handle the logic for confirming the connection
        s.send("mp!{}|{}".format(target_id, pubkey).encode())
        window2_active = False
        exit_flag = True

def window2():
    from main import s
    global target_id, window2_active, exit_flag
    layout2 = [
        [gui.Text('Connecting with'), gui.Text(str(target_id), key='target_id'), gui.Text("...")],
        [gui.Button('Confirm sharing my public key and establish connection', key='accept', enable_events=True),
         gui.Button('Deny connection request', key='denied', enable_events=True)]
    ]
    window2_active = True
    window2 = gui.Window("Connection Request", layout2, finalize=True, no_titlebar=True)
    while True:
        event2, values2 = window2.read()
        if event2 == gui.WINDOW_CLOSED:
            break
        window2_event_handler(event2)
        if exit_flag:
            break
    window2.close()

def window3():
    from main import s
    layout3 = [
        [gui.Multiline(size=(None, 10), key='text_output', disabled=True, autoscroll=True)],
        [gui.Input(size=(None, 1), key='text_input'), gui.Button('Send', key='send')]
    ]
    global window3
    window3 = gui.Window("Chat Window-{}".format(target_id), layout3, finalize=True)
    exit_flag_window3 = False  # Exit flag for window3
    while True:
        event3, values3 = window3.read()
        if event3 == gui.WINDOW_CLOSED:
            exit_flag_window3 = True  # Set the exit flag for window3 to True
            break  # Exit the event loop
        if event3 == 'send':
            message = values3['text_input']
            # Handle the sending logic
            window3['text_output'].print(f'You: {message}')
            s.send(f"ms!{target_id}|{message}".encode('utf-8'))
            window3['text_input'].update('')  # Clear the input field

    window3.close()

    # When window3 is closed, set the exit flag to True and wait for the event loop in the thread to exit
    exit_flag = True
    while threading.active_count() > 1:
        pass

def start_GUI_progress(id):
    from main import s
    global restart_thread
    read_keys()
    layout = [
        [gui.Text('Your ID'), gui.Text(id)],
        [gui.Text('Note: Please enter the target ID in the input box below and click the Connect button')],
        [gui.Input(key='target_id'), gui.Button('Connect', key='connect')]
    ]
    global window
    window = gui.Window("RSA Encrypted Instant Messaging", layout, finalize=True)
    host = "localhost"
    port = 23333
    s.connect((host, port))
    print(s.recv(1024))
    t_recv = threading.Thread(target=recv_msg)
    t_recv.start()
    # Send the ID
    s.send(b"__!" + str(id).encode('utf-8'))
    while True:
        event, values = window.read()
        if event == gui.WINDOW_CLOSED:
            break
        if not t_recv.is_alive():
            print("Thread DEAD!!")
        if event == 'connect':
            print("Client starts to attempt connection: {}".format(values['target_id']))
            # Construct the message to send
            message = "_!?{}".format(values['target_id'])
            # Send the message to the server
            s.send(message.encode('utf-8'))
            message = "mp!{}|{}".format(values['target_id'], pubkey)
            s.send(message.encode('utf-8'))
        elif event == 'open_window2':
            window2()
        elif event == 'open_window3':
            window3()
        elif event == gui.WINDOW_CLOSE_ATTEMPTED_EVENT:
            break
    window.close()

ddhello
  • 1
  • 2
  • 1
    `elif decoded_data == 'target_connect_denied':gui.popup('Connection request denied')`, you didn't update this `gui.popup` with `window.write_event_value`. – Jason Yang Jun 04 '23 at 08:49
  • I dont think so, the problem is not on the side of denying the connection request, but happened in the situation that accepted the request.. – ddhello Jun 04 '23 at 10:33
  • 1
    Just tell you where I found issue, not debug all you code for your question here. – Jason Yang Jun 04 '23 at 11:26

1 Answers1

1

This code suggests a misunderstanding of how the TCP protocol works:

data = s.recv(1024)
if not data:
   break
decoded_data = data.decode('utf-8')
print("Received message:", decoded_data)

In particular, s.recv(1024) doesn't receive "a message".

Rather, it receives the next N bytes of data from the socket (where N is the number of received bytes currently available for processing in the kernel's socket-buffer; in this case will be between 1 and 1024).

Because TCP does not provide message framing, that means that the number of bytes you receive may not correspond to the number of bytes previously sent by any particular send() call by the client.

For example, if the client sent three messages:

  1. One 10-byte message
  2. One 50-byte message
  3. One 15-byte message

... then your first recv() call might return a buffer with anywhere between 1 and 75 bytes in it, and it is up to the receiving code to figure out how to handle it correctly if, for example, the first recv() call returned 34 bytes, then the second recv() call returned 16 bytes, and then the third recv() call returned the remaining 25 bytes.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234