poll을 이용한 채팅서버

OS/리눅스 & 유닉스 2012. 5. 24. 18:38

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>  //poll
#include <errno.h>     //errno
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>  //socket
#include <netinet/in.h>    //sockaddr
#include <netdb.h>        //hostent

#define PORT 8001
#define BUFFSIZE 1024  // 송수신을 위한 버퍼크기
#define MAXPOLL 128   // pollfd의 최대 크기


// tcp server 
int main() {
   struct pollfd polls[MAXPOLL];     // pollfd 배열
   int count=0;
   char buff[BUFFSIZE];
   int yes=1;
   int i, poll_result;
   int server_socket, client_socket;
   struct sockaddr_in server_addr, client_addr;
   int server_addrlen=sizeof(server_addr);  //서버소켓주소의 길이
   int client_addrlen=sizeof(client_addr);   //클라이언트 소켓주소의 길이


   // 인터넷 도메인 TCP 서버 소켓 생성
   if ( (server_socket=socket(AF_INET,SOCK_STREAM,0)) < 0 ) {
      perror("socket");
      exit(1);
   }
   
  // 서버 포트번호를 재사용 할 수 있도록 소켓 옵션 설정
   if ( setsockopt(server_socket,  //socket
                 SOL_SOCKET,  // level
                 SO_REUSEADDR,  // option
                 &yes,  //option value
                 sizeof(int)) < 0 ) {  // option length
       perror("setsockopt");
       exit(9);              
   }
   
   //서버의 소켓주소를 생성
   bzero((void *)&server_addr,sizeof(server_addr));
   server_addr.sin_family=AF_INET;
   server_addr.sin_addr.s_addr=INADDR_ANY;
   server_addr.sin_port=htons(PORT);
   
   //소켓과 서버주소 연결 bind()
   
   if ( bind(server_socket,(struct sockaddr *)&server_addr,
           sizeof(server_addr)) < 0) {
        perror("bind");
        exit(2);
   }
   
   //커널에 포트 알림 listen()
   if ( listen(server_socket,5) < 0 ) {
       perror("listen");
       exit(3);
   }
   
   printf("서버가 시작됨: %d\n",PORT);

  // 서버 소켓에 대한 이벤트 등록
   polls[0].fd=server_socket;
   polls[0].events=POLLIN;
   count++;    // 등록된 소켓의 수 
   
   // 서버소켓을 제외한 나머지 pollfd의 디스크립트 값을 -1 로 설정하여 할당되지 않음을 표시
   for(i=1;i<MAXPOLL;i++) polls[i].fd=-1;
   
   // 클라이언트 연결을 처리하기 위해 대기중
    
   while (1) {  
   poll_result=poll(polls,count,1000);
   
  
   if (poll_result == 0 ) continue;  // 타임아웃에 걸린 경우 다시 while loop를 테스트하도록 한다.
   if (polls[0].revents & POLLIN) {  //서버소켓에 이벤트가 발생한 경우
      bzero((void *)&client_addr,sizeof(client_addr));
      if ( (client_socket= accept(server_socket,
             (struct sockaddr *)&client_addr,&client_addrlen)) < 0) {
          perror("accept");
          exit(4);
      }
      printf("클라이언트가 접속됨:\n");
      printf("IP: %s  PORT: %d\n",inet_ntoa(client_addr.sin_addr), 
                                ntohs(client_addr.sin_port));
      polls[count].fd=client_socket;      // 새로 연결된 클라이언트 소켓을 pollfd에 등록하여 이벤트를 감시하도록 한다.
      polls[count].events = POLLIN;  
      count++;   
      continue;
   } else {  //클라이언트 소켓에서 이벤트가 발생한 경우              
      for(i=1;i<count;i++) {
         if ( polls[i].revents & POLLIN ) {
           //클라이언트가 전송한 메시지를 buff에 수신함
           bzero(buff,sizeof(buff));
           if ( recv(polls[i].fd, buff,sizeof(buff),0) < 0 ) {
               perror("recv");
               break;
           }else 
             printf("[%d]수신 %s",polls[i].fd, buff);
           //클라이언트가 종료를 요청하면 소켓을 닫아주고
           //pollfd에서 삭제해준다.  
           if ( bcmp(buff,"exit",4) == 0 ) {
              close(polls[i].fd);
              polls[i].fd=-1;
              // polls이사를 시키세요
              break;
           }
           //클라이언트에게 수신된 메시지 echo
           if ( send(polls[i].fd,buff,strlen(buff),0) < 0) {
              perror("send");
              break;
           }else 
              printf("[%d]송신 %s",polls[i].fd, buff);
         }//if
      }//for
    }//else
   }//while
   close(polls[0].fd);
   exit(0);     
}


출처 - http://cafe.naver.com/sunschool/5521

'OS > 리눅스 & 유닉스' 카테고리의 다른 글

ibm aix polling  (0) 2012.05.31
공유 메모리 (shared memory)  (0) 2012.05.29
AIX 32bit/64bit 컴파일  (0) 2012.05.23
Compiler 옵션  (0) 2012.05.23
gcc 옵션 [출처] gcc 옵션 간단 정리|작성자 열이  (0) 2012.05.23
: