하나의 스레드로 여러 연결을 처리하는 방법을 배우려면 잠깐 쓴 것이 있습니다. 결코 완벽하지는 않지만 원하는 것을 보여줍니다. 클라이언트 객체는 연결의 읽기 및 쓰기 스트림을 관리하고 서버에 올바른 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
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
을,하지만 당신은 asyncore 살펴 있었다? 그것은 당신이 가진 것과 같은 서버를 다루는 표준 파이썬 모듈입니다. – Krumelur
감사합니다 Krumelur, 나는 그것을 보았습니다. 그러나 주 서버 루프에서 다른 것들을 처리해야하고 asyncore로 그 일을하는 방법을 보지 못했습니다. – mikip
힌트 - 전달할 수있는 'count'및 'timeout'매개 변수를보십시오. asyncore.loop. – Kylotan