◆ 소켓 기본 사항
PHP는 Berkley의 소켓 라이브러리를 사용하여 연결을 생성합니다. 소켓은 데이터 구조에 지나지 않습니다. 이 소켓 데이터 구조를 사용하여 클라이언트와 서버 간의 세션을 시작합니다. 이 서버는 항상 새 세션 생성을 듣고 준비하고 있습니다. 클라이언트가 서버에 연결되면 서버가 세션을 수신하는 포트를 엽니다. 이때 서버는 클라이언트의 연결 요청을 수락한 후 한 사이클을 수행하게 됩니다. 이제 클라이언트는 서버에 정보를 보낼 수 있고, 서버는 클라이언트에 정보를 보낼 수 있습니다.
소켓을 생성하려면 프로토콜, 소켓 유형, 공용 프로토콜 유형이라는 세 가지 변수가 필요합니다. 소켓을 생성할 때 선택할 수 있는 세 가지 프로토콜이 있습니다. 자세한 프로토콜 내용을 보려면 아래를 계속 읽으세요.
공용 프로토콜 유형을 정의하는 것은 연결의 필수 요소입니다. 아래 표에서는 일반적인 프로토콜 유형을 살펴봅니다.
표 1: 프로토콜 이름/상수 설명
AF_INET 대부분의 소켓에서 사용하는 프로토콜로 TCP 또는 UDP를 사용하여 전송하며 IPv4 주소에서 사용됩니다.
AF_INET6은 위와 유사하지만 IPv6 주소에 사용됩니다.
Unix 및 Linux 시스템에서 사용되는 AF_UNIX 로컬 프로토콜은 일반적으로 클라이언트와 서버가 동일한 시스템에 있을 때 사용됩니다.
SOCK_STREAM 이 프로토콜은 순차적이고 안정적인 데이터 통합 바이트 스트림 기반 연결입니다. 가장 일반적으로 사용되는 소켓 유형입니다. 이 소켓은 전송에 TCP를 사용합니다.
SOCK_DGRAM 이 프로토콜은 연결이 없는 고정 길이 전송 호출입니다. 이 프로토콜은 신뢰할 수 없으며 연결에 UDP를 사용합니다.
SOCK_SEQPACKET 이 프로토콜은 전송을 위해 고정 길이 데이터 패킷을 보내는 안정적인 두 줄 연결입니다. 이 패킷을 읽으려면 먼저 완전히 수락해야 합니다.
SOCK_RAW 이 소켓 유형은 단일 네트워크 액세스를 제공합니다. 이 소켓 유형은 ICMP 공용 프로토콜을 사용합니다. (ping 및 Traceroute는 이 프로토콜을 사용합니다)
SOCK_RDM 이 유형은 거의 사용되지 않으며 대부분의 운영 체제에서 구현되지 않습니다. 이는 데이터 링크 계층에서 사용하도록 제공되며 패킷 순서를 보장하지 않습니다. 표 3: 공용 프로토콜 이름/상수 설명.
ICMP 인터넷 제어 메시지 프로토콜은 주로 게이트웨이와 호스트에서 네트워크 상태를 확인하고 오류 메시지를 보고하는 데 사용됩니다.
연결이 없고 신뢰할 수 없는 전송 프로토콜인 UDP 사용자 데이터그램 프로토콜
가장 일반적으로 사용되는 신뢰할 수 있는 공용 프로토콜인 TCP 전송 제어 프로토콜은 데이터 패킷이 수신자에게 도달할 수 있도록 보장할 수 있습니다. 전송 프로세스 중에 오류가 발생하면 오류 패킷을 다시 보냅니다.
이제 소켓을 생성하는 세 가지 요소를 알았으므로 PHP에서 소켓_create() 함수를 사용하여 소켓을 생성합니다. 이 소켓_create() 함수에는 프로토콜, 소켓 유형 및 공용 프로토콜의 세 가지 매개변수가 필요합니다. 소켓_create() 함수는 성공적으로 실행되면 소켓이 포함된 리소스 유형을 반환합니다. 실패하면 false를 반환합니다.
자원 소켓_create(int 프로토콜, int 소켓 유형, int commonProtocol);
이제 소켓을 생성한 다음에는 무엇을 합니까? PHP는 소켓을 조작하기 위한 여러 함수를 제공합니다. 소켓을 IP에 바인딩하고, 소켓의 통신을 수신하고, 소켓을 수락할 수 있습니다. 이제 함수가 소켓을 생성하고 수락하고 수신하는 방법을 이해하기 위해 예제를 살펴보겠습니다.
<?php
$commonProtocol = getprotobyname("tcp");//공용 프로토콜 이름을 사용하여 프로토콜 유형을 가져옵니다.
$socket = 소켓_create(AF_INET, SOCK_STREAM, $commonProtocol);//소켓을 생성하고 소켓 리소스의 인스턴스를 반환합니다.
Socket_bind($socket, 'localhost', 1337);//로컬 컴퓨터에 소켓 바인딩
Socket_listen($socket);//들어오는 모든 소켓 연결을 수신합니다.
// 더 많은 소켓 기능이 제공될 예정입니다.
?>
위의 예는 자체 서버 측을 생성합니다. 예제의 첫 번째 줄은
$commonProtocol = getprotobyname("tcp");
프로토콜 유형을 얻으려면 공용 프로토콜 이름을 사용하십시오. 여기서는 TCP 공용 프로토콜이 사용됩니다. UDP 또는 ICMP 프로토콜을 사용하려면 getprotobyname() 함수의 매개변수를 "udp" 또는 "icmp"로 변경해야 합니다. 또 다른 대안은 getprotobyname() 함수를 사용하는 대신 소켓_create() 함수에 SOL_TCP 또는 SOL_UDP를 지정하는 것입니다.
$socket = 소켓_생성(AF_INET, SOCK_STREAM, SOL_TCP);
예제의 두 번째 줄은 소켓을 생성하고 소켓 리소스의 인스턴스를 반환합니다. 소켓 리소스의 인스턴스가 있으면 소켓을 IP 주소 및 포트에 바인딩해야 합니다.
소켓_바인드($socket, 'localhost', 1337);
여기서 소켓을 로컬 컴퓨터(127.0.0.1)에 바인딩하고 소켓을 1337 포트에 바인딩합니다. 그런 다음 들어오는 모든 소켓 연결을 수신해야 합니다.
소켓_청취($socket);
네 번째 줄 이후에는 모든 소켓 기능과 사용법을 이해해야 합니다.
표 4: 소켓 함수 함수 이름 설명
소켓_accept()는 소켓 연결을 허용합니다.
소켓_바인드()는 소켓을 IP 주소 및 포트에 바인딩합니다.
소켓_clear_error()는 소켓 오류 또는 마지막 오류 코드를 지웁니다.
소켓_close()는 소켓 자원을 닫습니다.
Socket_connect()는 소켓 연결을 시작합니다.
소켓_create_listen()은 지정된 포트에서 수신 대기하는 소켓을 엽니다.
소켓_create_pair()는 구별할 수 없는 소켓 쌍을 배열로 생성합니다.
소켓_create()는 소켓 데이터 구조를 생성하는 것과 동일한 소켓을 생성합니다.
소켓_get_option() 소켓 옵션 가져오기
소켓_getpeername() 원격 유사한 호스트의 IP 주소를 가져옵니다.
소켓_getsockname()은 로컬 소켓의 IP 주소를 가져옵니다.
소켓_iovec_add()는 분산/집계 배열에 새 벡터를 추가합니다.
소켓_iovec_alloc() 이 함수는 전송, 수신, 읽기 및 쓰기가 가능한 iovec 데이터 구조를 생성합니다.
소켓_iovec_delete()는 할당된 iovec을 삭제합니다.
소켓_iovec_fetch()는 지정된 iovec 리소스의 데이터를 반환합니다.
소켓_iovec_free()는 iovec 자원을 해제합니다.
소켓_iovec_set()은 iovec 데이터의 새 값을 설정합니다.
Socket_last_error()는 현재 소켓의 마지막 오류 코드를 가져옵니다.
Socket_listen()은 지정된 소켓의 모든 연결을 수신합니다.
소켓_read()는 지정된 길이의 데이터를 읽습니다.
소켓_readv()는 분산/집계 배열에서 데이터를 읽습니다.
소켓_recv()는 소켓에서 캐시로 데이터를 종료합니다.
소켓_recvfrom()은 지정된 소켓의 데이터를 허용합니다. 지정하지 않으면 기본값은 현재 소켓입니다.
소켓_recvmsg()는 iovec로부터 메시지를 받습니다.
소켓_select() 다중 선택
소켓_send() 이 함수는 연결된 소켓으로 데이터를 보냅니다.
소켓_sendmsg()는 소켓에 메시지를 보냅니다.
소켓_sendto()는 지정된 주소의 소켓에 메시지를 보냅니다.
소켓_set_block()은 소켓을 블록 모드로 설정합니다.
소켓_set_nonblock() 소켓을 비블록 모드로 설정합니다.
소켓_set_option()은 소켓 옵션을 설정합니다.
소켓_shutdown() 이 함수를 사용하면 읽기, 쓰기 또는 지정된 소켓을 닫을 수 있습니다.
소켓_strerror()는 지정된 오류 번호와 함께 자세한 오류를 반환합니다.
Socket_write()는 소켓 캐시에 데이터를 씁니다.
소켓_writev()는 분산/집합 배열에 데이터를 씁니다. 위의 모든 함수는 PHP의 소켓과 관련되어 있습니다. 소켓을 열지 않은 경우 php.ini 파일을 편집하고 제거하십시오. 이 줄 앞의 설명 다음:
확장자=php_sockets.dll
주석을 제거할 수 없는 경우 다음 코드를 사용하여 확장 라이브러리를 로드하십시오.
<?php
if(!extension_loaded('소켓')) {
if(strtoupper(substr(PHP_OS, 3)) == “승리”) {
dl('php_sockets.dll');
}또 다른{
dl('sockets.so');
}
}
?>
소켓이 열려 있는지 여부를 모르는 경우 phpinfo() 함수를 사용하여 소켓이 열려 있는지 확인할 수 있습니다. phpinfo 정보를 보면 소켓이 열려 있는지 확인할 수 있습니다.
phpinfo()의 소켓 정보 보기 ◆ 서버 생성 이제 첫 번째 예제를 개선해 보겠습니다. 특정 소켓을 수신하고 사용자 연결을 처리해야 합니다.
<?php
$commonProtocol = getprotobyname("tcp");
$socket = 소켓_생성(AF_INET, SOCK_STREAM, $commonProtocol);
소켓_바인드($socket, 'localhost', 1337);
소켓_청취($socket);
//서버로 들어오는 모든 연결을 수락합니다.
$연결 = 소켓_수용($socket);
if($연결){
소켓_write($connection, "소켓에 연결되었습니다...nr");
}
?>
이 예제를 실행하려면 명령 프롬프트를 사용해야 합니다. 그 이유는 여기에 웹페이지가 아닌 서버가 생성되기 때문이다. 웹 브라우저를 사용하여 이 스크립트를 실행하려고 하면 30초 제한을 초과할 가능성이 높습니다. 아래 코드를 사용하여 무한 런타임을 설정할 수 있지만 명령 프롬프트를 사용하여 실행하는 것이 좋습니다.
set_time_limit(0);
명령 프롬프트에서 이 스크립트를 테스트해 보세요.
Php.exe example01_server.php
시스템 환경 변수에 PHP 인터프리터 경로를 설정하지 않은 경우 php.exe 경로를 지정해야 합니다. 서버를 실행하면 텔넷을 통해 1337번 포트에 접속하여 서버를 테스트할 수 있습니다.
위의 서버 측에는 세 가지 문제가 있습니다. 1. 다중 연결을 허용할 수 없습니다. 2. 하나의 명령만 완료합니다. 3. 웹 브라우저를 통해 이 서버에 연결할 수 없습니다.
이 첫 번째 문제는 해결하기가 더 쉽습니다. 애플리케이션을 사용하여 매번 서버에 연결할 수 있습니다. 하지만 다음 문제는 서버에 연결하기 위해 웹 페이지를 사용해야 한다는 점인데, 이것이 더 어렵습니다. 서버가 연결을 수락하고 클라이언트에 일부 데이터를 쓰고(필요한 경우) 연결을 닫고 다음 연결을 기다리도록 할 수 있습니다.
이전 코드를 개선하고 다음 코드를 생성하여 새 서버를 만듭니다.
<?php
// 소켓 설정
$commonProtocol = getprotobyname("tcp");
$socket = 소켓_생성(AF_INET, SOCK_STREAM, $commonProtocol);
소켓_bind($socket, 'localhost', 1337); //socket_bind()는 소켓을 IP 주소 및 포트에 바인딩합니다.
소켓_청취($socket);
//버퍼 초기화
$buffer = "데이터 없음";
동안(참) {
// 이 소켓으로 들어오는 모든 연결을 수락합니다.
$connection = 소켓_accept($socket);//socket_accept()는 소켓 연결을 허용합니다.
printf("소켓이 연결되었습니다rn");
//버퍼에 아무것도 없는지 확인
if($buffer != ""){
printf("버퍼에 뭔가가 있습니다...데이터를 보내는 중...rn");
소켓_write($connection, $buffer . "rn"); //socket_write()는 소켓 캐시에 데이터를 씁니다.
printf("소켓에 썼습니다rn");
}또 다른 {
printf("버퍼에 데이터가 없습니다rn");
}
//입력받기
while($data = 소켓_read($connection, 1024, PHP_NORMAL_READ))//socket_read()는 지정된 길이의 데이터를 읽습니다.
{
$버퍼 = $데이터;
소켓_write($connection, "정보 수신됨rn");
printf("버퍼: " . $buffer . "rn");
}
소켓_close($connection); //socket_close()는 소켓 자원을 닫습니다.
printf("소켓을 닫았습니다rnrn");
}
?>
이 서버는 무엇을 해야 합니까? 소켓을 초기화하고 캐시를 열어 데이터를 보내고 받습니다. 연결을 기다리고 연결이 이루어지면 서버 측 화면에 "소켓 연결됨"을 인쇄합니다. 이 서버는 버퍼를 확인하여 버퍼에 데이터가 있으면 연결된 컴퓨터로 데이터를 보냅니다. 그런 다음 이 데이터에 대한 수락 메시지를 보냅니다. 메시지를 수락하면 메시지를 데이터에 저장하고 연결된 컴퓨터가 메시지를 인식하게 한 다음 마지막으로 연결을 닫습니다. 연결이 닫히면 서버는 다음 연결 처리를 시작합니다.
◆ 두 번째 문제를 처리하기 위한 클라이언트 생성은 쉽습니다. PHP 페이지를 생성하고, 소켓에 연결하고, 일부 데이터를 캐시로 보내고 처리해야 합니다. 그런 다음 처리된 데이터가 대기 중이고 데이터를 서버로 보낼 수 있습니다. 다른 클라이언트 연결에서는 해당 데이터를 처리합니다.
다음 예에서는 소켓 사용을 보여줍니다.
<?php
// 소켓을 생성하고 연결
$socket = 소켓_생성(AF_INET, SOCK_STREAM, SOL_TCP);
$connection = 소켓_연결($socket,'localhost', 1337);
while($buffer = 소켓_read($socket, 1024, PHP_NORMAL_READ)) {
if($buffer == "데이터 없음") {
echo(“<p>데이터 없음</p>”);
부서지다;
}또 다른{
// 버퍼의 데이터로 작업 수행
echo(“<p>버퍼 데이터: “ . $buffer . “</p>”);
}
}
echo(“<p>소켓에 쓰기</p>”);
// 소켓에 테스트 데이터 쓰기
if(!socket_write($socket, “일부 데이터rn”)){
echo(“<p>쓰기 실패</p>”);
}
// 소켓에서 응답을 읽습니다.
while($buffer = 소켓_read($socket, 1024, PHP_NORMAL_READ)){
echo("<p>전송된 데이터: 일부 데이터<br> 응답:" . $buffer . "</p>");
}
echo(“<p>소켓 읽기 완료</p>”);
?>
이 예제 코드는 서버에 연결하는 클라이언트를 보여줍니다. 클라이언트가 데이터를 읽습니다. 이것이 이 주기에 도착하는 첫 번째 연결인 경우 서버는 "NO DATA"를 클라이언트에 다시 보냅니다. 이런 일이 발생하면 클라이언트가 연결의 최상위에 있습니다. 클라이언트는 데이터를 서버로 보내고, 데이터는 서버로 전송되며, 클라이언트는 응답을 기다립니다. 응답을 받으면 화면에 응답을 씁니다.