Develop!/php

PHP를 이용한 다중 연결 소켓 통신 (1)

체리필터 2011. 10. 7. 17:32
728x90
반응형

from phpschool

이진우

프리랜서
프로그래머

            
          


이문서의 배포는 자유로우나 최소한 제작자의 정보는 제외하지 않고 배포해 주세요.

문서가 존재하는 모든곳에 답변을 드릴수 없으므로 질문은 홈페이지(http://www.jinoos.com)에서만 받습니다.


1. 소개

앞으로 몇번에 걸처서 PHP를 이용한 다중 연결 소켓 통신에 대해서 알아보겠습니다. PHP는 확장 함수로 socket 계열 함수를 지원합니다. 하지만 이것은 컴파일시 --with-socket 옵션을 주어 컴파일 해야 합니다. 클라이언트 소켓에 관한 함수 fsockopen()는 이곳에서 사용하지 않습니다.


1.1. PHP 컴파일 하기

앞으로 설명할 내용들은 일반적인 아파치 모듈로서의 PHP가 아닌 독립적으로 실행 가능한 PHP CGI형태입니다. 이를 위해서 재 컴파일이 필요하며 이때 소켓에 관한 옵션을 추가하게 됩니다.

PHP 4.3.1 버전을 이용했습니다.

#] tar -zxvf php-4.3.1.tar.gz
#] cd php-4.3.1
#] ./configure --with-socket
#] make

make 를 한후 make install 을 하지말고 php-4.3.1 디렉터리를 보면 php 라는 실행파일이 생성된것을 알수 있다. 그럼 이제 프로그램 짤 준비는 다�다. 간단한가? 간단하다. -_-a


1.2. PHP의 소켓 함수

PHP의 소켓 함수 몇가지를 알아보고 넘어 가도록 하자. PHP의 소켓 함수는 C sys/socket.h 에 정의 되어있는 함수들과 매우 유사하다. 참고 하도록 하자.

socket_create ( int domain, int type, int protocol )

소켓의 연결 자원을 생성 합니다. 소켓 함수를 사용할때 기본으로 쓰입니다.

domain 파라메터에는 AF_UNIX 또는 AF_INET 으로 유닉스 도메인 소켓 또는 인터넷 소켓으로 지정합니다.

type 파라메터에는 STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW, SOCK_RDM, or SOCK_PACKET 등의 소켓의 종류가 설정 됩니다.

protocol 파라메터에는 TCP또는 UDP 설정(SOL_UDP or SOL_TCP)을 합니다.

socket_connect ( resource socket, string address [, int port] )

서버소켓으로 접속할때 사용하는 함수. 소켓 클라이언트에서 사용하는 함수 입니다.

socket_setopt ( resource socket, int level, int optname, int )

소켓에 옵션을 지정합니다. 크게 중요하지 않은 함수 입니다.-_-

socket_bind ( resource socket, string address [, int port] )

서버 소켓에 주소와 포트번호를 부여 합니다. 서버 소켓에서 필수적인 작업입니다.

만약 AF_UNIX로 지정했다면 port 파라메터는 생략이 가능합니다.

socket_listen ( resource socket [, int backlog] )

서버 소켓을 클라이언트 대기 상태로 만듭니다.

socket_listen() 함수를 호출한 이후부터 서버 소켓은 클라이언트가 접속하는지 아닌지 귀를 기울이는 일을 하게 되는겁니다. 서버 소켓 사용에서 필수 적입니다.

backlog 파라메터는 받아들일 클라이언트의 최대 수를 지정합니다. 생략하면 최대 갯수로 설정됩니다.

리눅스에서 소켓의 최대 갯수는 ulimit -a 를 해보시면 open files 항목이 소켓 최대 갯수와 상응합니다.

socket_accept ( resource socket )

클라이언트 접속을 허가 할때 사용하는 함수 입니다.

함수 호출후 새로운 소켓 리소스가 리턴되는데 이것은 기존에 서버 소켓 리소스에서 생성된 클라이 언트와 통신하는 새로운 소켓 리소스 입니다.

socket_getpeername ( resource socket, string &addr [, int &port] )

클라이언트의 접속 정보를 가져 옵니다.

socket_read ( resource socket, int length [, int type] )

소켓에서 length만큼의 정보를 읽어 들입니다.

type 읽어들일 타입을 결정 합니다.

  • PHP_BINARY_READ : 바이너리 타입으로 읽어 들입니다. 4.1.0 포함 버전 이후부터 기본값으로 설정되었습니다.

  • PHP_NORMAL_READ : \r또는 \n이 입력될때 끊어서 읽습니다. 한마디로 라인 단위로 읽는 다는 말이죠. 4.1.0이전 버전에선 기본값.

socket_write ( resource socket, string buffer [, int length] )

소켓에 정보를 써넣는 함수로 마지막 인자를 생략하면 buffer의 길이가 자동으로 대입됩니다.

socket_close ( resource socket )

소켓 연결을 끊는다.


2. 소켓 서버 만들기

이제 실전으로 들어가 보겠다. 오늘 만들것은 간단하게 클라이언트가 접속하면 클라이언트의 접속 정보를 출력하고 클라이언트에게 현재 날자와 시간을 전송한후 종료 합니다.

엄밀히 말하면 오늘 만들 소켓 서버는 다중 사용자를 위한 시스템은 아니다. 하지만 오늘은 간단히 소켓의 개념을 집고 넘어가는 의미로 생각하자.

PHP를 CGI형태로 실행하기 위해서 소스코드 상단에

#!/usr/local/bin/php -q
<?php
..
..
..
?>

처럼 프로그래밍을 합니다. 이것은 Perl스크립트나 기타 쉘 스크립트에서 전처리기를 설정하는것과 같은 방법 입니다. -q 옵션은 http protocol 헤더를 제거 하는 옵션입니다.

#!/usr/local/bin/php -q
<?php
define("_IP",    "123.123.123.12");
define("_PORT",  "65000");

$sSock      = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($sSock, _IP, _PORT);
socket_listen($sSock);
while($cSock = socket_accept($sSock))
{
    socket_getpeername($cSock, $addr, $port);
    echo "SERVER >> client connected $addr:$port \n";
    $date = date("Y/m/d H:i:s");
    socket_write($cSock, $date);
    socket_close($cSock);
    echo "SERVER >> client Close.\n";
}
?>

서버는 지속적으로 클라이언트를 기다리는 형태의 모습을 하고 있습니다.


3. 소켓 클라이언트 만들기 와 실행

클라이언트는 서버에 접속을 하고 서버쪽에서 보내온 메시지를 읽은뒤 출력하고 종료합니다.

주의

프로그램상의 아이피는 가상으로 만든 것입니다. 테스트시 적절한 아이피로 변경해 주세요.

#!/home/dimeclub/www/bin/php/php -q
<?php
define("_IP",    "123.123.123.12");
define("_PORT",  "65000");

$sock      = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($sock, _IP, _PORT);
echo "CLIENT >> socket connect to "._IP.":"._PORT."\n";
$date = socket_read($sock, 4096);
echo "CLIENT >> this time is $date \n";
socket_close($sock);
echo "CLIENT >> socket closed.\n";
?>

너무 간단하다고 돌 날아오겠네요. -_-a. 위 두 파일을 server.php, client.php라 저장하고 실행권한을 준뒤 실행해 보도록 하겠습니다.

아래 화면의 #]는 쉘 커맨드 입니다.

#]
#] ll
total 8
-rwxr-xr-x    1 jinoos   jinoos        387 May  7 04:59 client.php
-rwxr-xr-x    1 jinoos   jinoos        495 May  7 04:59 server.php
#]
#] ./server.php &
[1] 23833
#]
#] ./client.php 
SERVER >> client connected 123.123.123.12:45188 
SERVER >> client Close.
CLIENT >> socket connect to 123.123.123.12:65000
CLIENT >> this time is 2003/05/07 04:59:49 
CLIENT >> socket closed.
#]
#] ./client.php 
SERVER >> client connected 123.123.123.12:45358 
SERVER >> client Close.
CLIENT >> socket connect to 123.123.123.12:65000
CLIENT >> this time is 2003/05/07 05:01:03 
CLIENT >> socket closed.
#]
#]

위 내용은 서버프로그램을 백그라운드로 실행하고, 짧은 시간동안 두번 클라이언트로 서버에 접속한 모습입니다. 원하던데로 출력된것을 확인할수 있습니다.

같은 머신 상에서 접속하게 된다면 서버와 클라이언트에서 같은 IP를 출력하게 될것입니다. 그리고 잘보면 클라이언트의 PORT가 변경되었는데 클라이언트의 머신의 경우 일정 대역의 포트중 사용하지 않는 포트를 자동으로 사용하는 것입니다. 이것을 프로그램상으로 조정하는것은 아닙니다. OS에서 자동적으로 할당된것을 사용하는것입니다.


4. 결론

오늘은 간단하게 PHP를 이용해서 소켓함수를 사용하는 것을 해보았습니다. 다음시간에는 PHP의 Process Control Functions 함수들을 이용해서 Fork를 사용한 오늘 보다 좀더 진보된 다중 접속 서버 소켓을 만들어 보겠습니다.

728x90
반응형