2009-08-05 4 views
4

어떻게하면 간단한 서버를 만들 수 있습니까? (연결을 수락하고 터미널에 인쇄 할 때처럼 간단합니다) 여러 포트 또는 포트 범위에서 연결을 수락 하시겠습니까?여러 포트에서 서버가 연결을 수락하는 방법?

바인드 호출마다 하나씩 여러 개의 스레드를 사용해야합니까? 아니면 다른 해결책이 있습니까?

간단한 서버는 다음과 유사 할 수 있습니다.

def server(): 
import sys, os, socket 

port = 11116 
host = '' 
backlog = 5 # Number of clients on wait. 
buf_size = 1024 

try: 
    listening_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    listening_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 
    listening_socket.bind((host, port)) 
    listening_socket.listen(backlog) 
except socket.error, (value, message): 
    if listening_socket: 
     listening_socket.close() 
    print 'Could not open socket: ' + message 
    sys.exit(1) 

while True: 
    accepted_socket, adress = listening_socket.accept() 

    data = accepted_socket.recv(buf_size) 
    if data: 
     accepted_socket.send('Hello, and goodbye.') 
    accepted_socket.close() 

server() 

편집

: 이 그것을 할 수있는 방법의 예입니다. 모두에게 감사드립니다.

import socket, select 

def server(): 
import sys, os, socket 

port_wan = 11111 
port_mob = 11112 
port_sat = 11113 

sock_lst = [] 
host = '' 
backlog = 5 # Number of clients on wait. 
buf_size = 1024 

try: 
    for item in port_wan, port_mob, port_sat: 
     sock_lst.append(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) 
     sock_lst[-1].setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 
     sock_lst[-1].bind((host, item)) 
     sock_lst[-1].listen(backlog) 
except socket.error, (value, message): 
    if sock_lst[-1]: 
     sock_lst[-1].close() 
     sock_lst = sock_lst[:-1] 
    print 'Could not open socket: ' + message 
    sys.exit(1) 

while True: 
    read, write, error = select.select(sock_lst,[],[]) 

    for r in read: 
     for item in sock_lst: 
      if r == item: 
       accepted_socket, adress = item.accept() 

       print 'We have a connection with ', adress 
       data = accepted_socket.recv(buf_size) 
       if data: 
        print data 
        accepted_socket.send('Hello, and goodbye.') 
       accepted_socket.close() 

server() 

답변

6

나는 파이썬 사람이 아니지만 관심있는 기능은 "선택"입니다. 이렇게하면 여러 개의 소켓을 볼 수 있으며 그 중 하나에서 활동이 발생하면 중단됩니다.

여기는 python example that uses select입니다.

+3

저는 파이썬 사람이고 선택해야합니다. http://docs.python.org/library/select.html –

+0

고마워요. Se 예제 코드에 대한 원래 게시물 – Orjanp

1

프로그래머 (평가 관점이 아닌)에서 실제로 게으르려면 블록 읽기에 시간 초과를 설정하고 모든 소켓을 반복하면됩니다. 시간 초과가 발생하면 사용 가능한 데이터가 없습니다. 기능적으로 이것은 select이하는 것과 비슷하지만, OS에서 벗어나 응용 프로그램에 넣고 있습니다.

물론 이것은 수면 시간이 짧아짐에 따라 프로그램이 100 % CPU 사용량에 접근하므로 프로덕션 앱에서 사용하지 않을 것임을 의미합니다. 장난감이라도 괜찮습니다.

그것은이 같은 갈 것이다 : 파이썬의 너무 많은 오버 헤드를 가지고 있기 때문에 (하지 테스트)

def server(): 
    import sys, os, socket 

    port = 11116 
    host = '' 
    backlog = 5 # Number of clients on wait. 
    buf_size = 1024 
    NUM_SOCKETS = 10 
    START_PORT = 2000 

    try: 
      socket.setdefaulttimeout(0.5) # raise a socket.timeout error after a half second 
      listening_sockets = [] 
      for i in range(NUM_SOCKETS): 
       listening_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
       listening_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 
       listening_socket.bind((host, START_PORT + i)) 
       listening_socket.listen(backlog) 
       listening_sockets.append(listening_socket) 
    except socket.error, (value, message): 
      if listening_socket: 
        listening_socket.close() 
      print 'Could not open socket: ' + message 
      sys.exit(1) 

    while True: 
      for sock in listening_sockets: 
       try: 
        accepted_socket, adress = sock_socket.accept() 

        data = sock.recv(buf_size) 
        if data: 
          sock_socket.send('Hello, and goodbye.') 
        sock.close() 
       except socket.timeout: 
        pass 

    server() 
+1

직접 선택을 구현하는 이유는 무엇입니까? 내장 된 선택 모듈이 이것보다 간단하지 않습니까? –

+0

감사합니다. select는 적은 CPU를 사용하기 때문에 추측합니다. 나는 그 해결책을 찾아 갔다. – Orjanp

+0

나는 그것을 단순하게 회상하지 않는다. 하지만 이제 좀 더 생각해 보았습니다. 파이썬이 아니라 C에서 일하고있는 꽤 좋은 기회입니다. ( –

2

을, 멀티 스레드 애플리케이션은 논쟁의 큰 포인트입니다. 그렇다면 전체적인 차단 - 운영 - GIL 문제도 있습니다. 운좋게도 의 파이썬 모토는 "큰 문제처럼 보인다면 누군가가 이미 해결책을 찾았을 것입니다 (또는 여러 개!)"이 여기에 해당됩니다. 제가 가장 좋아하는 솔루션은 마이크로 스레드 모델, 특히 gevent입니다.

Gevent는 원숭이 패치를 통해 사용자를 위해 대부분의 문제를 처리하는 이벤트 기반 단일 스레드 동시성 라이브러리입니다. gevent.monkey.patch_socket()은 일반 소켓 호출을 비 차단 변종, 폴링 및 절전 모드로 바꿔 필요한 다른 그린렛으로의 전환을 허용하는 기능입니다. 더 많은 제어를 원한다면, 또는 당신을 위해 자르지 않을 것입니다. select와 gevent의 협조적인 수율로 스위칭을 쉽게 관리 할 수 ​​있습니다.

다음은 간단한 예입니다. 포트 1024에서 2048 사이에 일반 텍스트 We got your message!를 제공하는 슈퍼 간단한 완전히 검증되지 않은 서버가 될 것

import gevent 
import socket 
import gevent.monkey; gevent.monkey.patch_socket() 

ALL_PORTS=[i for i in xrange(1024, 2048)] 
MY_ADDRESS = "127.0.0.1"  

def init_server_sock(port): 
    try: 
     s=socket.socket() 
     s.setblocking(0) 
     s.bind((MY_ADDRESS, port)) 
     s.listen(5) 
     return s 
    except Exception, e: 
     print "Exception creating socket at port %i: %s" % (port, str(e)) 
     return False 

def interact(port, sock): 
    while 1: 
     try: 
      csock, addr = sock.accept() 
     except: 
      continue 
     data = "" 
     while not data: 
      try: 
       data=csock.recv(1024) 
       print data 
      except: 
       gevent.sleep(0) #this is the cooperative yield 
     csock.send("Port %i got your message!" % port) 
     csock.close() 
     gevent.sleep(0) 


def main(): 
    socks = {p:init_server_sock(p) for p in ALL_PORTS} 
    greenlets = [] 
    for k,v in socks.items(): 
     if not v: 
      socks.pop(k) 
     else: 
      greenlets.append(gevent.spawn(interact, k, v)) 

    #now we've got our sockets, let's start accepting 
    gevent.joinall(greenlets) 

. select를 포함시키는 것이 조금 어렵습니다. 당신은 select를 호출 한 다음 활성화 된 것을 시작하는 매니저 greenlet을 가져야 할 것입니다; 하지만 구현하기가 어렵지 않습니다.

희망이 도움이됩니다. Greenlet 기반 철학의 좋은 점은 선택 호출이 사실상 허브 모듈의 일부라는 점입니다. 이는 내가 더 많이 확장 가능하고 복잡한 서버를 더 쉽게 만들 수 있도록합니다. 그것은 너무 효율적입니다. 주위에 떠있는 몇 가지 벤치 마크가 있습니다.