1. 메일 확인
2. 메일 조회
3. 메일 지우기
4. 메일 보내기

mail_detail.php

<?
// 필요한 서브 함수입니다.. 아래 메인의 소스를 보시고 이 함수 내용은 마지막에 보세요.
// 메일의 구조를 분석하는 함수


function checkstruct($mailstream, $MSG_NO) {
// 메일 구조 분석
$struct = imap_fetchstructure($mailstream, $MSG_NO);
// 메일의 구조를 객체로 리턴해 줍니다. 인자는 메일스트림과 해당 메일번호입니다.

$type = $struct->subtype;
/*
메일의 타입을 얻습니다. 크게 PLAIN, MIXED, ALTERNATIVE, RELATED 이렇게 있읍
니다.. ( 더 있는지도 모르죠... ^ ^)
PLAIN : 그냥 텍스트 메일이죠.. 이건 그냥 출력만 해주면 됩니다..
MIXED : 첨부파일이 있는 메일이란 건데... 이게 가장 복잡하죠.. 아래 switch문에
switch 문에서 설명하죠.
ALTERNATIVE : HTML 형식으로 메일을 보내면 이게 됩니다.
RELATED : HTML 형식으로 보낼때 보면 메일안에 이미지를 삽입해서 보낼 수 있습니다.
그 경우에 해당됩니다.

아래에서 자세히 보죠..
*/


switch($type) {
case "PLAIN": // 일반텍스트 메일
echo str_replace("\n", "<br>",
imap_fetchbody($mailstream, $MSG_NO, "1"));
// 그냥 본문을 얻어서 출력해 주면 됩니다.
// 본문을 얻는 방법은 위처럼 imap_fetchbody 함수를 사용하는데.. 여기서 세번째
// 인자가 "1" 이렇게 되어 있죠. 이것은 몌일의 body가 boundary라는 것으로 구분
// 되어 여러개가 올 수 있는데 그 중 첫번째 것이란 겁니다.. 당연 텍스트 메일은
// body가 하나밖에 없기에 그냥 무조건 위처럼 하면 됩니다.
break;
case "MIXED": // 첨부파일 있는 메일
/*
이게 좀 복잡하죠. 먼저 위에서 말했듯 첨부파일이 있는 것은 body가 여러개입니다.
즉 첨부파일이 두개인 text 메일일 경우 body는 세개로 나뉘죠..
이 세개의 body를 각각 표현하는 것이 되겠습니다.
*/
for($i=0;$i<count($struct->parts);$i++) {
// parts라는 속성에는 boundary로 구분된 body의 개체들이 들어 가게 됩니다.
// 이것의 갯수를 알아서 루프를 돌리는 거죠.


$part = $struct->parts[$i];
$param = $part->parameters[0];
$file_name = Decode($param->value);
// 첨부파일일 경우 파일명 Decode 함수는 어제 말한 제가 만든 거죠...
$mime = $part->subtype; // MIME 타입 혹은 메일의 종류가 리턴됩니다.
$encode = $part->encoding; // encoding

/*
아래 부분을 보면 $mime 이란 변수에 ALTERNATIVE 라는 것이 올수 있게 되어
있습니다.. 즉 OUTLOOK에서 HTML 형식으로 첨부파일을 보내면 대략
-메세지
-첨부파일1
-첨부파일2
-첨부파일3
이렇게 나뉘고 다시 메세지는
---PLAN
---HTML
이렇게 나뉘게 됩니다.. 이경우 메세지에 해당하는 부분이 ALTERNATIVE인 거죠..
*/
if($mime == "ALTERNATIVE") {
$val = imap_fetchbody($mailstream, $MSG_NO, (string)($numpart+1));
// 해당 part의 번호로 body에서 그 부분만 빼옵니다. 그리곤 이것을
// 화면에 출력하죠.. 아래 함수로.. 이것은 제가 만든 건데.. 나중에 설명하죠.
printOutLook($val);
} else {
printbody($mailstream, $MSG_NO, $i, $encode, $mime, $file_name);
// 첨부파일일 경우 printbody함수를 호출합니다.. 이건 바로 밑에 있는 함수인
// 데 거기서 설명하죠..
}
}
break;
case "ALTERNATIVE": // outlook html
for($i=0;$i<count($struct->parts);$i++) {
$part = $struct->parts[$i];
$param = $part->parameters[0];
$file_name = Decode($param->value); // 첨부파일일 경우 파일명
$mime = $part->subtype;
$encode = $part->encoding;

if($mime == "HTML") {
printbody($mailstream, $MSG_NO, $i, $encode, $mime, $file_name);
}
}
break;
case "RELATED": // outlook 본문에 이미지 삽입
for($i=0;$i<count($struct->parts);$i++) {
$part = $struct->parts[$i];
$param = $part->parameters[0];
$file_name = Decode($param->value); // 첨부파일일 경우 파일명
$mime = $part->subtype; // MIME 타입
$encode = $part->encoding; // encoding
if($mime == "ALTERNATIVE") {
$val = imap_fetchbody($mailstream, $MSG_NO, (string)($numpart+1));
printOutLook($val);
} else {
printbody($mailstream, $MSG_NO, $i, $encode, $mime, $file_name);
}
}
break;
}
}

// 메일 내용을 출력하는 함수
function printbody($mailstream, $MSG_NO, $numpart, $encode, $mime, $file_name) {
$val = imap_fetchbody($mailstream, $MSG_NO, (string)($numpart+1));
// 먼저 해당 part의 본문을 받아 옵니다.
// 그리고 인자값으로 넘어온 $encode 에 의해 먼저 본문을 decoding 해줍니다.

switch($encode) {
case 0: // 7bit
case 1: // 8bit
$val = imap_base64(imap_binary(imap_qprint(imap_8bit($val))));
break;
case 2: // binary
$val = imap_base64(imap_binary($val));
break;
case 3: // base64
$val = imap_base64($val);
break;
case 4: // quoted-print
$val = imap_base64(imap_binary(imap_qprint($val)));
break;
case 5: // other
echo "알수없는 Encoding 방식.";
exit;
}

// mime type 에 따라 출력합니다.
switch($mime) {
case "PLAIN":
echo str_replace("\n", "<br>", $val);
break;
case "HTML":
echo $val;
break;
default:
// 첨부파일인 경우이므로 다운로드 할 수 있게 링크를 걸어 줍니다.
echo "<br>첨부: <a href="mail_down.php?
MSG_NO=" . $MSG_NO . "&PART_NO=
" . $numpart . "" >" . $file_name . "</a>";
}
}
// ----------------------
// 메인 시작
// include 선언
// ----------------------
include ("mail_lib.php"); // 라이브러리 파일엔 지난번 강좌에 있던 Decode라는 함수가 있죠.
?>
<html>
<body>
<?
$box = $BOX; // 메일 박스명
if($box == "") $box = "INBOX";
switch($box) {
case "INBOX":
$box_name="받은 편지함";
break;
case "sent":
$box_name="보낸 편지함";
break;
}
?>
<body bgcolor="#FFFFFF" leftmargin=5 topmargin=20 marginwidth=5 marginheight=20>
<table width="610" border=0 bgcolor=#527900 cellpadding=4 cellspacing=0>
<tr>
<td align=center width="25" bgcolor="#334600">
<font face="Wingdings" size="4" color="#FFCC33">.</font></td>
<td width=95%>
<font size="3" color="#FFFFFF"><b>편지읽기</b></font>
</td>
</tr>
</table>
<table width=610 border=0 cellpadding=4 cellspacing=0 bgcolor=#D8D8D8>
<tr>
<td class="tk1" width=40%></td>
<td align="right" class="tk1" width=60%>
<a href="mail_cmd.php?CMD=del&NO[]=<?echo $MSG_NO;?>">삭제</a>
&nbsp;&nbsp;&nbsp;&nbsp;
[<a href="mail_list.php?BOX=<?echo $box;?>">목록</a>]
</td>
</tr>
</table>
<?
$login = "userid";
$pass = "pwd";
$C_DOMAIN = "hagopa.co.kr";

$mailstream = imap_open("{" . $C_DOMAIN . ":143}" . $box, $login, $pass);

if ($mailstream == 0) {
echo "Error!
";
exit;
}

// 메일 헤더 분석
$head = imap_header($mailstream,$MSG_NO);
$head->Unseen = "U";

$date = date("Y년 m월 d일 H시 i분", $head->udate);
$subject = $head->Subject;
$subject = Decode($subject);
$from_obj = $head->from[0];
$from_name = $from_obj->personal;
$from_addr = substr($from_obj->mailbox . "@" . strtolower($from_obj->host), 0, 30);
if($from_name == "") $from_name = $from_addr;
$from_name = Decode($from_name);

// 여기까지는 지난번 강좌에서 한 것과 동일하죠.. 설명 안하겠습니다.
?>
<table width=610 border=0 cellpadding=2 cellspacing=0 bordercolor=#E8E8E8>
<tr>
<td class="tk1" align="center" bgcolor="#EEEEEE" width="100">보낸날짜</td>
<td class="tk1" bgcolor="#F7F7F7"><?echo $date;?></td>
</tr>
<tr>
<td class="tk1" align="center" bgcolor="#EEEEEE">보낸이</td>
<td class="tk1" bgcolor="#F7F7F7"><?echo "<a href=mailto:$from_addr>$from_name</a>
";?></td>
</tr>
<tr>
<td class="tk1" align="center" bgcolor="#EEEEEE">제 &nbsp; 목</td>
<td class="tk1" bgcolor="#F7F7F7"><?echo $subject;?></td>
</tr>
</table>
<table width="610" border="0" cellpadding="4">
<tr>
<td class="tk1">
<?
checkstruct($mailstream, $MSG_NO);
imap_close($mailstream);

/*
위의 두개의 함수가 이번 강좌의 하이라이트죠... 하나 하나 설명합니다. 설명은 위에 해당 함수 선언된
곳을 보세요.
*/

?>
</td>
</tr>
</table>
<table width=610 border=0 cellpadding=4 cellspacing=0 bgcolor=#D8D8D8>
<tr>
<td class="tk1" width=40%></td>
<td align="right" class="tk1" width=60%>
<a href="mail_cmd.php?BOX=<?echo $box;?>&CMD=del&NO[]=<?echo $MSG_NO;?>">삭제</a>
&nbsp;&nbsp;&nbsp;&nbsp;
[<a href="mail_list.php?BOX=<?echo $box;?>">목록</a>]
</td>
</tr>
</table>
<br>
</body>
</html>
, .

1. 메일 확인
2. 메일 조회
3.메일 지우기
4. 메일 보내기

위의 순서에서 메일 확인 입니다.. 즉 사용자의 메일 박스를 뒤져서 메일 리스트를 화면에 출력해 주는 부분입니다.

mail_list.php

<html>
<body bgcolor="#FFFFFF" leftmargin=5 topmargin=20 marginwidth=5 marginheight=20>
<form name=frm method=post>
<?
$box = $BOX;
if($box == "") $box = "INBOX";

switch($box) {
case "INBOX":
$box_name="받은 편지함";
break;
case "sent":
$box_name="보낸 편지함";
break;
}

$login = "userid"; // 사용자 ID
$pass = "pwd"; // 사용자 비밀번호
$C_DOMAIN = "hagopa.co.kr"; // 서버 url

$mailstream = imap_open("{" . $C_DOMAIN . ":143}" . $box, $login, $pass);

if ($mailstream == 0) {
echo "Error!";
exit;
}
?>
<input type=hidden name=BOX value
="<?echo $box;?>">
<table width="610" border=0 bgcolor=#527900 cellpadding=4 cellspacing=0>
<tr>
<td align=center width="25" bgcolor="#334600">
<font face="Wingdings" size="4" color="#FFCC33">.</font></td> <td width="95%">
<font size="3" color="#FFFFFF"><b>편지읽기</b></font>

</td> </tr>
</table>
<table width="610" border="0" cellpadding="4" cellspacing="0">
<tr>
<td class="tk3">새편지 <?echo imap_num_recent($mailstream);?>개 /

<?echo imap_num_msg($mailstream);?>개 </td>
<td align=right class="tk3"></td>
</tr>
</table>

<table width="610" border="0" cellpadding="2" cellspacing="1">
<tr bgcolor="#E8E8E8">
<td class="tk1" align="right" width="8%">선택</td>
<td class="tk4" align="center" width=20%>받는이</td>
<td class="tk4" align="center" width=52%>제 목</td>
<td class="tk4" align="center" width=20%>날 짜</td>
</tr>
<?

/*

위에서 imap_num_recent 라는 함수와 imap_num_msg라는 함수는 새로운 편지와 총 메일의 수를 리턴해 주는 함수입니다.. 인자값으로는 메일스트림을 저정해 주면 되고요..

*/

$mailno = imap_sort($mailstream, SORTDATE, 1);

/*

연결된 메일박스에 있는 메일의 갯수와 함께.. 메일을 날짜 순으로 Desending 하는 부분입니다. 그리고 $mailno 에는 각 메일의 메일번호가 소트한 결과에 따라 차례로 배열로 저장됩니다. 이 번호를 가지고 루프를 돌리는 거죠... 아래 있습니다.

*/


if(count($mailno) == 0) {
?>
<tr bordercolor="#383838" height=35>
<td colspan=4 align=center class=tk1>편지함이 비어 있습니다.</td>
</tr>
<?
}

// 메일이 없을 경우 위와 같고요... 메일이 있는 경우 아래를 실행하겠죠.

for ($i=0;$i<count($mailno);$i++) { // 메일의 갯수만큼루프를 돕니다.
$no = $mailno[$i]; // 메일번호를 얻구요..
$head = imap_header($mailstream,$no);

// 얻어진 메일번호로 해당 메일의 헤더를 읽습니다.

$recent = $head->Recent; // 새메일 여부를 리턴해 줍니다.
$unseen = $head->Unseen; // 메일을 읽었는지 여부를 리턴해 주죠..
$msgno = trim($head->Msgno); // 메일번호

$date = date("Y/m/d H:i", $head->udate); // 메일의 날짜를 얻고
$subject = $head->Subject; // 제목을 얻습니다.

$subject = Decode($subject);

// 제목의 경우 OUT LOOK에서 보내면 인코딩을 자동으로 하기에 이를 디코딩해야 합니다.
//
그 부분을 처리해 주는 것으로 제가 만들었죠.. 그 내용은 맨 마지막에 있으니 참조하세요.


$from_obj = $head->from[0]; // 보낸 사람을 얻는 부분입니다. 그냥 아래처럼 사용하세요.
$from_name = $from_obj->personal;
$from_addr = substr($from_obj->mailbox . "@" . strtolower($from_obj->host), 0, 30);
if($from_name == "") $from_name = $from_addr;
$from_name = Decode($from_name);

if(strlen($from_name) > 13) $from_name = substr($from_name, 0, 10) . "...";

?>

<tr>
<td align=right><?echo $unseen;?> <input type=checkbox name=NO[] value=<?echo $msgno;?>></td>
<td>
<?echo "<a href=mailto:$from_addr>$from_name</a>";?></td>
<td><ahref="mail_detail.php? BOX=<?echo $box;?>&MSG_NO=<?echo $no;?>"><?echo$subject;?></a></td>
<td>
<?echo $date;?></td>
</tr>

<?
}

imap_close($mailstream);
?>
</table>
<SCRIPT LANGUAGE="JavaScript">
<!--
var selectVal = true;

function setSelected(button) {
for(var i=0;i<document.frm.length;i++) if(document.frm[i].name == 'NO[]') document.frm[i].checked = selectVal;
selectVal = selectVal ? false: true;
if (selectVal) {
button.value = '전체선택';

} else {
button.value = '전체해제';
}
return false;
}

function Delete(){
var count = 0;
for(var i=0;i<document.frm.length;i++){
if(document.frm[i].name == "NO[]" && document.frm[i].checked == true){ count++; }
}
if ( count != 0 ){
document.frm.action = "mail_cmd.php?CMD=del";
document.frm.submit();
} else { alert('삭제할 항목을 선택하세요!'); }
}
//-->
</SCRIPT>
<table width=610 border="0" bgcolor="#E8E8E8" cellspacing=0 cellpadding=3>
<tr>
<td class="tk3"><input type="button" name="Sub2" value="전체선택" onClick="setSelected(this);"></td>
<td align="right">
<input type=button name=HOWTO22 value="삭 제" class="tk1" onClick="Delete();">
</td> </tr>
</table>
<br>
</form>
</body>
</html>

위와 같네요.. 아까 위에서 나온 Decode라는 함수

OUTLOOK에서 보낸 메일만 테스트 했기에 다른 곳에서 보낼때 다르게 인코딩 되었다면

에러가 날 수도 있답니다.

<?
function Decode($val) {
if(substr($val,0,2) == "=?") {
//인코딩 여부 확인
$code = strpos($val, "?", 3);
$code = strpos($val, "?", $code+1);
$val = substr($val, $code+1, strlen($val)- $code-3);
return imap_base64($val);
} else { return $val; }
}
?>

위 함수를 본 파일 맨 위에 놓거나 다른 파일에 저장해서 include 해서 사용하면 됩니다. mail_lib.php 라고 만들어서 거기에 놓았죠
, .

1. 메일 확인
2. 메일 조회
3.메일 지우기
4. 메일 보내기

최소환경은

OS :Linux (커널버전 2.2.12-20kr)
WebServer : Apache 1.3.12
언어 : PHP 4.0.0 ( 컴파일시 -with-imap 옵션을 주어야 함)
SENDMAIL
IMAP
POP3

환경 확인PHP ( mail_test.php )


<?
$box = "INBOX";
$login = "userid";
$pass = "pwd";
$C_DOMAIN = "hagopa.co.kr";

$mailstream = imap_open("{" . $C_DOMAIN . ":143}" . $box, $login, $pass);

if ($mailstream == 0) {
echo "Error!";
exit;
} else {
echo "환경 OK!";
exit;
}
?>

, .

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


 

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

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

이진우

 


1. 소개

이번강좌에는 fork를 이용해서 새로운 프로세스를 생성하여 생성된 자식 서버프로세스가 클라이언트를 담당하는 형태를 구연해 보겠습니다.

PHP에서 fork함수로는 Process Control 함수의 pcntl_fork() 함수가 있습니다. Process Control 함수는 기본함수가 아니기 때문에 컴파일시 옵셥으로 추가시켜야 합니다.


2. pcntl_fork() 함수

 

 

int pcntl_fork ( )

함수 호출후 리턴값에 0이면 자식 프로세스이며 >0 이면 부모 프로세스로 자식 프로세스의 PID번호를 리턴 받습니다. error발생시에는 -1 값을 가집니다.

포크 함수는 포크 함수를 실행한 프로세스와 동일한 자식 프로세스를 생성합니다. 동일한 자식 프로세스라는 의미는 프로세스 계보상의 깊이만 다를뿐 동작은 똑같은 쌍둥이를 만드는 것 입니다.

자식 프로세스는 부모 프로세스의 메모리를 복사해서 클론을 만들고 리소스(파일 지시자, DB 커넥션, 소켓 커넥션 등)은 공유합니다.

간단하게 pcntl_fork() 코드를 살펴 보겠습니다.

<?php
$i = 0;
$pid = pcntl_fork();

// error
if($pid == -1)
{
echo "fork error";

// 부모 프로세스
}elseif($pid > 0)
{
for(;$i<10;$i++)
{
echo "Parent Process \$i : $i\n";
}

// 자식 프로세스
}elseif($pid == 0)
{
for(;$i<10;$i+=2)
{
echo "Child Process \$i : $i\n";
}
}
?>
부모 프로세스는 $i 값이 1씩, 자식 프로세스는 $i 값이 2씩 증가하는 프로그램 입니다. 결과는 각자 해보시기 바랍니다.

 


3. PHP 컴파일 하기

첫번째 강좌(PHP를 이용한 다중 연결 소켓 통신 (1)) 에서 소켓 함수를 사용하기 위해 --enable-sockets 옵션을 주어 컴파일 하였습니다.

오늘은 소켓 함수와 Process Control 함수를 추가시켜 컴파일 해보겠습니다.

 

#] tar -zxvf php-4.3.1.tar.gz
#] cd php-4.3.1
#] ./configure --enable-sockets --enable-pcntl
#] make

역시 php 실행파일이 생성됩니다.


4. 프로그램 작성

오늘 작성할 서버와 클라이언트의 구조는 아래와 같습니다.

 

┌───────┐ ┌───┐
┌─(Fork)─┤Child Process ├─(socket)─┤Client│
│ └───────┘ └───┘
┌───────┐ │ ┌───────┐ ┌───┐
│Master Process├─┼─(Fork)─┤Child Process ├─(socket)─┤Client│
└───────┘ │ └───────┘ └───┘
│ ┌───────┐ ┌───┐
└─(Fork)─┤Child Process ├─(socket)─┤Client│
└───────┘ └───┘
좀더 단순화 되고 직관적으로 표현되었군요.

Child Process 하나가 Client 하나를 독립적으로 마크하는 구조입니다.

연결이 끊어진 Child Process는 바로 소멸됩니다. 새로운 클라이언트가 참여하면 바로 Master Process는 pcntl_fork함수를 이용해서 Child Process를 생성하죠.


4.1. 서버 만들기

서버의 구조를 간단히 살펴보면

소켓생성
소켓바인트및 리슨
while(새로운연결수락)
{
포크
if(자식프로세스)
{
while(메시지수신)
{
메시지 처리
if(quit메시지)
{
소켓닫기
종료
}
}
}
}
구조 입니다. 메시지 처리 부분은 지난 강좌(PHP를 이용한 다중 연결 소켓 통신 (2))의 메시지 처리 부분과 동일하며 select처리 대신 fork를 이용한 처리 입니다.

 

#!/usr/local/bin/php -q
<?php
set_time_limit(0);

define("_IP", "111.222.333.12");
define("_PORT", "65000");

$sSock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

socket_bind($sSock, _IP, _PORT);
socket_listen($sSock);

pcntl_signal(SIGCHLD, SIG_IGN);

while($sock = socket_accept($sSock))
{
socket_getpeername($sock, $sockIp, $sockPort);
msg("client connect : ".$sockIp.":".$sockPort."\n");

$pid = pcntl_fork();
msg("fork\n");
if($pid == -1)
{
msg("fork failed\n");
exit;
// 자식 프로세스 일때
}if($pid == 0)
{
while(1)
{
$buf = socket_read($sock, 4096);

// 접속 종료
if(!$buf)
{
msg("client connection broken : ".$sockIp.":".$sockPort."\n");
exit;
}
// 메시지 수신 이벤트
else
{
msg("recive data : ".$buf."\n");
$cmd = substr($buf, 0, 4);
switch($cmd)
{
// 시간전송
case "time":
msg("client(".$sockPort.") time data request\n");
socket_write($sock, date("Y/m/d H:i:s"));
break;

// 종료
case "quit":
msg("client(".$sockPort.") quit request\n");
socket_write($sock, "quit");
socket_close($sock);
exit;
break;
default:
msg("client(".$sockPort.") invalid command $cmd\n");
break;
}
}
}
}
}

function msg($msg)
{
echo "SERVER >> ".$msg;
}
?>

역시 server.php로 저장하고 실행권한을 줍니다.


4.2. 클라이언트 만들기

클라이언트는 지난 강좌(PHP를 이용한 다중 연결 소켓 통신 (2))에서 사용한 클라이언트 프로그램을 수정없이 그대로 사용합니다.


4.3. 실행하기

server.php를 실행 후 client.php를 3번 실행하고 프로세스와 프로세스 트리를 확인해보겠습니다.

server.php 실행 화면

#] ./server.php
SERVER >> client connect : 111.222.333.12:38276 -- (1)
SERVER >> fork
SERVER >> fork
SERVER >> recive data : time
SERVER >> client(38276) time data request
SERVER >> client connect : 111.222.333.12:38396 -- (2)
SERVER >> fork
SERVER >> fork
SERVER >> recive data : time
SERVER >> client(38396) time data request
SERVER >> client connect : 111.222.333.12:38559 -- (3)
SERVER >> fork
SERVER >> fork
SERVER >> recive data : time
SERVER >> client(38559) time data request -- (4)
SERVER >> recive data : quit
SERVER >> client(38276) quit request -- (5)
SERVER >> recive data : quit
SERVER >> client(38396) quit request -- (6)
SERVER >> recive data : quit
SERVER >> client(38559) quit request -- (7)

client는 (1), (2), (3)에서 3번 실행하여 동일하게 time 메시지를 송신 및 데이타를 수신하고 하고 quit 했습니다.

#] ./client.php
CLIENT >> socket connect to 111.222.333.12:65000
CLIENT >> Enter command time or quit : time
CLIENT >> Input command : time
CLIENT >> recived data : 2003/05/21 16:18:34
CLIENT >> Enter command time or quit : quit
CLIENT >> Input command : quit
#]

아래는 (3),(7)시점에서 두번 프로세스 현황을 확인(ps, pstree)한 결과 입니다.

#] ps -xa | grep server.php
30947 pts/3 S 0:00 /usr/local/bin/php -q ./server.php
31203 pts/3 S 0:00 /usr/local/bin/php -q ./server.php
31287 pts/3 S 0:00 /usr/local/bin/php -q ./server.php
31372 pts/3 S 0:00 /usr/local/bin/php -q ./server.php
31467 pts/7 S 0:00 grep server.php
#] pstree
init-+-crond
...
...
|-sshd-+-sshd---bash---server.php---3*[server.php]
| |-3*[sshd---bash---client.php]
| `-sshd---bash---pstree
...
...
`-xinetd
#]
#] ps -xa | grep server.php
30947 pts/3 S 0:00 /usr/local/bin/php -q ./server.php
31521 pts/7 S 0:00 grep server.php
#] pstree
init-+-crond
...
...
|-sshd-+-sshd---bash---su---bash---server.php
| |-3*[sshd---bash]
| `-sshd---bash---pstree
...
...
`-xinetd
#]
(3) 시점에는 fork 3번 실행한 순간이므로 부모 프로세스와 자식 프로세스 3개, 총 4개의 프로세스가 실행되고 있는것을 확인할수 있습니다.

pstree의 경우는 server.php---3*[server.php]처럼 Master Process 한개Child Process 3개로 표현되어 있습니다. 문론 메시지도 잘 전송 되었구요.. ^^


5. 결론

오늘은 PHP의 Process Control Function을 이용하여 다수의 클라이언트 요청처리를 해보았습니다.

fork방식은 select방식보다 간단한 구조로 구현하기 간편하다는 장점도 있지만, 다중 프로세스 구조라 프로세스간 통신을 위해서 부차적인 IPC를 구현해야 할 상황이 생길 수도 있다는 점이 단점이라 할 수 있습니다.

다음 강좌에는 mysql과 지금까지 배운 소켓 통신을 가지고 간단한 채팅 클라이언트/서버를 만들어 보겠습니다.


, .