>
소켓 프로그래밍에서 청취 소켓을 생성 한 다음 연결하는 각 클라이언트에 대해 클라이언트 요청을 처리하는 데 사용할 수있는 일반 스트림 소켓을 얻습니다. OS는 무대 뒤에서 들어오는 연결 대기열을 관리합니다.

두 개의 프로세스는 같은 포트에 동시에 바인딩 할 수 없습니다-기본적으로 어쨌든

잘 알려진 OS, 특히 Windows에서 프로세스의 여러 인스턴스를 시작하여 소켓에 바인딩하여 큐를 효과적으로 공유 할 수있는 방법이 있는지 궁금합니다. 각 프로세스 인스턴스는 단일 스레드 일 수 있습니다. 새 연결을 수락하면 차단됩니다. 클라이언트가 연결되면 유휴 프로세스 인스턴스 중 하나가 해당 클라이언트를 수락합니다.

이것은 각 프로세스가 매우 단순한 단일 스레드 구현을 가능하게하며 명시적인 공유 메모리를 통해서는 아무것도 공유하지 않으며 사용자는 더 많은 인스턴스를 시작하여 처리 대역폭을 조정할 수 있습니다.

이러한 기능이 있습니까?

수정 :"쓰레드를 사용하지 않는 이유는 무엇입니까?" 분명히 스레드는 옵션입니다. 그러나 단일 프로세스에서 여러 스레드를 사용하면 모든 개체를 공유 할 수 있으며 개체가 공유되지 않거나 한 번에 하나의 스레드에만 표시되거나 절대적으로 변경할 수 없으며 가장 인기있는 언어와 런타임에는 이러한 복잡성 관리를위한 기본 지원 기능이 없습니다.

소수의 동일한 작업자 프로세스를 시작하면default가 공유하지 않는 동시 시스템이 생겨서 정확하고 확장 가능한 구현을 훨씬 쉽게 구축 할 수 있습니다

  • 답변 # 1

    Linux와 Windows의 두 개 이상의 프로세스간에 소켓을 공유 할 수 있습니다.

    fork() 를 사용하는 Linux (또는 POSIX 유형 OS)에서  갈래의 아이가 부모의 모든 파일 디스크립터의 사본을 갖도록합니다. 닫히지 않은 것은 계속 공유되며 (예를 들어 TCP 수신 소켓과 함께) accept() 에 사용할 수 있습니다  클라이언트를위한 새로운 소켓. 이것은 대부분의 경우 Apache를 포함하여 몇 대의 서버가 작동하는지입니다.

    Windows에서는 fork() 가 없다는 것을 제외하고는 기본적으로 같은 것이 사실입니다.  시스템 호출이므로 부모 프로세스는 CreateProcess 를 사용해야합니다.  또는 자식 프로세스 (물론 동일한 실행 파일을 사용할 수 있음)를 생성 할 수 있으며 상속 가능한 핸들을 전달해야합니다.

    청취 소켓을 상속 가능한 핸들로 만드는 것은 완전히 사소한 활동은 아니지만 너무 까다로운 것도 아닙니다. 와이즈 비즈  상속 가능한 플래그가 설정된 중복 핸들을 만드는 데 사용해야합니다 (여전히 부모 프로세스에는 있음). 그런 다음 DuplicateHandle() 에서 그 핸들을 줄 수 있습니다.  CreateProcess에서 자식 프로세스를 STARTUPINFO 로 구조화 STDIN  또는 OUT  처리합니다 (다른 용도로는 사용하고 싶지 않다고 가정).

    수정 :

    MDSN 라이브러리를 읽으면 ERR 로 보입니다.  이 작업을 수행하는보다 강력하고 올바른 메커니즘입니다. 부모/자식 프로세스가 일부 IPC 메커니즘에 의해 복제되어야하는 핸들을 해결해야하기 때문에 여전히 중요하지 않습니다 (파일 시스템의 파일처럼 간단 할 수는 있지만)

    설명 :

    OP의 원래 질문에 대한 대답으로, 여러 프로세스가 WSADuplicateSocket 를 수행 할 수 없습니다. ;원래 부모 프로세스 만 bind() 를 호출합니다. bind()  등, 자식 프로세스는 listen() 에 의해 요청을 처리합니다. accept() send()  등.

  • 답변 # 2

    대부분의 사람들은 이것이 작동하는 기술적 이유를 제공했습니다. 다음은이를 직접 보여주기 위해 실행할 수있는 파이썬 코드입니다.

    recv()
    
    

    실제로 두 개의 프로세스 ID 청취가 있습니다 :

    import socket
    import os
    def main():
        serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        serversocket.bind(("127.0.0.1", 8888))
        serversocket.listen(0)
        # Child Process
        if os.fork() == 0:
            accept_conn("child", serversocket)
        accept_conn("parent", serversocket)
    def accept_conn(message, s):
        while True:
            c, addr = s.accept()
            print 'Got connection from in %s' % message
            c.send('Thank you for your connecting to %s\n' % message)
            c.close()
    if __name__ == "__main__":
        main()
    
    

    telnet과 프로그램을 실행 한 결과는 다음과 같습니다.

    $ lsof -i :8888
    COMMAND   PID    USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
    Python  26972 avaitla    3u  IPv4 0xc26aa26de5a8fc6f      0t0  TCP localhost:ddi-tcp-1 (LISTEN)
    Python  26973 avaitla    3u  IPv4 0xc26aa26de5a8fc6f      0t0  TCP localhost:ddi-tcp-1 (LISTEN)
    
    

  • 답변 # 3

    이 질문에 이미 MarkR과 zackthehack이 완전히 대답 한 것처럼 보이지만 Nginx가 청취 소켓 상속 모델의 예라고 덧붙이고 싶습니다.

    여기에 좋은 설명이 있습니다 :

    http://zimbra.imladris.sk/download/src/GNR-601/ThirdParty/nginx/docs/IMPLEMENTATION

    와이즈 비즈 와이즈 비즈      

    ...

         

    NGINX 작업자 프로세스의 흐름

         

    기본 NGINX 프로세스가 구성 파일과 포크를 읽은 후   구성된 작업자 프로세스 수, 각 작업자 프로세스   루프에서 각각의 이벤트를 기다리는 루프에 들어갑니다.   소켓 세트.

         

    각 작업자 프로세스는 청취 소켓으로 시작합니다.   아직 사용할 수있는 연결이 없기 때문입니다. 따라서 이벤트   각 작업자 프로세스에 대한 설명자 세트는   청취 소켓.

         

    (참고) NGINX는 여러 이벤트 중 하나를 사용하도록 구성 할 수 있습니다   폴링 메커니즘 :   aio/devpoll/epoll/eventpoll/kqueue/poll/rtsig/select

         

    연결 소켓에 연결이 도착하면   (POP3/IMAP/SMTP), 각 작업자 프로세스는 이벤트 폴링에서 나옵니다.   각 NGINX 작업자 프로세스는 수신 소켓을 상속하기 때문입니다. 그때,   각 NGINX 작업자 프로세스는 글로벌 뮤텍스를 획득하려고 시도합니다.   작업자 프로세스 중 하나가 잠금을 획득하지만   다른 사람들은 각자의 이벤트 폴링 루프로 돌아갑니다.

         한편, 글로벌 뮤텍스를 획득 한 작업자 프로세스는   트리거 된 이벤트를 검사하고 필요한 작업 큐를 작성합니다.   트리거 된 각 이벤트에 대한 요청. 이벤트는   디스크립터 세트의 단일 소켓 디스크립터   직원이 이벤트를보고있었습니다.

    트리거 된 이벤트가 새로운 수신 연결에 해당하는 경우   NGINX는 청취 소켓으로부터의 연결을 받아들입니다. 그런 다음   컨텍스트 데이터 구조를 파일 디스크립터와 연관시킵니다. 이   컨텍스트는 연결에 대한 정보를 보유합니다 (   POP3/IMAP/SMTP, 사용자 인증 여부 등). 그때,   이 새로 구성된 소켓이 이벤트 설명자 세트에 추가됩니다.   그 작업자 프로세스를 위해.

         

    이 노동자는 이제 뮤텍스를 포기합니다.   다른 노동자들에게 도착한 사람들은 다가올 수 있습니다.)   이전에 대기 한 각 요청 각 요청은   신호 이벤트. 있던 각 소켓 설명자에서   신호를 받으면 작업자 프로세스가 해당 컨텍스트를 검색합니다.   이전에 해당 디스크립터와 연관된 데이터 구조   그런 다음 수행하는 해당 콜백 함수를 호출합니다.   해당 연결 상태를 기반으로하는 작업 예를 들어   NGINX가 처음으로 새로 설립 한 IMAP 연결   표준 IMAP 환영 메시지를
      연결된 소켓 (* OK IMAP4 준비 완료).

         

    각 작업자 프로세스는 작업 대기열 처리를 완료합니다.   각 미결 이벤트에 대한 항목으로 돌아가서 해당 이벤트로 돌아갑니다.   폴링 루프. 클라이언트와의 연결이 설정되면   소켓이 연결될 때마다 이벤트가 더 빠릅니다.   읽을 준비가되었고, 읽기 이벤트가 트리거되고,   해당 조치를 취해야합니다.

  • 답변 # 4

    소켓을 AF__UNIX 소켓 (프로세스 간 소켓)을 통해 Unix/Linux에서 공유 할 수 있다고 덧붙이고 싶습니다. 일어날 것으로 보이는 것은 새로운 소켓 디스크립터가 생성되어 원래의 디스크립터와 다소 별개입니다. 이 새 소켓 설명자는 AFUNIX 소켓을 통해 다른 프로세스로 전송됩니다. 이것은 프로세스가 파일 디스크립터를 공유하기 위해 fork () 할 수없는 경우에 특히 유용합니다. 예를 들어 스레딩 문제로 인해이를 방지하는 라이브러리를 사용할 때. 유닉스 도메인 소켓을 생성하고 libancillary를 사용하여 디스크립터를 보내야합니다.

    참조 :

    https://www.linuxquestions.org/questions/programming-9/how-to-share-socket-between-processes-289978/

    AF_UNIX 소켓을 만들려면 :

    http://docs.sun.com/app/docs/doc/817-4415/portmapper-51908?a=view

    예 : 코드 :

    http://lists.canonical.org/pipermail/kragen-hacks/2002-January/000292.html

    http://cpansearch.perl.org/src/SAMPO/Socket-PassAccessRights-0.03/passfd.c

  • 답변 # 5

    이것이 원래 질문과 얼마나 관련이 있는지 확실하지 않지만 Linux 커널 3.9에는 TCP/UDP 기능을 추가하는 패치가 있습니다. SO_REUSEPORT 소켓 옵션에 대한 TCP 및 UDP 지원;새로운 소켓 옵션을 사용하면 동일한 호스트의 여러 소켓을 동일한 포트에 바인딩 할 수 있으며 멀티 코어 시스템에서 실행되는 멀티 스레드 네트워크 서버 응용 프로그램의 성능을 향상시킬 수 있습니다. 참조 링크에서 언급 한 것처럼 Linux Kernel 3.9의 LWN 링크 LWN SO_REUSEPORT에서 자세한 정보를 확인할 수 있습니다.

    SO_REUSEPORT 옵션은 비표준이지만 다른 많은 UNIX 시스템 (특히 아이디어가 시작된 BSD)에서 유사한 형식으로 제공됩니다. 포크 패턴을 사용하지 않고도 멀티 코어 시스템에서 실행되는 네트워크 응용 프로그램에서 최대 성능을 끌어낼 수있는 유용한 대안을 제공하는 것 같습니다.

    $ telnet 127.0.0.1 8888 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Thank you for your connecting to parent Connection closed by foreign host. $ telnet 127.0.0.1 8888 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Thank you for your connecting to child Connection closed by foreign host. $ telnet 127.0.0.1 8888 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Thank you for your connecting to parent Connection closed by foreign host. $ python prefork.py Got connection from in parent Got connection from in child Got connection from in parent

  • 이전 python - 계층 적 분포 시각화
  • 다음 rails 31 자산 파이프 라인 - 컨트롤러 별 스크립트를로드하는 방법?