티스토리 뷰

program

[Linux] Select and Poll

littlecarbb 2015. 10. 14. 03:32

출처 : http://bluelimn.tistory.com/m/post/763


IPC : pipe, named pipe, semaphore, message queue, shared memory, futex, socket


Futex : fast userspace mutex(Spinlock 방식)

- 장점 : 빠름 (sleep 대신 while), 

            lock이 user space에 있기 때문에 접근성이 좋음(공유 메모리나 Thread 및           Process간 공유 가능)

- 단점 : 기본적으로 loop를 계속 돌고 있기 때문에 core수가 뒷받침되어야 한다. 

           (single core에서는 소용 없음.)


pthread mutex vs pthread spinlock

Pasted from <http://www.alexonlinux.com/pthread-mutex-vs-pthread-spinlock> 



Pselect()

int pselect(int nfds, fd_set *readfds, fd_set *writefds,

           fd_set *exceptfds, const struct timespec *timeout,

           const sigset_t *sigmask);

• pselect는 struct timespec 구조체 사용한다. timespec 구조체를 사용함으로써        나노초까지 세밀하게 조정할 수 있게 되었다.


struct timespec {

    long    tv_sec;         /* seconds */

    long    tv_nsec;        /* nanoseconds */

};

• pselect 는 Linux(:12) 커널 2.6.16에 추가되었다. 이전에는 glibc에서 애뮬레이트한 

          함수가 제공되었으나 버그를 가지고 있었다.

• sigmask를 사용해서 시그널을 블럭시킬 수 있다. select의 경우 수행되는 도중에         시그널에 의한 인터럽트가 발생하게 되면, race condition 혹은 무한 블록킹         상태에 놓일 수 있었다. pselect를 사용하면 이러한 문제를 제거할 수 있다. 


Pasted from <http://www.joinc.co.kr/modules/moniwiki/wiki.php/man/2/select> 

Pselect가 select와 다른 점

- Nano sec단위로 사용하므로 이론적으로는 타이머 해상도가 정밀하나 실전에서는 

        micro sec단위도 안정적으로 제공하지 못한다.

- Timeout parameter를 변경하지 않는다. 사용할 때마다 timeout을 다시 설정할 

        필요가 없음

- Signal parameter가 추가됨(sigmask) : signal 을 차단함.




Select() : 동기식 다중 입출력 제공

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>


Int select (int n,

                  fd_set *readfds,

                   fd_set *writefds,

                   fd_set *execptfds,

                   struct timeval *timeout);


FD_CLR(int fd, fd_set *set);       /* delete FD */

FD_ISSET(int fd, fd_set *set);    /* select의 결과에 해당 fd가 있는지 */

FD_SET(int fd, fd_set *set);      /* add FD*/

FD_ZERO(fd_set *set);



#include <sys/time.h>

Struct timeval {

             long tv_sec;    /* sec */

             long tv_usec;  /* micro sec */

};


Poll() : select를 보완 (fd set을 하나로 통일)

#include <sys/poll.h>

Int poll (struct pollfd *fds, unsigned int nfds, int timeout);


#include <sys/poll.h>

Struct pollfd {

            int fd;

            short events;   /* 감시 대상 요청 */

            short revents; /* returned event */

}


Events:

POLLIN : Data other than high-priority data may be read without blocking.

POLLRDNORM : Normal data may be read without blocking.

POLLRDBAND : Priority data may be read without blocking.

POLLPRI : High-priority data may be read without blocking.

POLLOUT : Normal data may be written without blocking.

POLLWRNORM : Equivalent to POLLOUT.

POLLWRBAND : Priority data may be written.

POLLERR : An error has occurred on the device or stream. This flag is only valid in the revents bitmask; it shall be ignored in the events member.

POLLHUP : The device has been disconnected. This event and POLLOUT are mutually-exclusive; a stream can never be writable if a hangup has occurred. However, this event and POLLIN, POLLRDNORM, POLLRDBAND, or POLLPRI are not mutually-exclusive. This flag is only valid in the revents bitmask; it shall be ignored in the events member.

POLLNVAL : The specified fd value is invalid. This flag is only valid in the revents member; it shall ignored in the events member.


Ppoll() : pselect 처럼 만든 것, 나노초 단위, sigmask 제공, linux 전용

#define _GNU_SOURCE

#include <sys/poll.h>

Int ppoll (struct pollfd *fds,

                  nfds_t nfds,

                  const struct timespec *timeout,

                  const sigset_t *sigmask);



server.c


#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>


#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <sys/stat.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

 

#define TIMEOUT 10       /* timeout : seconds */

#define FD_MAX_CLIENT 3

#define BUF_SIZE 1024

#define EXIT_STR "exit"

/*

 * error - wrapper for perror

 */

void error(char *msg) {

  perror(msg);

  exit(1);

}


int main(int argc, char **argv)

{

    int server_sockfd;

    int client_sockfd; 

    int max_fd;                     /* for using select */

    struct sockaddr_in serveraddr;

    struct sockaddr_in clientaddr;

    int clientlen;

    int client[FD_MAX_CLIENT];

    char buf[BUF_SIZE];          /* message buffer */

    int n; /* message byte size */

    struct timeval tv;

    fd_set readfds, temp_fds;

    

    int notdone;

    int i, ret;


    /* socket: create the parent socket  */

    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (server_sockfd < 0) 

        error("ERROR opening socket");


    max_fd = server_sockfd;


    bzero((char*)&serveraddr, sizeof(serveraddr));

    serveraddr.sin_family = AF_INET;

    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);

    serveraddr.sin_port = htons(9000);

 

    if(bind(server_sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)

        error("ERROR on binding");

 

    if(listen(server_sockfd, 5) < 0) /* allow 5 requests(backlog) to queue up */ 

        error("ERROR on listen");

    

    for (i = 0; i < FD_MAX_CLIENT; i++) {

        client[i] = -1;

    }

    

    /* initialize some things for the main loop */

    clientlen = sizeof(clientaddr);

    notdone = 1;


    printf("TCP Server Waiting ...\n");

    fflush(stdout);

    FD_ZERO(&readfds);          /* initialize the fd set */

    FD_SET(server_sockfd, &readfds); /* add socket fd */


    while(notdone)

    {

        temp_fds = readfds;

        tv.tv_sec = TIMEOUT;

        tv.tv_usec = 0;        

        ret = select(max_fd+1, &temp_fds, 0, 0, &tv);

        if (ret < 0)

          error("ERROR in select");

        else if(ret == 0)

        {

            printf("waiting...\n");

            continue;

        }


        if (FD_ISSET(server_sockfd, &temp_fds)) {

            /* accept: wait for a connection request */

            client_sockfd = accept(server_sockfd, (struct sockaddr *)&clientaddr, &clientlen);

            if(client_sockfd < 0)

                error("ERROR on accept");

            

            printf("connection from (%s , %d)\n", inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));


            for (i = 0; i < FD_MAX_CLIENT; i++)

            {

                if (client[i] < 0) {

                    client[i] = client_sockfd;

                    printf("\nclient_idx=%d, client_sockfd=%d\n", i, client_sockfd);

                    break;

                }

            }

            if(i >= FD_MAX_CLIENT)

            {

                printf("too many clients. so, closing client fd[%d]\n", client_sockfd);

                close(client_sockfd);

                continue;

            }

            FD_SET(client_sockfd, &readfds); /* add socket fd */

            max_fd = (client_sockfd > max_fd)?(client_sockfd):(max_fd);

        }


        for (i = 0; i <= FD_MAX_CLIENT; i++)

        {

            if (client[i] < 0)

                continue;

            

            client_sockfd = client[i];

            if (FD_ISSET(client_sockfd, &temp_fds))

            {

                bzero(buf, BUF_SIZE);

                

                /* n = recv(client_sockfd, buf, BUF_SIZE, 0); */

                n = read(client_sockfd, buf, BUF_SIZE);

                if (n <= 0) {

                    printf("Close client_sockfd : %d", client_sockfd);

                    close(client_sockfd);

                    FD_CLR(client_sockfd, &readfds);

                    client[i] = -1;

                }

                printf("[%d]RECV %s\n", client_sockfd, buf);

                if(strncmp(buf,EXIT_STR,strlen(EXIT_STR)) == 0)

                {

                    notdone = 0;

                    break;

                }

                /* send(client_sockfd,buf,strlen(buf), 0); */

                write(client_sockfd, buf, strlen(buf));

                break;

            }

        }

    }

    

    /* clean up */

    printf("\nTerminating server.\n");

    close(server_sockfd);

    exit(0);

}

 






공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함