현생/TCP 소켓 프로그래밍
10-6 멀티프로세스 기반 다중접속 서버 구현 [TCP/IP][C][LINUX]
푸더기
2022. 1. 30. 14:12
반응형
10-4, 10-5에서 쓰인 시그널 핸들링을 이용하면 멀티 프로세스 기반의 다중접속 서버를 구현할 수 있습니다.
위 그림은 이번에 구현할 멀티프로세스 기반 다중접속 에코 서버의 구현모델입니다. 클라이언트의 수가 둘이면 두 개의 자식 프로세스, 다섯이면 5 개의 자식 프로세스를 가지게 됩니다. 따라서 에코서버는 다음의 과정을 거쳐야 합니다.
1. 에코 서버의 부모프로세스는 accept 함수 호출을 통해 연결 요청 수락
2. 이때 얻게 되는 소켓의 파일 디스크립터 자식 프로세스 생성 후 넘겨줌
3. 자식 프로세스는 전달받은 파일 디시크립터를 바탕으로 서비스 제공
여기서 2번은 자식 프로세스는 생성될 때 부모 프로세스를 전부 복사하므로 따로 처리할 과정은 없습니다.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#define BUF_SIZE 30
void error_handling(char *message);
void read_childproc(int sig);
int main(int argc, char *argv[]){
int serv_sock, clnt_sock;
struct sockaddr_in serv_adr, clnt_adr;
pid_t pid;
struct sigaction act;
socklen_t adr_sz;
int str_len, state;
char buf[BUF_SIZE];
if(argc!=2){
printf("Usage : %s <port>\n",argv[0]);
exit(1);
}
act.sa_handler=read_childproc;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
state=sigaction(SIGCHLD, &act, 0);
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
serv_adr.sin_port=htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
error_handling("bind() error");
if(listen(serv_sock, 5)==-1)
error_handling("listen() error");
while(1){
adr_sz=sizeof(clnt_adr);
clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
if(clnt_sock==-1)
continue;
else
puts("new client connected...");
pid=fork();
if(pid==-1){
close(clnt_sock);
continue;
}
if(pid==0){//자식 프로세스 실행 영역
close(serv_sock);
while((str_len=read(clnt_sock,buf,BUF_SIZE))!=0)
write(clnt_sock, buf, str_len);
close(clnt_sock);
puts("client disconnected...");
return 0;
}
else
close(clnt_sock);
}
close(serv_sock);
return 0;
}
void read_childproc(int sig){
pid_t pid;
int status;
pid=waitpid(-1, &status, WNOHANG);
printf("removed proc id: %d \n",pid);
}
void error_handling(char *message){
fputs(message, stderr);
fputc('\n',stderr);
exit(1);
}
멀티프로세스기반 다중접속 에코서버의 코드입니다. 클라이언트는 https://pupuduck.tistory.com/32에서 쓰인 echo_client2를 사용하면 됩니다.
while문 안에서 accept를 받으면 자식 프로세스를 생성하고, 자식 프로세스에서 서비스를 제공합니다.
위 예제에서 자식 프로세스는 부모 프로세스의 파일 디스크립터를 복사하는데, 이때 소켓은 프로세스의 소유가 아닌 운영체제의 소유이기에 복사되지 않습니다. 해당 소켓을 가리키는 파일 디스크립터만 프로세스의 소유이고, 소켓이 복사가 된다면 같은 PORT를 갖는 소켓이 둘 이상 생기는 것이기에 말이 안됩니다.
소켓이 소멸되기 위해선 자신을 가리키는 파일 디스크립터가 없어야하는데, 자식 프로세스가 부모 프로세스의 파일 디스크립터를 복사해갔으므로 자식 프로세스와 부모 프로세스 둘 다 파일 디스크립터를 각자 닫아줘야 합니다.
반응형