==================================Outline====================================
채팅 멀티프로세스
----------------------------------------------------------------------------
채팅 멀티프로세스
리눅스에서는 프로그램의 리턴 값이 저장되고 echo $? 명령어를 사용하여 그 return 값을 출력할 수 있다.

//아무 일도 수행하지 않는 프로세스를 좀비 프로세스라고 한다.
fork함수를 사용하여 서버와 클라이언트의 멀티 프로세스 작업을 해보자.
우선 fork를 사용하기 위해여 헤더파일이 <unistd.h>를 추가해준다.
다음 fork함수의 리턴 값을 받기 위해 타입이 정의된 pid_t 변수를 하나 선언해 준다.
fork함수의 리턴 값이 0보다 크면 부모 프로세스이고 이 값은 프로세스 ID를 반환한다.
반면에 자식 프로세스는 0을 반환한다.
우선 fork함수를 통하여 클라이언트에서 쓰기/읽기를 분리하자.
write와 read함수 무한 while문 전에 fork 함수를 사용하여 프로세스를 복사한다.
부모 프로세스에는 읽기/자식 프로세스는 쓰기만 하도록 if문을 사용하여 분리해준다.
서버에서는 랑데부 소켓(클라이언트 연결 전용)과 커뮤니케이션 소켓(통신전용)을 사용한다.
if문을 사용하여 분리한다.
/*** 소스 ***/
<server.c>
#include "smartsock.h" #include <unistd.h>
int main(void) { int iSock; //소켓 함수의 반환 값을 받는 변수 int icSock; //accept의 반환 값을 받는 변수 int iRet; struct sockaddr_in stAddr; socklen_t uiSockLen=sizeof(struct sockaddr); char cBuff[BUF_SIZE]; const char * cP; pid_t pid;
iSock = socket(AF_INET, SOCK_STREAM, 0); //AF_INET = 2, if(0 > iSock) { perror("socket : "); return -1; } // stAddr구조체에 socket연결을 위한 필수 정보 입력 setting bzero(&stAddr, sizeof(stAddr)); //구조체 비우기(0으로 채우기) stAddr.sin_family = AF_INET; //#define AF_INET 2 /* IP protocol family. */ stAddr.sin_addr.s_addr = inet_addr(IP); //IP와 PORT값은 헤더파일에 정의되어 있다. stAddr.sin_port = htons((PORT));
iRet = bind(iSock, (struct sockaddr *)&stAddr,sizeof(stAddr)); if(iRet < 0) { perror("bind : "); close(iSock);
return -2; } iRet = listen(iSock, 5); if(iRet != 0) { perror("listen : "); close(iSock);
return -3; } while(1) { icSock = accept(iSock, (struct sockaddr *)&stAddr, &uiSockLen); //접속자의 정보가 stAddr에 입력된다.
if(icSock < 0) { perror("Accept : "); close(iSock);
return -4; } /////////////////////////////멀티 프로세스/////////////////////////////////////////// pid = fork();
if(pid == 0) //자식 프로세스이면 while문 break { break; } } close(iSock);
printf("Incoming Client \n"); //cP = inet_ntoa(stAddr.sin_addr); printf("Client IP :%s\n", inet_ntoa(stAddr.sin_addr)); printf("Client Port : %d\n", ntohs(stAddr.sin_port));
write(icSock, "Welcome :)", sizeof("Welcome :)"));
while(1) { read(icSock, cBuff, MSG_SIZE); printf("[client]: [%s]\n", cBuff);
write(icSock, cBuff, MSG_SIZE); if(0 == strncmp(MSG_END, cBuff, strlen(MSG_END) ) ) break;
} close(icSock); return 0; }
|
<client.c>
#include "smartsock.h" #include <unistd.h>
int main(void) { struct sockaddr_in stAddr; int iSock; int iRet; char cBuff[BUF_SIZE]; socklen_t uiSockLen=sizeof(struct sockaddr); pid_t pid;
iSock = socket(AF_INET, SOCK_STREAM, 0); if(0 > iSock) { perror("socket : "); return -1; }
bzero(&stAddr, sizeof(stAddr)); stAddr.sin_family = AF_INET;
stAddr.sin_addr.s_addr = inet_addr("192.168.0.173"); stAddr.sin_port = htons((PORT));
iRet = connect(iSock, (struct sockaddr *)&stAddr, uiSockLen); if(0 > iRet) { perror("connect : "); return -2; }
pid = fork();
if(pid > 0) { close(0); while(1) { read(iSock, cBuff, MSG_SIZE); printf("[server]: [%s]\n", cBuff);
if(0 == strncmp(MSG_END, cBuff, strlen(MSG_END))) break; }
} else { close(1); while(1) { iRet = read(0, cBuff, MSG_SIZE); cBuff[iRet-1] = 0; write(iSock, cBuff, MSG_SIZE);
}
}
close(iSock); return 0; }
|
여러 개의 클라이언트가 접속했음을 알 수 있다.


멀티 프로세서 분리된 서버/클라이언트의 통신은 가능하지만 서버 간의 통신이 없기 때문에 분리된 클라이언트들은 다른 클라이언트가 서버로 보낸 메시지를 볼 수 없다. 때문에 PIC(Internal Process Communication)이 필요하다.
To be continued...