2010-06-15 4 views
1

나는 select 호출을 사용하여 클라이언트로부터 멀티 플렉스 읽기를하는 tcp 서버를 가지고있다. 내가 들어오는 데이터 패킷파이썬 TCP 서버, 클라이언트에 쓰고 있니?

while(1) 

    rlist, wlist, xlist = select(input_sockets, output_sockets, [] , 1) 

    for insock in rlist: #any clients???? 

     if insock is server_socket: 
      new_socket, addr = server_socket.accept() 
      input_sockets.append(new_socket)  
      clients[insock.fileno()] = MClient(new_socket, addr, client_id) #dict of clients   
     else: 
      data = insock.recv(512) 
      if data: 
       clients[insock.fileno()].ProcessPacket(data) 
      else: 
       input_sockets.remove(insock) 
       del clients[insock.fileno()] 

    #handle writing to sockets 
    for outsock in wlist: 
     ....not done yet 



    #do some other stuff not associated with the socket 

내가 목록 'output_sockets'로 작성하는 방법을 다시 클라이언트, 즉 데이터를 전송 처리하는 방법에 대한 혼란 스러워요의 디코딩을 관리하는 클라이언트 클래스 (MClient)가 있습니다. Mclient 객체에 클라이언트에 다시 보낼 데이터가 있음을 나타내는 플래그를 설정하려고합니다. 내 서버 루프에서 각 클라이언트가이 플래그가 설정되어 있는지 확인한 다음 해당 소켓으로 output_list를 불러옵니다. 소켓을 쓸 수있게되면 적절한 클라이언트 쓰기 함수를 호출합니다.

이 구성표는 매우 우아하지 않지만 주 서버 루프에서 쓰는 것을 처리하고 싶습니다. 나는 어떻게 이것을 성취 할 것인가?

감사

+0

을,하지만 당신은 asyncore 살펴 있었다? 그것은 당신이 가진 것과 같은 서버를 다루는 표준 파이썬 모듈입니다. – Krumelur

+0

감사합니다 Krumelur, 나는 그것을 보았습니다. 그러나 주 서버 루프에서 다른 것들을 처리해야하고 asyncore로 그 일을하는 방법을 보지 못했습니다. – mikip

+0

힌트 - 전달할 수있는 'count'및 'timeout'매개 변수를보십시오. asyncore.loop. – Kylotan

답변

0

당신이 당신의 첫 번째 단락에 기술 구현은 select을 사용하여 서버를 구현하는 기존의 방법처럼 들린다.

당신이하는 당신이 같은 보이는 코드를 가진 의미 가정, "메인 서버 루프"의 클라이언트에 쓸 수 있도록하려면 : 당신이해야 다음

request = socket.recv() 
response = process_request(request) 
socket.send(response) 

을 클라이언트 당 별도의 스레드.

+0

감사합니다 jchl, 나는 그것을 멀티 스레드로 만들고 싶지 않았습니다, 나의 간단한 내용은 단일 스레드로 유지하는 것이 었습니다. – mikip

1

하나의 스레드로 여러 연결을 처리하는 방법을 배우려면 잠깐 쓴 것이 있습니다. 결코 완벽하지는 않지만 원하는 것을 보여줍니다. 클라이언트 객체는 연결의 읽기 및 쓰기 스트림을 관리하고 서버에 올바른 select() 목록에 클라이언트 소켓이 있는지 확인합니다. 이것은 메시지가 개행 문자로 끝나는 간단한 프로토콜을 구현합니다. pumpXXXX() 함수는 스트림 읽기/쓰기를 차단하고 읽기/쓰기 버퍼를 관리합니다. 완전한 메시지는 버퍼에 개행 문자가있는 경우에만 처리됩니다.

import socket 
import select 

class Client(object): 

    '''This object is created for each client connection. It tracks 
    what has been read, what has been written, and processes complete 
    messages terminated by newlines. It responds by returning the 
    original message wrapped in square brackets and terminated by a 
    newline. ''' 

    def __init__(self,who,sock,server): 

     '''who - client address 
     sock - client socket 
     server - server object for this client 
     ''' 

     self.who = who 
     self.readbuf = '' 
     self.writbuf = '' 
     self.server = server 
     self.sock = sock 

    def close(self): 

     '''Removes client from server's reader/writer queues and 
     closes the connection.''' 

     self.sock.close() 
     if self.sock in self.server.readers: 
      self.server.readers.remove(self.sock) 
     if self.sock in self.server.writers: 
      self.server.writers.remove(self.sock) 
     self.server.data.pop(self.sock) 

    def pumprecv(self): 

     '''Server calls pumprecv() when something is readable from the 
     client socket. The data is appended to the client's read 
     buffer.mro Complete messages (if any) are then removed from 
     the buffer and processed.''' 

     try: 
      tmp = self.sock.recv(1000) 
     except socket.error,e: 
      print 'recv',e 
      self.close() 
     else:     
      if tmp: 
       self.readbuf += tmp 

       # Complete messages are processed 
       while '\n' in self.readbuf: 
        msg,self.readbuf = self.readbuf.split('\n',1) 
        print self.who,msg 
        self.writbuf += '[' + msg + ']\n' 
        # New data to send. Make sure client is in the 
        # server's writer queue. 
        if self.sock not in self.server.writers: 
         self.server.writers.append(self.sock) 
      else: 
       self.close() 

    def pumpsend(self): 
     try: 
      # send some data. tmp is #chars sent (may not be all in writbuf). 
      tmp = self.sock.send(self.writbuf) 
     except socket.error,e: 
      print 'send:',e 
      self.close() 
     else: 
      # Removed sent characters from writbuf. 
      self.writbuf = self.writbuf[tmp:] 
      # If writbuf is empty, remove socket from server's write queue. 
      if not self.writbuf: 
       self.server.writers.remove(self.sock) 

class Server(object): 
    def __init__(self,ip='127.0.0.1',port=9999): 
     self.ssock = socket.socket() 
     self.ssock.bind((ip,port)) 
     self.ssock.listen(5) 
     self.readers = [self.ssock] 
     self.data = {} 
     self.writers = [] 
     self.quit = False 

    def pumpaccept(self): 

     '''Called when server socket is readable to accept a 
     connection and create a Client object.''' 

     csock,who = self.ssock.accept() 
     print 'Connected %s:%d' % who 
     self.readers.append(csock) 
     self.data[csock] = Client(who,csock,self) 

    def serve(self): 
     while not self.quit or self.writers: 
      readable,writable,other = select.select(self.readers,self.writers,[],1.0) 
      # Operate on copies of the queues since the pumpXXX() commands can modify the lists. 
      if self.ssock in readable[:]: 
       self.pumpaccept() 
       readable.remove(self.ssock) 
      for reader in readable[:]: 
       self.data[reader].pumprecv() 
      for writer in writable[:]: 
       self.data[writer].pumpsend() 

      if not readable and not writable and not other: 
       print '.', 

if __name__ == '__main__': 
    srv = Server() 
    srv.serve() 

나는 하나의 콘솔에서 서버를 시작하고, 다중 연결을 테스트하기 위해 다른 콘솔에서 다음 코드를 실행하여 테스트. 여러 개의 연결을 만들고 다른 창에서 대체 보내기를 보내고 부분 메시지를 보내 서버가 응답하는 방식을 확인합니다.

>>> from socket import * 
>>> s=socket() 
>>> s.connect(('localhost',9999)) 
>>> s.send('one\ntwo\nthree') 
13 
>>> s.send('\nfour\n') 
6 
>>> s.recv(1024) 
'[one]\n[two\three]\n[four]\n' 
>>> s.close() 

출력과 같이 보일 것입니다 : 이것은 약간 질문의 범위를 벗어날 수 있습니다

. . . . . . . . . . . . . . . . . . . Connected 127.0.0.1:1514 
. . . . . . . . . ('127.0.0.1', 1514) one 
. . . . . . . ('127.0.0.1', 1514) two 
. . . ('127.0.0.1', 1514) three 
('127.0.0.1', 1514) four 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
관련 문제