[英]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:奖励问题:
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.