【问题标题】:Send/Receive Python chat room not working (updated)发送/接收 Python 聊天室不工作(更新)
【发布时间】:2019-07-11 04:13:26
【问题描述】:

我问了一个关于我的服务器到客户端代码的问题,因为我遇到了很多问题,有人告诉我解决问题的方法是进行点对点聊天,我现在已经这样做了。

服务器.py

import socket, threading

host = "127.0.0.1"
port = 4000
s = socket.socket()
s.bind((host,port))
s.listen(5)
client_sockets = []
users = []
print("Listening")

def handle_client(conn):
    while True:
        try:
            data = conn.recv(512)
            for x in client_sockets:
                try:
                    x.send(data)
                except Exception as e:
                    print(e)
        except:
            pass

while True:
    conn,addr = s.accept()
    client_sockets.append(conn)
    print("Connections from", addr[0], "on port",addr[1])
    threading.Thread(target = handle_client,args = (conn,)).start()

客户端.py

import socket,threading

host = "127.0.0.1"
port = 4000
s = socket.socket()
s.connect((host,port))

def echo_data(sock):
   while True:
      try:
         data = sock.recv(512)
         print(data)
      except:
         pass

while True:
   threading.Thread(target=echo_data,args=(s,)).start()
   msg = input("Enter your message : ")
   s.send(msg.encode())

问题是,当我运行客户端并尝试与另一个客户端交谈时,除非另一个客户端按 Enter,否则不会发送消息,这也让我遇到了第二个问题,当客户端相互发送消息时,他们以这种格式收到:

b'hi'Enter your message :

This is the link to my previous question

【问题讨论】:

  • @han solo 我将如何在我的代码中实现select 模块?
  • 检查这个。这有你需要的一切。并松开线程。 pymotw.com/2/select :)
  • @hansolo 我已经阅读了它,但我仍然不太确定如何在我的代码中实现它,所以你能告诉我如何取悦
  • @hansolo 他试图为每个客户端使用一个线程。使用这种设计,阻止客户端线程等待来自该客户端的数据就可以了。同样,在他的客户端中,他有一个线程,其目的是阻止等待来自服务器的数据。同样,阻塞该线程也很好,因为它的唯一目的是等待该连接上的数据。
  • 我对python不太了解,无法帮助您。但我不认为你的程序有什么大问题。您需要将输入从行模式更改为更原始的模式,并且需要将接收到的数据从原始字节转换为可打印的字符串。除此之外,我觉得还可以。如果任何客户端拒绝从中读取数据,您的服务器将阻塞,但我认为您目前不太关心抵抗攻击。

标签: python python-3.x sockets tcp


【解决方案1】:

我将从与问题不直接相关的一般问题开始:

  • except: pass 通常是个坏主意,特别是当出现问题时,因为它会隐藏潜在有用的消息。它是语言允许的,但不应存在于实际代码中
  • 在 client.py 中,您为每条消息启动一个接收线程,而整个客户端只需要一个接收线程。您应该在循环外启动线程:

    threading.Thread(target=echo_data,args=(s,)).start()
    while True:
       msg = input("Enter your message : ")
       s.send(msg.encode())
    

现在回答问题:

  • 除非其他客户端点击回车,否则消息不会被发送

    这可能是由 IDE 引起的。具体来说,众所周知,IDLE 在多线程脚本中表现不佳。如果您正确使用一个接收线程并从命令行 (python client.py) 启动脚本,它应该可以正常工作

  • 消息以这种格式接收:b'hi'Enter your message

    sock.recv(sz) 返回一个字节串。您需要对其进行解码以将其转换为 Python 3 unicode 字符串:

     data = sock.recv(512)
     print(data.decode())
    

但这还不是全部。这对测试来说很好,但您至少应该允许客户端与服务器断开连接,并且当它们断开连接时,将它们从client_sockets 中删除。而且通常不向发件人发回消息。所以你可以改进 server.py 循环:

while True:
    try:
        data = conn.recv(512)
        for x in client_sockets:
            if x != conn:         # do not echo to sender
                x.send(data)
    except Exception as e:        # problem in connection: exit the loop
        print(e)
        break
# clear the connection
conn.close()
client_sockets.remove(conn)

【讨论】:

  • 我还有一个问题,当我向另一个客户发送消息时,他们现在会以这种格式收到hiEnter your message :
  • 还有print (e)是做什么的?
  • @system123456:是一个错字。我忘记了 except 规范的结尾。
  • 哦,好的,你有解决我的问题的方法吗?
  • @system123456:在接收消息时重复Enter your message :很奇怪。仅应在发送消息时重复。
猜你喜欢
  • 2014-10-31
  • 2017-06-20
  • 1970-01-01
  • 1970-01-01
  • 2018-03-22
  • 2019-07-03
  • 1970-01-01
  • 2017-09-12
  • 1970-01-01
相关资源
最近更新 更多