socketProg_select

Eden.Yang·2023년 11월 16일
0

Computer Network

목록 보기
24/25

I/O : selecting

필요성을 이해해야. block함수에 걸리는지 점검해야.

Assume that a process is handling two inputs at the same time, that is, standard input and a socket.If the process calls to read from a standard input, it is blocked until it receives data from the standard input. That is, the process can not receive data from a socket because it is blocked to read from the standrad input.

어떤 프로세스가 동시에 두개의 인풋을 받는다고 할 때(write도block함수이긴 하지만 packet을 주고받을 때까지가 아니라 자신의 시스템 내에서 return이되니 괜찮은데 read가 문제임) standard input그리고 소켓으로부터

standardinput으로부터의 read함수를 불렀다, 일반적으로 read는 block함수임. standardinput으로부터 입력이 들어오기 전까지 더이상 진행이 안됨.

read이후 block이 되면 kernel에게 요청을 한다. 그 상태에서 커널쪽에서 데이터가 들어올 때까지 기다린다. 데이터가 오면 그걸 read에게 넘겨준다. 그 동안은 모든 프로그램이 진행이 안 된다.

blcok 함수를 read를 부르면 시스템 콜이 되고 커널에서는 데이터가 있으면 주는데 데이터가 없어도 그냥 Ewouldblick으로 리턴해준다. 현재 상태를 알려주는 것. 다시 말해 데이터가 없다는 것을 알려줌.

자신이 기다리는 인풋, 파일 디스크립터가 뭔지 등록을 해서 커널에게 요청을 한다. standard input과 어떤 소켓. 여기서 일단 블락이 된다. 모니터링 하고자 하는 파일 쪽 이벤트가 발생할 때까지 블락이 된다. 만약 둘 중하나라도 이벤트가 발생하면 리턴이 된다. 데이터가 어베일러블한게 리턴된다. 리턴 안의 정보를 가지고 누가 누구로부터 데이터가 발생했는지 확인해서 실행. 여러개의 인풋 처리 가능.

시그널이 발생. 시그널 핸들러 쪽에서 그걸 읽어서 데이터를 처리.

aio함수를 부르면 등록하고 리턴이된다. 일반적으로 콜백함수를 등록시켜서 데이터를 등록하면 콜백함수가 호출된다.

sync는 함수를 부르는 것과 거기에 맞춰서 실행이됨. 블락, 논블락, 멀티플렉싱이 여기에 해당

async는 부르는 것과 실행이 별도임.

select

#include <sys/select.h>
#include <sys/time.h>

int select(int n, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval* timeout)

이벤트가 발생하길 원하는 게 뭔지 알려줌. 특정시간동안 혹은 무한대 동안 이벤트가 발생할 때까지 블락됨. int n은 가장 큰 수의 소켓(파일)디스크립터보다 하나 큰 값. 파일 디스크립터는 0부터 시작인데 예를 들어 standard input으로만 데이터가 오는 걸관찰하려면 0이니까 1을 주게 됨. 내가 모니터링하려는 값까지의 +1을 줘야함.

fd_set은 read쪽, write쪽, except쪽 이렇게 세개를 줘야 힘. 각각을 등록을 시켜서 시스템이 이벤트 발생을 확인하게 됨. timeout은 시간. write쪽은 잘 안 함. 즉시 리턴되기에 대부분 *readfds를 함.


timeout을 null로 주면 이벤트 발생까지 가만히 있음.
time을 0으로 하면 즉시 리턴함. 그래서 return value가 int인 것임. 정상적으로는 -1이 없다. timeout은 0. 주어진 시간 동안 이벤트가 발생 안 했다. 그 외에는 이벤트가 발생한 개수임.

readfds를 등록할 때 0~1023번까지 가능하다. 얘들은 체크해야 하는 파일 디스크립터가 하나에 한 비트씩 할당. 다시말해 1024비트가 필요함. 128바이트가 됨. 그래서 원하는 위치에 set시키는 게 어렵다. 그걸 쉽게 하기 위해

매크로 펑션이 세팅 되어 있다. fd set이라는 변수값이 어떤 파일 디스크립터를 1로 만드는 것.

zero는 다 클리어

포인터를 주고 1로 하면 그것만 1로 set
2를 클리어하면 걔만 클리어

어떤 경우에 해당하는 파일 디스크립터?

제일 중요한 건 readble?read쪽에서는 해당하는 디스크립터 쪽에서 수신한 데이터가 있으면 이벤트가 발생한다. 리슨하는 소켓 쪽에서 뉴커넥션, 클라이언트로부터 커넥션 리퀘스트도 read이벤트가 발생한다. 클라이언트가 close가 되어 있다. write

select함수에서 어느 파일descriptor에서 이벤트가 발생했는지 알기 위해서 첫번째 같은 경우 0,3번 파일 디스크립터의 리드 이벤트가 있는지 모니터링 하는 것임. 1,2번은 0이니까 안 함. 0은 키보드 인풋, 1번은 스탠다드 아웃풋 에러..리턴이 될 때는 네가 어떤 파일디스크립터에서 발생했는지 알려주기 위해 동일한 변수에값이 이벤트가 발생한 것만 1로 유지시킴. 이것만 잘 알면 돌아가는데 문제가 없다.

select

#define BUFSIZE 30
int main(int argc, char **argv){
fd_set reads, temps;
int result;
char message[BUFSIZE];
int str_len;
struct timeval timeout;
FD_ZERO(&reads);
FD_SET(0, &reads); /* standard input  */
while(1){
temps = reads;
timeout.tv_sec = 5;
timeout.tv_usec = 0; 
result = select(1, &temps, 0, 0, &timeout);
if (result == -1) {   /*errors in select */
puts("select error!");
exit(1);
}
else if (result == 0){   /* time-out*/
puts(“time-out! : select ");
}
else {  /* change in fd*/
if(FD_ISSET(0, &temps)) 
{
str_len = read(0, message, BUFSIZE);
message[str_len] = ‘\0;
fputs(message, stdout);
}
}
} /* while(1) */
}

int main(int argc, char **argv){int serv_sock;struct sockaddr_in serv_addr;fd_set reads, temps;int fd_max;char message[BUFSIZE];int str_len;struct timeval timeout;if(argc!=2){printf("Usage : %s <port>\n", argv[0]);exit(1);}serv_sock = socket(PF_INET, SOCK_STREAM, 0);serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);serv_addr.sin_port = htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)))error_handling("bind() error");if(listen(serv_sock, 5) == -1)error_handling("listen() error");
FD_ZERO(&reads);FD_SET(serv_sock, &reads);fd_max = serv_sock;while(1){int fd, str_len;int clnt_sock, clnt_len;struct sockaddr_in clnt_addr;temps = reads;timeout.tv_sec = 5;timeout.tv_usec = 0; if (select(fd_max+1, &temps, 0, 0, &timeout) == -1)error_handling("select() error");
Jong-won Lee 13ljw@handong.eduDescriptor setsExample Jong-won Lee 14ljw@handong.eduSelect functionConditions that cause a socket to be ready for selectconditionReadable?Writable?Exception?Data to read oNew connection ready from listening socketoRead-half closed(FIN received)oSpace avaliable for writingoWrite-half closedoTCP out-of-band dataoJong-won Lee 15ljw@handong.eduSelect functionExample : how to know which fds are ready?fd3 is readyJong-won Lee 16ljw@handong.eduSelect()Example 1#define BUFSIZE 30int main(int argc, char **argv){fd_set reads, temps;int result;char message[BUFSIZE];int str_len;struct timeval timeout;FD_ZERO(&reads);FD_SET(0, &reads); /* standard input  */while(1){temps = reads;timeout.tv_sec = 5;timeout.tv_usec = 0; result = select(1, &temps, 0, 0, &timeout);Jong-won Lee 17ljw@handong.eduSelect()Example 1if (result == -1) {   /*errors in select */puts("select error!");exit(1);}else if (result == 0){   /* time-out*/puts(“time-out! : select ");}else {  /* change in fd*/if(FD_ISSET(0, &temps)) {str_len = read(0, message, BUFSIZE);message[str_len] = ‘\0’;fputs(message, stdout);}}} /* while(1) */}Jong-won Lee 18ljw@handong.eduSelect()Example 1Jong-won Lee 19ljw@handong.eduSelect()Example 2int main(int argc, char **argv){int serv_sock;struct sockaddr_in serv_addr;fd_set reads, temps;int fd_max;char message[BUFSIZE];int str_len;struct timeval timeout;if(argc!=2){printf("Usage : %s <port>\n", argv[0]);exit(1);}serv_sock = socket(PF_INET, SOCK_STREAM, 0);serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);serv_addr.sin_port = htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)))error_handling("bind() error");if(listen(serv_sock, 5) == -1)error_handling("listen() error");Jong-won Lee 20ljw@handong.eduSelect()Example 2FD_ZERO(&reads);FD_SET(serv_sock, &reads);fd_max = serv_sock;while(1){int fd, str_len;int clnt_sock, clnt_len;struct sockaddr_in clnt_addr;temps = reads;timeout.tv_sec = 5;timeout.tv_usec = 0; if (select(fd_max+1, &temps, 0, 0, &timeout) == -1)error_handling("select() error");Jong-won Lee 21ljw@handong.eduSelect()Example 2for (fd= 0; fd< fd_max+1; fd++){if (FD_ISSET(fd, &temps)){if (fd== serv_sock) { /* connect request from a client*/clnt_len = sizeof(clnt_addr);clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_len);FD_SET(clnt_sock, &reads);if (fd_max < clnt_sock)fd_max=clnt_sock;printf(“connected client: %d \n", clnt_sock);} else {str_len = read(fd, message, BUFSIZE);if(str_len == 0) { /* connection close */FD_CLR(fd, &reads);close(fd);printf(“closed client: %d \n", fd);} else {write (fd, message, str_len); }}} //if(FD_ISSET(fd, &temps))} //for(fd=0; fd<fd_max+1; fd++)} //while(1)}

profile
손끝에서 땅끝으로, 골방에서 열방으로

0개의 댓글