2011-08-23 3 views
1

여러 클라이언트로 간단한 서버를 구현하려고합니다. 그것은 필요한 소켓에서 데이터를 수신하고 처리 한 다음 다른 클라이언트로 데이터를 보내야합니다. Python 표준 라이브러리에서 select 모듈을 사용합니다.여러 클라이언트가있는 간단한 서버

class ProcessingServer: 
    def __init__(self, bindaddress="localhost", portname=50001, maxqueue=5): 
     self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.socket.bind((bindaddress, portname)) 
     self.socket.listen(maxqueue) 
     self.inputsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.data = "" 

    def connect_to_output(self, address, port): 
     self.inputsocket.connect((address, port)) 

    def start(self): 
     rsocks = [] 
     wsocks = [] 
     rsocks.append(self.socket) 
     wsocks.append(self.inputsocket) 
     self.socket.accept() 

     while True: 
      try: 
       reads, writes, errs = select.select(rsocks, wsocks, []) 
      except: 
       return 
      for sock in reads: 
       if sock == self.socket: 
        client, address = sock.accept() 
        rsocks.append(client) 
       else: 
        self.socket.send(self.data) 
        rsocks.remove(sock) 
      for sock in writes: 
       if sock == self.inputsocket: 
        self.data = sock.recv(512) 
        wsocks.remove(sock) 
        print repr(self.data) 

여기 간단한 클라이언트 : 서버의 일부를 받기

import socket 
mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
mysocket.connect(("localhost", 50001)) 
while True: 
    data = mysocket.recv(512) 
    print repr(data) 
mysocket.close() 

가 잘 작동하지만 서버가 출력을 생성하지 않습니다 다음은 서버입니다. 나는 네트워크 프로그래밍에 전혀 경험이 없으며 뭔가를 놓친 것 같아. 대신

+0

(속삭임) __twisted__ –

+0

고마워,하지만 가능한 한 간단하게하고 싶다.) – qutron

+0

Twisted는 소켓을 사용하는 것보다 훨씬 간단하다. 스레드에 대해 걱정할 필요조차 없습니다. Twisted는 재즈를 연주하는 __all__을합니다. –

답변

2

에 이상한 것 몇 가지가 있습니다 당신의 스크립트.

선택 모듈의 표준 사용법은 다음과 같습니다. 연결을 청취 할 소켓이 하나 있고 클라이언트와 연결 당 소켓이 하나 있습니다.

처음에는 잠재적 인 독자 목록에이 소켓 만 추가되고 잠재적 작성자 목록은 비어 있습니다.

호출 select.select (potential_readers는, potential_writers는 potential_errors)이 3 개에는 반환합니다 - 작성하기위한 준비 소켓 - - 를 읽는 소켓 준비를 읽기위한 준비 소켓의 목록에서 오류

에서 소켓을, 소켓이 접속을 대기하는 소켓 인 경우, 소켓을 받아 들여, 잠재적 인 기입 해, 잠재적 인 기입 해 및 잠재적 인 에러에 새로운 소켓을 넣지 않으면 안됩니다.

소켓이 다른 소켓이면이 소켓에서 읽을 데이터가 있습니다. 당신은 sock.recv (길이)에 전화를 걸어.

데이터를 보내려면 select.select에서 반환 한 wlist에서 보내야합니다.

errlist는 자주 사용되지 않습니다.

import socket, select 

sock_producer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock_producer.bind(('localhost', 5000)) 
sock_producer.listen(5) 
producers = []  

clients = [] 
sock_consumer_listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
# Note: different port to differentiate the clients who receive data from the one who sends messages 
sock_consumer_listener.bind(('localhost', 5001)) 

rlist = [sock_producer, sock_listener] 
wlist = [] 
errlist = [] 

out_buffer = [] 

while True: 
    r, w, err = select.select(rlist, wlist, errlist) 
    for sock in r: 
     if sock == sock_producer: 
      prod, addr = sock.accept() 
      producers.append(prod) 
      rlist.append(prod) 
     elif sock == sock_consumer_listener: 
      cons, addr = sock.accept() 
      clients.append(cons) 
      wlist.append(cons) 
     else: 
      out_buffer.append(sock.recv(1024)) 

    out_string = ''.join(out_buffer) 
    out_buffer = [] 

    for sock in w: 
     if sock in clients: 
      sock.send(out_string) 

이 코드를 이렇게 테스트하지 않았습니다 :


지금, 당신의 문제, (내가 잘 이해하는 경우) 당신이 당신의 프로토콜을 설명하는 방법에 대한 솔루션을, 그것과 같을 수 있습니다 몇 가지 오류가있을 수 있지만 이것이 내가 어떻게 할 것인가에 가깝습니다.

+0

+1 "_ 메시지를 보내는 사람과 데이터를받는 클라이언트를 구별하는 다른 포트"_ 예. 어느 날, 나는 그것을 이해하기 전에 몇 시간을 보냈다. 그것은 문서들과 튜토리얼들에서 밑줄이 잘 벗겨지지 않습니다. – eyquem

+0

@Martin : 나는 그것을 얻지 못합니다. 하나의 소켓 - 데이터 소스가 있습니다. 원본 소켓은 클라이언트 소켓이며 서버를 시작하자마자 연결하려고합니다. (예제에서는 inputsocket). 다른 소켓은 들어오는 연결을 수신하는 소켓입니다. 그러나 여러분의 예제에는 sock_producer, sock_listener라는 두 개의 "서버"소켓이 있습니다. 좀 더 설명해 주시겠습니까? – qutron

+0

@qutron : 데이터 소스는 하나의 소켓입니다. 필자의 경우 소스 소켓은 제작자이다. 나는 어딘가에 연결하는 대신 듣는다. 그러나 듣기 대신에 연결하고 (블록을 ​​듣지 말고 연결) 블록을 제거하는 것이 쉽다.'sock == sock_producer : ... ' – Martin

2

그래 ... 사용 zeromq :

server.py

import zmq 
context = zmq.Context() 
socket = context.socket(zmq.REP) 
socket.bind("tcp://127.0.0.1:50001") 

while True: 
    msg = socket.recv() 
    print "Got", msg 
    socket.send(msg) 

client.py

import zmq 
context = zmq.Context() 
socket = context.socket(zmq.REQ) 
socket.connect("tcp://127.0.0.1:50001") 

for i in range(100): 
    msg = "msg %s" % i 
    socket.send(msg) 
    print "Sending", msg 
    msg_in = socket.recv() 
+0

아직 공개 인터넷에 zeromq을 설치하는 것이 안전할까요? 올해 초 악의적 인 당사자가 기형적 인 데이터를 변조하여 청취자를 추락시킬 수 있기 때문에 그렇지 않았습니다. –

+0

당신이 뭘 말하고 있는지 잘 모르십니까? 링크? 내가 손으로 낮은 수준의 소켓 물건을하려고보다 더 안정 될거라고 상상할 것이다. 좀 더 튼튼한 것을 원한다면 뒤틀린 것이 길일지도 모릅니다. – zeekay

+0

예 : 언급 된 두 가지 문제는 수정 된 것으로 보입니다 (슬프게도 링크가 깨져서 완전히 명확하지는 않습니다). 인터넷 검색 중 1-2 분만에 해당 게시물을 발견했습니다. 추가 검색을하면 다른 유사한 문제가 나타날 수 있습니다. –

관련 문제