2014-01-07 3 views
0

필자는 공개 서버에 정보를 보내고 (키 교환 방식의 작동 방식을 보여주기 위해) 그것을 특정 클라이언트로 보냅니다. 단 두 명의 고객이 있습니다.파이썬 3.x에서 클라이언트 (1)에서 서버 (2) 클라이언트 (2)

클라이언트 (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) 
+0

그리고? 문서에서 변경되지 않은 코드를 붙여 넣는 작업을 수행했습니다. 해당 코드에 대한 질문이 있으십니까? – abarnert

+0

@abarnert 클라이언트 (1)에서 서버로 정보를 가져 오는 방법에 대한 올바른 방향으로 밀어 넣기를 바라고, 그런 다음 서버가 해당 정보를 클라이언트 (2)로 리디렉션하도록합니다. 코드를 다소 복잡하게 만들었지 만 서버에서 정보를 보내고받는 방법에 익숙해졌지만 클라이언트를 차별화하고 특정 클라이언트에게 정보를 보내는 방법을 알지 못했습니다. – user2719977

+0

'socketserver'는 실제로 그런 식으로 사용하기위한 것이 아닙니다. 배우기 쉽고, 소스를 만드는 것이 쉽지 않습니다 (http://hg.python.org/cpython/file/3.3 /Lib/socketserver.py)보다 복잡한 프로젝트의 샘플 코드로 이해하기 쉽습니다. 클라이언트 간 통신에 도움이되는 프레임 워크가 있지만 '소켓 서버'는 그 중 하나가 아닙니다. 즉, 내가 대답에서 설명했듯이, 당신이 원하는 것은 ~ 할 수 있습니다 ...하지만 훨씬 더 복잡해지기를 원한다면 아마도 '소켓 서버'를 넘어서고 싶을 것입니다. – abarnert

답변

2

는 첫째, socketserver.TCPServer도 같은 두 개의 클라이언트에게 말할 수 없어 기본 시간 : the docs 설명 :

이 네 가지 클래스는 요청을 동 기적으로 처리합니다. 각 요청은 완료되어야 다음 요청을 시작할 수 있습니다.

같은 단락에서 알 수 있듯이 포크 또는 스레딩 믹스 인을 사용하여이 문제를 해결할 수 있습니다. 꽤 쉽습니다.


하지만 더 큰 문제가 있습니다. 스레드 된 socketserver 서버는 연결된 각 클라이언트에 대해 완전히 독립적 인 별도의 개체를 만들고 서로 통신하거나 서로에 대해 알 수있게하는 수단이 없습니다. 그래서, 당신은 무엇을 할 수 있습니까?

언제든지 직접 제작할 수 있습니다. 어떤 종류의 공유 ​​데이터를 어딘가에 넣고 어떤 종류의 동기화를 수행하면 모든 스레드가 어떤 스레드와도 동일한 방식으로 서로 대화 할 수 있습니다. socketserver 또는 그 밖의 방법으로 수행 할 수 있습니다. 귀하의 디자인에 대 한

하는 queue은 우리가 필요로하는 모든 것을 내장 모든 마법이있다 : 클라이언트 일 수 put A (클라이언트 2는 아직 여부를 찾았 여부) 큐에 메시지 및 클라이언트가 둘 수 get 메시지 해제 동일한 대기열 (메시지가 아직없는 경우 자동으로 대기)이며 모두 자동으로 동기화됩니다.

큰 질문은 다음과 같습니다. 서버가 클라이언트 1과 클라이언트 2를 어떻게 알 수 있습니까? 주소와 포트를 기반으로 전환하거나 일종의 "로그인"메커니즘을 추가하고 싶지 않다면 내가 생각할 수있는 유일한 규칙은 먼저 연결하는 사람은 클라이언트 1이고 두 번째 연결 사람은 클라이언트 2이고 그 뒤에 연결하는 사람 , 누가 상관, 그들은 여기에 속하지 않습니다. 따라서 간단한 공유 플래그를 Lock과 함께 사용할 수 있습니다.

모두 함께 퍼팅 : 좀 더 복잡해진다, 당신은 심지어 멀리 socketserver을 스트레칭하고

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) 

모든 사람이 모든 사람에게 이야기 더 복잡한 채팅 서버를 구축하려면 ... 음, 의도 한도를 초과합니다.

낮은 수준으로 떨어지고 수동으로 서버에 멀티 쓰레딩하거나 스레드를 작성하거나 (b) 상호 의존적 인 클라이언트를보다 쉽게 ​​처리 할 수있는 더 높은 수준의보다 강력한 프레임 워크로 이동할 것을 제안합니다.

stdlib에는 서버 작성을위한 몇 가지 대안이 있지만, 모두 asyncio을 제외하고 빨기는하지만 훌륭합니다.하지만 불행히도 아주 새로운 것입니다 (아직 3.4가 필요하며 아직 베타 버전이거나 뒤로 설치할 수 없습니다). -port for 3.3). 출혈을 피하기 위해 스케이트를 타지 않으려면 twisted 또는 gevent과 같은 훌륭한 타사 선택 사항이 있습니다. 이 모든 옵션은 학습 곡선이 socketserver보다 높지만 훨씬 유연하고 강력한 것으로 기대됩니다.

관련 문제