목적 : 멀티플렉싱 기반 서버 구현에 대한 이해, 멀티플렉싱 특징
프로그램 :
1. 멀티플렉싱을 이용해서 다수의 클라이언트에 서비스. 단, 한번에 하나의 클라이언트만 처리함.
2. select함수 사용
멀티프로세스 기반 서버는 프로세스 생성에 상당한 오버헤드가 든다. IPC가 필요한 상황에서 코딩하기도 매우 힘들다.
멀티플렉싱 : 하나의 통신채널을 통해 둘 이상의 데이터(시그널)를 전송하는데 사용되는 기술.
->멀티플렉싱을 이용하면 하나의 프로세스로 다수의 client를 상대하는 서버를 구현할 수 있다.
select함수와 사용되는 구조체
#include <sys/select.h>
#include <sys/time.h>
int select(int maxfd, fd_set *readset, fd_set *writeset,
fd_set *exceptset, const struct timeval * timeout);
/*
오류시 -1, 타임아웃 시 0 반환
readset, writeset, exceptset에 등록된 fd에 변화가 발생하면 변화가 발생한 fd의 개수 반환
maxfd : 검사 대상이 되는 파일 디스크립터 개수
readset : 수신 데이터 존재여부 검사
writeset : 데이터 전송(non-blocking)의 가능여부 검사
excetpset : 예외상황 발생여부 검사
timeout : 무한정 블로킹되지 않도록 timeout 설정
*/
/* 자료형 설명
timeval : 시간 설정
fd_set : 최대 1024개의 비트를 설정할 수 있는 구조체.
-> FD_ZERO, FD_SET, FD_CLR, FD_ISSET사용해서 설정
*/
<echo_selectserv.c> 여태 사용했던 아무 echo_client 처리가능
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#define BUF_SIZE 100
void error_handling(char * buf);
int main(int argc, char ** argv){
int serv_sock, clnt_sock;
struct sockaddr_in serv_adr, clnt_adr;
struct timeval timeout;
fd_set reads, cpy_reads;
socklen_t adr_sz;
int fd_max, str_len, fd_num, i;
char buf[BUF_SIZE];
if(argc!=2){
printf("Usage: %s <port>\n", argv[0]);
exit(1);
}
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");
//~~서버소켓을 만들고 bind, listen하는것 똑같음
FD_ZERO(&reads);
FD_SET(serv_sock, &reads); //데이터 수신여부를 관찰하는 대상에 서버소켓 포함시키기.
fd_max = serv_sock; //index = fd_max 까지 확인할 것. (개수는 fd_max+1)
while(1){
cpy_reads = reads;
//timeout = 6
timeout.tv_sec = 5;
timeout.tv_usec = 5000;
if((fd_num = select(fd_max+1, &cpy_reads, 0 , 0, &timeout))==-1)//error
break;
if(fd_num==0) //timeout
continue;
//serv_sock에 변화가 있었다면 새로운 연결 요청 받았다는 것
//그 외(당연히 3이상)에 변화가 있었다면 메세지를 수신한 것
for(i=0; i<fd_max+1; i++){
if(FD_ISSET(i, &cpy_reads)){ //수신된 데이터가 있는 소켓 감지
if(i==serv_sock){ //connection request!
adr_sz = sizeof(clnt_adr);
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
FD_SET(clnt_sock, &reads);
if(fd_max < clnt_sock)
fd_max=clnt_sock;
printf("connected client: %d\n", clnt_sock);
}
else{ //read message!
str_len = read(i, buf, BUF_SIZE);
if(str_len==0){ //close request
FD_CLR(i, &reads);
close(i);
printf("closed client: %d\n", i);
}
else{ //echo
write(i, buf, str_len);
}
}
}
}
}
close(serv_sock);
return 0;
}
void error_handling(char * buf){
fputs(buf, stderr);
fputc('\n', stderr);
exit(1);
}
'CS > 컴퓨터네트워크' 카테고리의 다른 글
TCP/IP (1) (0) | 2020.12.22 |
---|---|
[열혈] 멀티쓰레드 기반 서버구현 (0) | 2020.12.22 |
[열혈] 멀티 프로세스 기반 서버구현 (2) | 2020.10.25 |
[열혈] dns (0) | 2020.10.24 |
[열혈] half close (0) | 2020.10.24 |