PHP 기반 네트워크 애플리케이션, 특히 청취를위한 특정 포트가 필요한 서비스 (예 : HTTP 서버, 소켓 서비스 등)를 개발할 때는 "포트가 점유 된"문제가 발생하는 것이 일반적입니다. 이 문제는 일반적으로 서비스가 중단 된 후에 발생하며 운영 체제는 여전히 포트가 점유되어 있다고 믿어 서비스를 다시 시작하고 포트를 바인딩 할 수 없습니다.
이 문제를 효과적으로 해결하기 위해 PHP는 Socket_set_option 함수를 제공하며 다양한 소켓 옵션을 설정하는 데 사용할 수 있습니다. 그중에서도 SO_Reuseaddr은 포트 점유 문제를 해결하는 데 도움이되는 일반적으로 사용되는 옵션입니다. 이 기사에서는 Socket_set_option을 사용하여 SO_Reuseaddr을 설정하는 방법을 자세히 설명하여 서비스가 다시 시작될 때 중고 포트를 다시 결합시킬 수 있습니다.
SO_Reuseaddr는 Time_wait 상태에서 포트를 바인딩 할 수있는 소켓 옵션입니다. 운영 체제는 일반적으로 모든 패킷이 정리되도록 포트의 상태를 time_wait 로 설정합니다. 그러나 시스템은 다른 프로세스가 Time_wait 상태의 포트에 바인딩되는 것을 방지합니다. SO_REUSEADDR을 설정 한 후에는 여전히 Time_wait 상태에있을 때 포트를 다시 반짝 반응 할 수 있습니다.
PHP에서 Socket_set_option 함수는 이미 생성 된 소켓의 옵션을 설정하는 데 사용됩니다. 구문은 다음과 같습니다.
<span><span><span class="hljs-keyword">bool</span></span><span> </span><span><span class="hljs-title function_ invoke__">socket_set_option</span></span><span> ( resource </span><span><span class="hljs-variable">$socket</span></span><span> , </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$level</span></span><span> , </span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$optname</span></span><span> , </span><span><span class="hljs-keyword">mixed</span></span><span> </span><span><span class="hljs-variable">$optval</span></span><span> )
</span></span>
$ 소켓 : 옵션을 설정하기위한 소켓 리소스.
$ level : 일반적으로 sol_socket 프로토콜 계층은 소켓 레벨 옵션이 작동 함을 의미합니다.
$ optname : so_reuseaddr 의 옵션 이름은 SO_Reuseaddr (보통 1 )입니다.
$ optVal : 옵션 값, SO_REUSEADDR 의 경우이 값은 일반적으로 1 이므로 옵션이 활성화되어 있음을 나타냅니다.
다음은 Socket_set_option을 사용하여 포트 점유를 피하기 위해 SO_Reuseaddr 옵션을 설정하는 방법을 보여주는 간단한 PHP 예입니다.
<span><span><span class="hljs-meta"><?php</span></span><span>
</span><span><span class="hljs-comment">// a TCP socket</span></span><span>
</span><span><span class="hljs-variable">$socket</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_create</span></span><span>(AF_INET, SOCK_STREAM, SOL_TCP);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$socket</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Socket 창조가 실패했습니다: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>()) . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
</span><span><span class="hljs-comment">// 설정 SO_REUSEADDR 옵션</span></span><span>
</span><span><span class="hljs-variable">$optval</span></span><span> = </span><span><span class="hljs-number">1</span></span><span>;
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">socket_set_option</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>, SOL_SOCKET, SO_REUSEADDR, </span><span><span class="hljs-variable">$optval</span></span><span>) === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"설정 SO_REUSEADDR 옵션失败: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>)) . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
</span><span><span class="hljs-comment">// 지정된 것에 결합합니다 IP 그리고 포트</span></span><span>
</span><span><span class="hljs-variable">$host</span></span><span> = </span><span><span class="hljs-string">'127.0.0.1'</span></span><span>;
</span><span><span class="hljs-variable">$port</span></span><span> = </span><span><span class="hljs-number">8080</span></span><span>;
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">socket_bind</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>, </span><span><span class="hljs-variable">$host</span></span><span>, </span><span><span class="hljs-variable">$port</span></span><span>) === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"바인딩이 실패했습니다: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>)) . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Socket 성공적으로 바운드 <span class="hljs-subst">$host</span></span></span><span>:</span><span><span class="hljs-subst">$port</span></span><span>\n";
</span><span><span class="hljs-comment">// 포트를 들어보세요</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">socket_listen</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>) === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"듣기 실패: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>)) . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
</span><span><span class="hljs-comment">// 연결을 기다리고 있습니다</span></span><span>
</span><span><span class="hljs-variable">$clientSocket</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_accept</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$clientSocket</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"클라이언트 연결을받지 못했습니다: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>)) . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span><span><span class="hljs-keyword">exit</span></span><span>;
}
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"클라이언트가 연결되어 있습니다!\n"</span></span><span>;
</span><span><span class="hljs-comment">// 연결을 닫으십시오</span></span><span>
</span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$clientSocket</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">socket_close</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>);
</span><span><span class="hljs-meta">?></span></span><span>
</span></span>
소켓 생성 : 우리는 TCP 소켓을 생성하기 위해 Cocket_Create 기능을 사용합니다. 이 함수는 생성 된 소켓을 나타내는 리소스를 반환합니다. 창조가 실패하면 거짓이 반환됩니다.
SO_REUSEADDR 옵션 설정 옵션 : 포트가 time_wait 상태에있을 때 포트를 다시 반입 할 수 있도록 socket_set_option을 통해 so_reuseaddr을 설정합니다.
바인드 포트 : Socket_bind 함수를 사용하여 생성 된 소켓을 지정된 IP 주소 및 포트에 바인딩하십시오. 바인딩이 실패하면 프로그램이 오류 메시지를 출력합니다.
청취 포트 : socket_listen 함수는 바운드 포트를 듣는 데 사용되며 클라이언트 연결을 수락 할 준비가되었습니다.
클라이언트 연결 수신 : Socket_Accept가 대기하고 클라이언트 연결을 수락합니다.
socket_set_option 으로 so_reuseaddr 옵션을 설정하면 특히 서비스가 다시 시작될 때 포트 점유 문제를 효과적으로 해결할 수 있습니다. 이 옵션을 사용하면 Time_wait 상태에있을 때 포트를 다시 반짝 반짝 반짝이하여 공통 "포트가 점유되었습니다"오류를 피할 수 있습니다.
SO_Reuseaddr 옵션을 사용하면 운영 체제의 포트 사용 규칙을 완전히 우회 할 수 없습니다. 주로 포트가 Time_wait 상태에있을 때 상황을 해결합니다. 다른 시나리오에서 포트 점령을받는 경우 더 복잡한 네트워크 구성 또는 프로세스 관리 전략을 고려해야 할 수도 있습니다.