【问题标题】:Client(1) to Server to Client(2) in Python 3.x (Sockets?)Python 3.x 中的客户端(1)到服务器到客户端(2)(套接字?)
【发布时间】:2014-01-07 22:46:44
【问题描述】:

我一直在处理一个项目,该项目涉及将信息发送到公共服务器(以演示密钥交换方案的工作原理),然后将其发送到特定客户端。只有两个客户。

我希望在如何将信息从客户端 (1) 获取到服务器的正确方向上得到推动,然后让服务器将该信息重定向到客户端 (2)。我对代码有些混乱,对如何从服务器发送和接收信息感到满意,但我不知道(到目前为止大约 2 小时的研究)如何区分客户端并将信息发送给特定客户端 我当前的服务器代码(与python3 docs 几乎没有变化:

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The RequestHandler class for our server.

It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""

def handle(self):
    # self.request is the TCP socket connected to the client
    self.data = self.request.recv(1024).strip()
    print("{} wrote:".format(self.client_address[0]))
    print(self.data)
    # just send back the same data, but upper-cased
    self.request.sendall(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

# Create the server, binding to localhost on port 9999
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)

# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()

我的客户端代码(与python3 docs 几乎没有变化:

import socket
import time

data = "matt is ok"

def contactserver(data):
    HOST, PORT = "localhost", 9999
    # Create a socket (SOCK_STREAM means a TCP socket)
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

     # Connect to server and send data
    sock.connect((HOST, PORT))
    sock.sendall(bytes(data, "utf-8"))

   # Receive data from the server and shut down
    received = str(sock.recv(1024), "utf-8")
    print("Sent:     {}".format(data))
    print("Received: {}".format(received))
    return format(received)

while True:
    k = contactserver('banana')
    time.sleep(1)
print(k)

【问题讨论】:

  • 然后呢?您已经很好地粘贴了与文档几乎没有变化的代码。您对该代码有疑问吗?
  • @abarnert 我希望在如何从客户端(1)获取信息到服务器的正确方向上得到推动,然后让服务器将该信息重定向到客户端(2)。我对代码有些混乱,对如何从服务器发送和接收信息感到满意,但我不知道(到目前为止大约 2 小时的研究)如何区分客户端并将信息发送给特定客户端。
  • socketserver 真的不应该以这种方式使用 - 它保持简单以使其更易于学习,并使the source 易于理解,作为更复杂项目的示例代码.有一些框架可以帮助您进行客户端间通信,但socketserver 不是其中之一。话虽这么说,你想要的可行的,正如我在回答中解释的那样......但如果你想变得更复杂,你可能想要超越socketserver

标签: python sockets client communication


【解决方案1】:

首先,基地socketserver.TCPServer 甚至不能同时与两个客户交谈。正如the docs 解释:

这四个类同步处理请求;必须先完成每个请求,然后才能开始下一个请求。

正如同一段所告诉您的,您可以通过使用分叉或线程混合来解决该问题。这很容易。


但是还有一个更大的问题。线程化的socketserver 服务器为每个连接的客户端创建一个单独的、完全独立的对象,并且无法在它们之间进行通信,甚至无法让它们相互了解。那么,你能做什么呢?

您始终可以自己构建它。将某种共享数据放在某处,并对其进行某种同步,所有线程都可以像任何线程一样相互通信,socketserver 或其他方式。

对于您的设计,queue 内置了我们需要的所有功能:客户端 1 可以put 队列中的消息(无论客户端 2 是否出现),客户端 2 可以@ 987654331@同一队列中的一条消息(如果消息还没有,则自动等待),并且全部自动同步。

最大的问题是:服务器如何知道谁是客户端 1 和谁是客户端 2?除非你想根据地址和端口进行切换,或者添加某种“登录”机制,否则我能想到的唯一规则就是先连接的人是客户端1,其次连接的人是客户端2,然后再连接的人,谁在乎,他们不属于这里。因此,我们可以使用带有Lock 的简单共享标志。

把它们放在一起:

class MyTCPHandler(socketserver.ThreadingMixIn, socketserver.BaseRequestHandler):
    q = queue.queue()
    got_first = False
    got_first_lock = threading.Lock()
    def handle_request(self):
        with MyTCPHandler.got_first_lock:
            if MyTCPHandler.got_first:
                 first = False
            else:
                 first = True
                 MyTCPHandler.got_first = True
        if first:
            self.data = self.request.recv(1024).strip()
            print("{} wrote:".format(self.client_address[0]))
            print(self.data)
            # just send back the same data, but upper-cased
            self.request.sendall(self.data.upper())
            # and also queue it up for client 2
            MyTCPHandler.q.put(self.data)
        else:
            # get the message off the queue, waiting if necessary
            self.data = MyTCPHandler.q.get()
            self.request.sendall(self.data)

如果您想构建一个更复杂的聊天服务器,每个人都可以在其中与每个人交谈……嗯,这会变得有点复杂,而且您将socketserver 延伸到超出其预期限制的范围。

我建议 (a) 降低到较低级别并手动编写线程或多路复用服务器,或者 (b) 转到更高级别、更强大的框架,以便更轻松地处理相互依赖的客户端。

stdlib 提供了一些用于编写服务器的替代方案,但除了asyncio 之外,所有替代方案都很糟糕——这很棒,但不幸的是全新的(它需要 3.4,它仍处于测试阶段,或者可以安装为3.3 的后端端口)。如果您不想在最前沿滑冰,有一些很棒的第三方选择,例如 twistedgevent。所有这些选项都比 socketserver 具有更高的学习曲线,但这只能通过更灵活和强大的东西来实现。

【讨论】:

    猜你喜欢
    • 2023-03-18
    • 1970-01-01
    • 2014-11-05
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-11
    • 2011-11-15
    • 1970-01-01
    相关资源
    最近更新 更多