본문 바로가기
IT/데이터베이스_네트워크

윤성우의 열혈 tcp/ip 소켓 프로그래밍 16장, 17장 연습문제 솔루션

by nutrient 2021. 5. 24.
728x90
728x170

 


정    답 1.  a, b, c, e

정    답 2.  옳지 않은 것 없음. 모두 옳음 


정    답 1.
select 함수호출 이후에 항상 등장하는, 모든 파일 디스크립터를 대상으로 하는 반복문
select 함수를 호출할 때마다 인자로 매번 전달해야 하는 관찰대상에 대한 정보들

정    답 2.
select와 epoll은 파일 디스크립터, 정확히 말하면 소켓변화의 관찰이 요구되는 방식이다. 그런데 소켓은 운영체제에 의해 관리가 된다. 즉, select 방식과 epoll 방식은 절대적으로 운영체제에 의해 완성되는 함수이다. 때문에 관찰대상의 정보를 운영체제에게 전달해야 한다.

정    답 3.
epoll은 select 방식과 달리 관찰의 대상이 되는 파일 디스크립터의 정보를 한번씩만 전달하면 된다. epoll 방식은 select 방식의 단점을 극복하여 리눅스 커널에서 관찰의 대상 정보를 기억하는 방식이기 때문이다.  

정    답 4.
서버의 접속자 수가 많지 않으면서(고성능이 요구되지 않으면서), 다양한 운영체제에서 운영이 가능해야 하는 경우.

정    답 5.
레벨 트리거 방식에서는 입력버퍼에 데이터가 남아있는 동안 계속해서 이벤트가 등록된다. 반면 엣지 트리거 방식에서는 입력버퍼에 데이터가 들어올 때 이벤트가 등록된다.

정    답 6.
엣지 트리거 방식을 사용하면 입력버퍼에 데이터가 수신될 때 딱 한번만 이벤트가 발생하고, 입력버퍼에 데이터가 남아있는 동안에는 이벤트가 발생하지 않기 때문에 데이터가 수신된 이후에 원하는 시점에 가서 데이터를 처리할 수 있다. 그리고 이렇게 데이터의 수신과 처리의 시점을 분리하면 서버 구현에 엄청난 유연성을 갖게 된다. 


 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>

#define BUF_SIZE 100
#define MAX_CLNT 256
#define EPOLL_SIZE 50

void setnonblockingmode(int fd);
void error_handling(char *buf);
void send_msg(char * msg, int len);

int clnt_cnt=0;
int clnt_socks[MAX_CLNT];

int main(int argc, char *argv[])
{
	int serv_sock, clnt_sock;
	struct sockaddr_in serv_adr, clnt_adr;
	socklen_t adr_sz;
	int str_len, i;
	char buf[BUF_SIZE];

	struct epoll_event *ep_events;
	struct epoll_event event;
	int epfd, event_cnt;

	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");

	epfd=epoll_create(EPOLL_SIZE);
	ep_events=malloc(sizeof(struct epoll_event)*EPOLL_SIZE);

	setnonblockingmode(serv_sock);
	event.events=EPOLLIN;
	event.data.fd=serv_sock;	
	epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);

	while(1)
	{
		event_cnt=epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
		if(event_cnt==-1)
		{
			puts("epoll_wait() error");
			break;
		}

		puts("return epoll_wait");
		for(i=0; i<event_cnt; i++)
		{
			if(ep_events[i].data.fd==serv_sock)
			{
				adr_sz=sizeof(clnt_adr);
				clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
				setnonblockingmode(clnt_sock);
				event.events=EPOLLIN|EPOLLET;
				event.data.fd=clnt_sock;
				epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event);
				clnt_socks[clnt_cnt++]=clnt_sock;
				printf("connected client: %d \n", clnt_sock);
			}
			else
			{
					while(1)
					{
						str_len=read(ep_events[i].data.fd, buf, BUF_SIZE);
						if(str_len==0)    // close request!
						{
							epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
							close(ep_events[i].data.fd);

							for(i=0; i<clnt_cnt; i++) 
							{
								if(ep_events[i].data.fd==clnt_socks[i])
								{
									while(i++<clnt_cnt-1)
										clnt_socks[i]=clnt_socks[i+1];
									break;
								}
							}
							clnt_cnt--;
							printf("closed client: %d \n", ep_events[i].data.fd);
							break;
						}
						else if(str_len<0)
						{
							if(errno==EAGAIN)
								break;
						}
						else
						{
							send_msg(buf, str_len);
						}
				}
			}
		}
	}
	close(serv_sock);
	close(epfd);
	return 0;
}


void send_msg(char * msg, int len)   // send to all
{
	int i;
	for(i=0; i<clnt_cnt; i++)
		write(clnt_socks[i], msg, len);
}
void setnonblockingmode(int fd)
{
	int flag=fcntl(fd, F_GETFL, 0);
	fcntl(fd, F_SETFL, flag|O_NONBLOCK);
}
void error_handling(char *buf)
{
	fputs(buf, stderr);
	fputc('\n', stderr);
	exit(1);
}

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>

#define BUF_SIZE 100
#define MAX_CLNT 256
#define EPOLL_SIZE 50
void error_handling(char *buf);
void send_msg(char * msg, int len);

int clnt_cnt=0;
int clnt_socks[MAX_CLNT];

int main(int argc, char *argv[])
{
	int serv_sock, clnt_sock;
	struct sockaddr_in serv_adr, clnt_adr;
	socklen_t adr_sz;
	int str_len, i;
	char buf[BUF_SIZE];

	struct epoll_event *ep_events;
	struct epoll_event event;
	int epfd, event_cnt;

	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");

	epfd=epoll_create(EPOLL_SIZE);
	ep_events=malloc(sizeof(struct epoll_event)*EPOLL_SIZE);

	event.events=EPOLLIN;
	event.data.fd=serv_sock;	
	epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);

	while(1)
	{
		event_cnt=epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
		if(event_cnt==-1)
		{
			break;
		}

		for(i=0; i<event_cnt; i++)
		{
			if(ep_events[i].data.fd==serv_sock)
			{
				adr_sz=sizeof(clnt_adr);
				clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
				event.events=EPOLLIN;
				event.data.fd=clnt_sock;
				epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event);
				clnt_socks[clnt_cnt++]=clnt_sock;
				printf("connected client: %d \n", clnt_sock);
			}
			else
			{
				str_len=read(ep_events[i].data.fd, buf, BUF_SIZE);
				if(str_len==0)  
				{
					epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
					close(ep_events[i].data.fd);
					printf("closed client: %d \n", ep_events[i].data.fd);

					for(i=0; i<clnt_cnt; i++) 
					{
						if(clnt_sock==clnt_socks[i])
						{
							while(i++<clnt_cnt-1)
								clnt_socks[i]=clnt_socks[i+1];
							break;
						}
					}
					clnt_cnt--;
				}
				else
				{
					send_msg(buf, str_len);
				}
			}
		}
	}
	close(serv_sock);
	close(epfd);
	return 0;
}

void send_msg(char * msg, int len)   // send to all
{
	int i;
	for(i=0; i<clnt_cnt; i++)
		write(clnt_socks[i], msg, len);
}

void error_handling(char *buf)
{
	fputs(buf, stderr);
	fputc('\n', stderr);
	exit(1);
}

728x90
그리드형

댓글