简体   繁体   English

客户端(1)到Python 3.x中的服务器到客户端(2)(套接字?)

[英]Client(1) to Server to Client(2) in Python 3.x (Sockets?)

I've been working with a project that involves sending information to a public server (to demonstrate how key-exchange schemes work) and then sending it to a specific client. 我一直在处理一个项目,该项目涉及向公共服务器发送信息(以演示密钥交换方案如何工作),然后将其发送给特定客户端。 There is only two clients. 只有两个客户。

I'm hoping to get pushed in the right direction on how to get information from client(1) to the server, then have the server redirect that information to client(2). 我希望能够在如何从客户端(1)获取信息到服务器方面朝着正确的方向前进,然后让服务器将该信息重定向到客户端(2)。 I've messed with the code somewhat, getting comfortable with how to send and recieve information from the server, but I have no idea (~2 hours of research so far) how to differentiate clients and send information to specific clients My current server code (pretty much unchanged from the python3 docs : 我有点搞砸了代码,对如何从服务器发送和接收信息感到满意,但我不知道(到目前为止大约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()

My client code (pretty much unchanged from the python3 docs : 我的客户端代码(与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)

First, a base socketserver.TCPServer can't even talk to two clients at the same time. 首先,基本的socketserver.TCPServer甚至无法同时与两个客户端通信。 As the docs explain: 正如文档解释:

These four classes process requests synchronously; 这四个类同步处理请求; each request must be completed before the next request can be started. 必须在下一个请求开始之前完成每个请求。

As the same paragraph tells you, you can solve that problem by using a forking or threading mix-in. 正如同一段落告诉您的那样,您可以通过使用分叉或线程混合来解决该问题。 That's pretty easy. 这很简单。


But there's a bigger problem. 但是有一个更大的问题。 A threaded socketserver server creates a separate, completely independent, object for each connected client, and has no means of communicating between them, or even letting them find out about each other. 线程socketserver服务器服务器为每个连接的客户端创建一个单独的,完全独立的对象,并且无法在它们之间进行通信,甚至让它们相互了解。 So, what can you do? 所以,你可以做什么?

You can always build it yourself. 你总是可以自己构建它。 Put some kind of shared data somewhere, and some kind of synchronization on it, and all of the threads can talk to each other the same way any threads can, socketserver or otherwise. 在某处放置某种共享数据,并在其上进行某种同步,并且所有线程可以以任何线程, socketserver或其他方式相同的方式相互socketserver

For your design, a queue has all the magic built in for everything we need: client 1 can put a message on the queue (whether client 2 has shown up yet or not), and client 2 can get a message off the same queue (automatically waiting around if the message isn't there yet), and it's all automatically synchronized. 对于您的设计, queue具有我们需要的所有内容:客户端1可以在队列上put消息(客户端2是否已经显示),客户端2可以get同一队列中get消息(如果消息还没有,则自动等待,并且全部自动同步。

The big question is: how does the server know who's client 1 and who's client 2? 最大的问题是:服务器如何知道谁是客户1以及谁是客户2? Unless you want to switch based on address and port, or add some kind of "login" mechanism, the only rule I can think of is that whoever connects first is client 1, whoever connects second is client 2, and anyone who connects after that, who cares, they don't belong here. 除非您想根据地址和端口进行切换,或者添加某种“登录”机制,否则我能想到的唯一规则是,首先连接的是客户端1,连接第二个的是客户端2,以及之后连接的任何人谁在乎,他们不属于这里。 So, we can use a simple shared flag with a Lock on it. 因此,我们可以使用一个带有Lock的简单共享标志。

Putting it all together: 把它们放在一起:

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)

If you want to build a more complicated chat server, where everyone talks to everyone… well, that gets a bit more complicated, and you're stretching socketserver even farther beyond its intended limits. 如果你想构建一个更复杂的聊天服务器,每个人都与每个人交谈...好吧,这会变得有点复杂,而且你的socketserver甚至超出了预期的限制范围。

I would suggest either (a) dropping to a lower level and writing a threaded or multiplexing server manually, or (b) going to a higher-level, more-powerful framework that can more easily handle interdependent clients. 我建议(a)降低到较低级别并手动编写线程或多路复用服务器,或者(b)转到更高级别,更强大的框架,以便更轻松地处理相互依赖的客户端。

The stdlib comes with a few alternatives for writing servers, but all of them suck except for asyncio —which is great, but unfortunately brand new (it requires 3.4, which is still in beta, or can be installed as a back-port for 3.3). stdlib有一些用于编写服务器的替代方案,但除了asyncio之外它们asyncio - 这很不错,但不幸的是全新的(它需要3.4,仍处于测试阶段,或者可以安装为3.3的后端口) )。 If you don't want to skate on the bleeding edge, there are some great third-party choices like twisted or gevent . 如果你不想在最前沿滑冰,那么有一些伟大的第三方选择,如twistedgevent All of these options have a higher learning curve than socketserver , but that's only to be expected from something much more flexible and powerful. 所有这些选项都具有比socketserver更高的学习曲线,但这只能通过更加灵活和强大的功能来实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM