【问题标题】:Python Socket Message ExchangePython 套接字消息交换
【发布时间】:2018-04-26 22:29:04
【问题描述】:

我必须编辑我在 chatServer 的 python 中拥有的这段代码,以便您可以将私人消息发送给接收者,如果接收者没有登录,它会向发送者输出错误。此外,服务器向客户端发送的任何消息都必须提供原始发送者的名称。

chatClient.py

​​>
import socket
import struct
import sys
import threading
from datetime import datetime

PORT = 8888
HEADER_LENGTH = 2


def receive_fixed_length_msg(sock, msglen):
    message = b''
    while len(message) < msglen:
        chunk = sock.recv(msglen - len(message))
        if chunk == b'':
            raise RuntimeError("socket connection broken")
        message = message + chunk
    return message


def receive_message(sock):
    header = receive_fixed_length_msg(sock, HEADER_LENGTH)
    message_length = struct.unpack("!H", header)[0] 

    message = None
    if message_length > 0: 
        message = receive_fixed_length_msg(sock, message_length) 
        message = message.decode("utf-8")

    return message


def send_message(sock, message):
    encoded_message = message.encode("utf-8") 
    header = struct.pack("!H", len(encoded_message))

    message = header + encoded_message 
    sock.sendall(message);

def message_receiver():
    while True:
        msg_received = receive_message(sock)
        if len(msg_received) > 0:  # ce obstaja sporocilo
            current_time = datetime.now().strftime('%H:%M:%S')
            print("[RKchat][" + current_time + "] " + name + ": " + msg_received)

print("[system] connecting to chat server ...")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("localhost", PORT))
print("[system] connected!")

thread = threading.Thread(target=message_receiver)
thread.daemon = True
thread.start()

name = input("Vpiši ime: ")

while True:
    try:
        msg_send = input("")
        send_message(sock, msg_send)
    except KeyboardInterrupt:
        sys.exit()

聊天服务器.py

​​>
import signal

signal.signal(signal.SIGINT, signal.SIG_DFL)
import socket
import struct
import threading

PORT = 8888
HEADER_LENGTH = 2


def receive_fixed_length_msg(sock, msglen):
    message = b''
    while len(message) < msglen:
        chunk = sock.recv(msglen - len(message)) 
        if chunk == b'':
            raise RuntimeError("socket connection broken")
        message = message + chunk  # pripni prebrane bajte sporocilu

    return message


def receive_message(sock):
    header = receive_fixed_length_msg(sock, HEADER_LENGTH)
    message_length = struct.unpack("!H", header)[0]

    message = None
    if message_length > 0:
        message = receive_fixed_length_msg(sock, message_length)
        message = message.decode("utf-8")

    return message


def send_message(sock, message):
    encoded_message = message.encode("utf-8")

    header = struct.pack("!H", len(encoded_message))

    message = header + encoded_message
    sock.sendall(message);

def client_thread(client_sock, client_addr):
    global clients

    print("[system] connected with " + client_addr[0] + ":" + str(client_addr[1]))
    print("[system] we now have " + str(len(clients)) + " clients")

    try:
        while True:
            msg_received = receive_message(client_sock)

            if not msg_received: 
                break

            print("[RKchat] [" + client_addr[0] + ":" + str(client_addr[1]) + "] : " + msg_received)

            for client in clients:
                send_message(client, msg_received.upper())
    except:
        pass

    with clients_lock:
        clients.remove(client_sock)
    print("[system] we now have " + str(len(clients)) + " clients")
    client_sock.close()

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("localhost", PORT))
server_socket.listen(1)

print("[system] listening ...")
clients = set()
clients_lock = threading.Lock()
while True:
    try:
        client_sock, client_addr = server_socket.accept()
        with clients_lock:
            clients.add(client_sock)

        thread = threading.Thread(target=client_thread, args=(client_sock, client_addr));
        thread.daemon = True
        thread.start()

    except KeyboardInterrupt:
        break

print("[system] closing server socket ...")
server_socket.close()

【问题讨论】:

  • 那么你可能需要编写一些代码来做到这一点。 Stackoverflow 不是让别人为你写代码的。如果您对此有具体问题,请解释它是什么,有人可能会帮助您。由于您的问题现已格式化,因此不太可能收到任何有用的回复。
  • 问题是我不知道该怎么做...我希望得到一些帮助。

标签: python sockets


【解决方案1】:

您现在有了一个简单的“接收消息,向所有人广播”类型的客户端和服务器。正如用 cmets 编写的那样,我们不会为您编写代码,但这里有一些您可以使用的想法。

首先,您需要构建一个协议。现在您将服务器接收到的所有内容都视为消息并将其广播到其他连接。如果您现在需要处理公共(向所有人广播)和私人消息(仅发送给特定用户),服务器需要知道用户名。服务器还需要区分公共和私人消息。

例如,您可以在服务器中要求您从新连接收到的第一条消息是

REGISTER username

然后您将识别此消息,而不是为客户端设置一组,而是将其更改为字典并将用户名作为键

clients[username] = client_sock

或类似的东西。

当您的客户端线程收到消息时,它们也会对其进行解析。可能的消息可能是

PUBLICMESSAGE message
PRIVATEMESSAGE username message

如果您收到公开消息,您会按照现在的方式进行操作。如果您收到一条私人消息,您将获得要发送的套接字

try:
     client = clients[username]
     send_message(client, message)
except KeyError:
     Send an error message back stating the target user is not online

这些只是指针。您需要一个协议,因为您需要区分公共消息和私人消息,并且您需要让服务器知道您的用户名是什么的方法,以便它可以将其用作标识符。然后你需要构建一点解析来将协议关键字与消息分开。

我还想向您指出我前一段时间写的先前答案。 Python: Multithreaded socket server runs endlessly when client stops unexpectedly 请阅读从“TCP 套接字传输数据,而不是消息”开始的最后几段。现在您的服务器不适合场景 3-5,但它应该。当您构建协议时,这一点变得更加重要,因为如果您从套接字接收的内容超出预期,您将在很多方面出错,因为您会吞下连续的协议关键字。

【讨论】:

    猜你喜欢
    • 2016-02-28
    • 1970-01-01
    • 2016-10-13
    • 2019-12-28
    • 2015-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多