Python 3.x 中的 client(1) to server to client(2)(套接字?)



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

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

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文档几乎没有变化:

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)

首先,一个基本socketserver.TCPServer甚至不能同时与两个客户端交谈。正如文档所解释的那样:

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

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


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

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

对于您的设计,queue具有内置的所有魔力,可以满足我们所需的一切:客户端 1 可以在队列中put一条消息(无论客户端 2 是否出现),客户端 2 可以将消息从同一队列中get(如果消息尚未出现,则自动等待), 这一切都是自动同步的。

最大的问题是:服务器如何知道谁是客户端 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,但这只能从更灵活和更强大的东西中得到期望。

相关内容

  • 没有找到相关文章

最新更新