简体   繁体   English

Python 字符串通过 sockets 发送两次

[英]Python string being sent twice through sockets

I'm improving this GUI-based chatroom script I found online.我正在改进我在网上找到的这个基于 GUI 的聊天室脚本。 Right now I've been working on a way to add chat name tags, starting with a server host tag.现在我一直在研究一种添加聊天名称标签的方法,从服务器主机标签开始。 This is a snip of my code that adds [Server Host] to someone's nickname if a connection with the host's IP is made:这是我的代码片段,如果与主机的 IP 建立连接,则将[Server Host]添加到某人的昵称:

...
for key, value in addresses.items(): # Go through the currently connected addresses...
        if HOST in value: # ...and check if the host's IP is connected.
            name = "[Server Host] " + name # Add chat tag to the beginning of their nickname.
    msg = "%s has joined the chat!" % name
    broadcast(bytes(msg, "utf8"))
    clients[client] = name
...

However, when one joins the chat with the tag, it says [Server Host] [Server Host] somename for example instead of only one tag.但是,当一个人使用标签加入聊天时,它会显示[Server Host] [Server Host] somename例如,而不是只有一个标签。 Yet when chatting, the tag is just fine.但是聊天的时候,标签就好了。

Why does this happen?为什么会这样?

Bonus questions:奖励问题:

  • Is it possible to add color to text in the chat, for tags and text for example?是否可以为聊天中的文本添加颜色,例如标签和文本?
  • Every time a client attempts to exit by pressing the exit button on the window, the server's output has a large error message.每次客户端尝试通过按下 window 上的退出按钮来退出时,服务器的 output 都会出现很大的错误消息。 How do I fix this so it's not annoying?我该如何解决这个问题,所以它不烦人?

Here's the code for the server:这是服务器的代码:

from socket import AF_INET, socket, SOCK_STREAM, gethostbyname, gethostname
from threading import Thread


def accept_incoming_connections():
    """Sets up handling for incoming clients."""
    while True:
        client, client_address = SERVER.accept()
        print("%s:%s has connected." % client_address)
        client.send(bytes("Welcome! Type your name and press enter.", "utf8"))
        addresses[client] = client_address
        Thread(target=handle_client, args=(client,)).start()


def handle_client(client):  # Takes client socket as argument.
    """Handles a single client connection."""

    name = str(client.recv(BUFSIZ).decode("utf8"))
    welcome = 'Welcome, %s! To quit, type !quit.' % name
    client.send(bytes(welcome, "utf8"))
    for key, value in addresses.items(): # Go through the currently connected addresses...
        if HOST in value: # ...and check if the host's IP is connected.
            name = "[Server Host] " + name
    msg = "%s has joined the chat!" % name
    broadcast(bytes(msg, "utf8"))
    clients[client] = name
    while True:
            msg = client.recv(BUFSIZ)
            if msg != bytes("!quit", "utf8"):
                broadcast(msg, name + ": ")
            else:
                client.send(bytes("!quit", "utf8"))
                client.close()
                del clients[client]
                broadcast(bytes("%s has left the chat." % name, "utf8"))
                break


def broadcast(msg, prefix=""):  # prefix is for name identification.
    """Broadcasts a message to all the clients."""
    for sock in clients:
        sock.send(bytes(prefix, "utf8")+msg)

        
clients = {}
addresses = {}

HOST = gethostbyname(gethostname())
while True:
    try:
        PORT = int(input("Enter port to run server on: "))
        if PORT > 1024:
            break
        print("Invalid port entered\n")
    except:
        print('Port must be a number > 1024\n')
print("\nServer running on host %s, and on port %s" % (HOST, PORT,))
BUFSIZ = 1024
ADDR = (HOST, PORT)

SERVER = socket(AF_INET, SOCK_STREAM)
SERVER.bind(ADDR)

if __name__ == "__main__":
    SERVER.listen(5)
    print("Waiting for server connection...")
    ACCEPT_THREAD = Thread(target=accept_incoming_connections)
    ACCEPT_THREAD.start()
    ACCEPT_THREAD.join()
    SERVER.close()

And the client:和客户:

from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
import tkinter


def receive():
    """Handles receiving of messages."""
    while True:
        try:
            msg = client_socket.recv(BUFSIZ).decode("utf8")
            msg_list.insert(tkinter.END, msg)
        except OSError:  # Possibly client has left the chat.
            break


def send(event=None):  # event is passed by binders.
    """Handles sending of messages."""
    msg = my_msg.get()
    my_msg.set("")  # Clears input field.
    client_socket.send(bytes(msg, "utf8"))
    if msg == "!quit":
        client_socket.close()
        top.quit()


def on_closing(event=None):
    """This function is to be called when the window is closed."""
    my_msg.set("!quit")
    send()


HOST = input('Enter host: ')
PORT = input('Enter port: ')
if not PORT:
    PORT = 12345
else:
    PORT = int(PORT)

try:
    BUFSIZ = 1024
    ADDR = (HOST, PORT)

    client_socket = socket(AF_INET, SOCK_STREAM)
    client_socket.connect(ADDR)
except:
    print("Couldn't connect - the server may not be up or you had a different problem.")
    exit()


top = tkinter.Tk()
top.title("Chatroom")

messages_frame = tkinter.Frame(top)
my_msg = tkinter.StringVar()  # For the messages to be sent.
scrollbar = tkinter.Scrollbar(messages_frame)  # To navigate through past messages.
# Following will contain the messages.
msg_list = tkinter.Listbox(messages_frame, height=15, width=50, yscrollcommand=scrollbar.set)
scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
msg_list.pack(side=tkinter.LEFT, fill=tkinter.BOTH)
msg_list.pack()
messages_frame.pack()

entry_field = tkinter.Entry(top, textvariable=my_msg)
entry_field.bind("<Return>", send)
entry_field.pack()
send_button = tkinter.Button(top, text="Send", command=send)
send_button.pack()

top.protocol("WM_DELETE_WINDOW", on_closing)

receive_thread = Thread(target=receive)
receive_thread.start()
tkinter.mainloop()  # Starts GUI execution.

Related to the first question, is because you are not overwriting the var name but concatenating the string instead.与第一个问题相关,是因为您没有覆盖 var name ,而是连接字符串。 Try changing the name of that variable, something like this:尝试更改该变量的名称,如下所示:

for key, value in addresses.items(): # Go through the currently connected addresses...
        prefix = "[Server Host] "
        if HOST in value: # ...and check if the host's IP is connected.
            prefix += name # Add chat tag to the beginning of their nickname.
    msg = "%s has joined the chat!" % prefix
    broadcast(bytes(msg, "utf8"))
    clients[client] = name

In this way you separate your formatted string from the user name.通过这种方式,您可以将格式化的字符串与用户名分开。

Also, if you are using python 3.x I recommend to change:此外,如果您使用的是 python 3.x,我建议更改:

msg = "%s has joined the chat!" % prefix

for this:为了这:

msg = f"{prefix} has joined the chat!"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM