簡體   English   中英

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

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

我一直在處理一個項目,該項目涉及向公共服務器發送信息(以演示密鑰交換方案如何工作),然后將其發送給特定客戶端。 只有兩個客戶。

我希望能夠在如何從客戶端(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或其他方式相同的方式相互socketserver

對於您的設計, queue具有我們需要的所有內容:客戶端1可以在隊列上put消息(客戶端2是否已經顯示),客戶端2可以get同一隊列中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之外它們asyncio - 這很不錯,但不幸的是全新的(它需要3.4,仍處於測試階段,或者可以安裝為3.3的后端口) )。 如果你不想在最前沿滑冰,那么有一些偉大的第三方選擇,如twistedgevent 所有這些選項都具有比socketserver更高的學習曲線,但這只能通過更加靈活和強大的功能來實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM