#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<signal.h>
#include<sys/wait.h>
#include<errno.h>
void sigHandler(int sig)
{
int pid;
int status;
pid = wait(&status);
printf("pid[%d] terminated\n",pid);
}
int process_init()
{
int state;
struct sigaction act;
act.sa_handler = sigHandler;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
state = sigaction(SIGCHLD,&act,0);
if(state !=0)
{
printf("signal error\n");
exit(1);
}
}
int sock_init(int port)
{
struct sockaddr_in server_addr;
int server_fd;
int len;
if((server_fd = socket(AF_INET, SOCK_STREAM,0))==-1)
{
printf("socket error\n");
exit(0);
}
memset(&server_addr, 0x00, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))<0)
{
printf("bind error\n");
exit(0);
}
if(listen(server_fd,5)<0)
{
printf("listen error\n");
exit(0);
}
return server_fd;
}
int do_write(int fd,char *buf)
{
return write(fd,buf,strlen(buf));
}
int do_read(int fd, char *buf)
{
return read(fd,buf,sizeof(buf));
}
int service(int fd)
{
char buf[120];
do_write(fd,"Hello Sir?\n");
do_read(fd,buf);
exit(1);
}
int main(int argc, char *argv[])
{
int server_fd,client_fd;
pid_t pid;
int len;
struct sockaddr_in client_addr;
if(argc !=2)
{
printf("usage : %s [port]\n",argv[0]);
return 0;
}
process_init();
server_fd = sock_init(atoi(argv[1]));
while(1)
{
len = sizeof(client_addr);
if((client_fd = accept(server_fd ,(struct sockaddr *)&client_addr, &len))<0)
{
if(errno == EINTR)
continue;
else
printf("accept error\n");
}
if((pid = fork())<0)
{
printf("fork error\n");
exit(0);
}
else if(pid > 0)
{
close(client_fd);
continue;
}
else if(pid == 0)
{
close(server_fd);
service(client_fd);
}
}
}
sock_init 함수는 socket, bind, listen 함수로 서버 설정을 하는 함수이다.
fork를 통해 자식프로세스를 생성한다 => 부모면 그대로 서버소켓 유지, 자식이면 서비스 실행.
SIGCHLD 시그널을 처리하기 위해 sigaction 함수를 쓴다.
wait 함수는 자식프로세스의 종료 상태를 가져올 때까지 부모를 기다리게 할 수 있다.
accept문을 그냥 쓰면 무한반복되는데 이를 방지하기 위해 errno가 EINTR 일 때에도 처리해준다.