본문 바로가기
코스웨어/11년 내장형하드웨어

[내장형]김수만_10월 24일

by 알 수 없는 사용자 2011. 10. 25.
728x90
반응형



● 전체소스코드
   1: // TCP/IP 소켓프로그래밍 p.32의 버전업
   2: // TCPEchoServer4_v2.c
   3: // select:()사용
   4: // 2011년 10월 24일
   5: #include <stdio.h>
   6: #include <stdlib.h>
   7: #include <string.h>
   8: #include <unistd.h>
   9: #include <sys/time.h>
  10: #include <sys/types.h>
  11: #include <sys/socket.h>
  12: #include <netinet/in.h>
  13: #include <arpa/inet.h>
  14:  
  15:  
  16: #define    MAXCLIENT    2        // 손님 두 명까지 서비스 가능
  17:  
  18: int main()
  19: {
  20:     int iRet;                    // 리턴값 임시 저장
  21:     int iCNum = 0;                // 현재 접속한 클라이언트수
  22:     int iCnt;                    // 반복 제어변수
  23:     int iDs;                    // 랑데뷰 소켓 디스크립터
  24:     int iMaxDs;                    // 최대 파일 디스크립터수
  25:     int iAccept;                // 커뮤니케이션 소켓 디스크립터
  26:     int iaClient[MAXCLIENT];    // 커뮤니케이션 소켓 디스크립터 배열
  27:     int iAddrSize;                // 구조체 크기
  28:     struct sockaddr_in stAddr;    // 랑데뷰 소켓 IP주소
  29:     struct sockaddr_in stAccept;// 커뮤니케이션 소켓 IP주소
  30:     fd_set fsStatus;            // 디스크립터 벡터
  31:     unsigned char ucBuf[256];    // 문자열 저장 버퍼
  32:  
  33:     // 1. socket() - 소켓 생성 (열기)
  34:     iDs = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);    // IP, TCP, TCP
  35:     if(-1 == iDs)
  36:     {    // 소켓 생성 실패시 에러메시지 출력 후 종료
  37:         perror("socket() failed");
  38:         return -1;    // 1단계 에러
  39:     }
  40:  
  41:     // 2. 구조체 초기화
  42:     bzero(&stAddr, sizeof(struct sockaddr_in));    // 구조체를 0으로 채움.
  43:     stAddr.sin_family = PF_INET;    // IPv4 주소 패밀리
  44:  
  45:     // ----- 첫 인자 참조해 IP주소 dotted decimal 주소 -> 32bit주소
  46:     iRet = inet_pton(PF_INET, "127.0.0.1", &stAddr.sin_addr.s_addr);
  47:     if(0 >= iRet)    // 0이거나 음수이면 에러 man page참조
  48:     {
  49:         perror("inet_pton() failed");
  50:         close(iDs);
  51:         return -2;    // 2단계 에러
  52:     }
  53:     
  54:     printf("IP : %s\n", inet_ntoa(stAddr.sin_addr));
  55:     stAddr.sin_port = htons(3000);    // 서버의 포트번호, 리틀 -> 빅 엔디안
  56:     
  57:     // 3. bind() - 지역 주소에 바인드
  58:     iRet = bind(iDs, (struct sockaddr *)&stAddr, sizeof(struct sockaddr_in));    
  59:     if(-1 == iRet)
  60:     {
  61:         perror("bind() failed");
  62:         close(iDs);
  63:         return -3;    // 3단계 에러
  64:     }
  65:  
  66:     // 4. listen() - 소켓이 들어오는 요청을 처리할 수 있도록 설정
  67:     iRet = listen(iDs, 5);    // 5개 초과시 접속거부...확인은 불가
  68:     if(-1 == iRet)
  69:     {
  70:         perror("listen() failed");
  71:         close(iDs);
  72:         return -4;    // 4단계 에러
  73:     }
  74:  
  75:     // 5. select() -  멀티플렉싱
  76:     iMaxDs = iDs + 1;        // 검사할 파일디스크립터 개수
  77:  
  78:     while(1)
  79:     {
  80:         printf("현재 접속자수: %d 명\n", iCNum);
  81:         FD_ZERO(&fsStatus);        // 구조체 0으로 초기화
  82:         FD_SET(iDs, &fsStatus);    // 그룹1...3번 - 랑데뷰소켓 감시
  83:         FD_SET(0, &fsStatus);    // 그룹2...0번 - 키보드도 감시
  84:         // 그룹3...접속한 커뮤니케이션 소켓디스크립터 세트
  85:         for(iCnt = 0 ; iCNum > iCnt ; ++iCnt)
  86:         {
  87:             FD_SET(iaClient[iCnt], &fsStatus);
  88:         }
  89:         
  90:         printf("TEST...select() 시작!!\n");
  91:         // select()는 인터럽트와 폴링방식을 혼합한 것.
  92:         iRet = select(iMaxDs, &fsStatus, 0, 0, 0);    // 입력x시 블록
  93:         if(-1 == iRet)
  94:         {
  95:             perror("select() failed");
  96:             close(iDs);
  97:             return -5;    // 5단계 에러
  98:         }
  99:     
 100:         printf("TEST...select() 끝!!\n");
 101:         
 102:         if(1 == FD_ISSET(0, &fsStatus))        // 키보드입력 있나?
 103:         {        // 키보드는 항상 0번
 104:             iRet = read(0, ucBuf, sizeof(ucBuf));
 105:             ucBuf[iRet] = 0;    // 문자열 끝을 나타냄.
 106:             
 107:             for(iCnt = 0 ; iCNum > iCnt ; ++iCnt)
 108:             {    // 접속자 모두에게 메시지 전송
 109:                 write(iaClient[iCnt], ucBuf, iRet);
 110:             }
 111:             continue;
 112:         }
 113:     
 114:         if(1 == FD_ISSET(iDs, &fsStatus))    // 랑데뷰 소켓으로 새로운 접속시
 115:         {
 116:             // 6. accept() - 클라이언트와 연결
 117:             iAddrSize = sizeof(struct sockaddr_in);
 118:             iAccept = accept(iDs, (struct sockaddr *)&stAccept, &iAddrSize);
 119:             if(-1 == iAccept)
 120:             {
 121:                 perror("accept() failed");
 122:                 close(iDs);
 123:                 // 열려진 커뮤니케이션 디스크립터 닫기
 124:                 for(iCnt = 0 ; iCNum > iCnt ; ++iCnt)
 125:                 {
 126:                     close(iaClient[iCnt]);
 127:                 }
 128:         
 129:                 return -6;    // 6단계 에러
 130:             }
 131:  
 132:             if(MAXCLIENT <= iCNum)    // 최대 접속자수 제한
 133:             {
 134:                 write(iAccept, "Server is busy. 저리가~ \n", sizeof("Server is busy. 저리가~ \n"));
 135:                 close(iAccept);        // 클라이언트의 접속을 끊음.
 136:                 continue;
 137:             }
 138:         
 139:             if(iAccept == iMaxDs)    // 새로 접속한 소켓번호가 최고 번호보다 1 큰 경우
 140:             {
 141:                 iMaxDs = iAccept + 1;    // 최대 접속수 갱신
 142:             }
 143:     
 144:             iaClient[iCNum] = iAccept;
 145:             ++iCNum;
 146:             printf("Client IP : %s\n", inet_ntoa(stAccept.sin_addr));
 147:             continue;    // 랑데뷰소켓인 경우 아래 명령 처리x 
 148:         }
 149:         
 150:         // 랑데뷰소켓으로 접속이 아닌 경우            
 151:         // 커뮤니케이션소켓으로 접속...데이터전송 (채팅)
 152:         printf("커뮤니케이션소켓 - 클라이언트 데이터전송\n");
 153:  
 154:         for(iCnt = 0 ; iCNum > iCnt ; ++iCnt)
 155:         {    // 접속자 모두 검사해 데이터를 보내온 소켓처리 (폴링방식)
 156:             if(1 == FD_ISSET(iaClient[iCnt], &fsStatus))
 157:             {    // 해당소켓번호에 데이터가 들어옴.
 158:                 // 6. read() - 클라이언트로부터 수신
 159:                 iRet = read(iaClient[iCnt], ucBuf, sizeof(ucBuf));
 160:                 ucBuf[iRet] = 0;    // 문자열 끝을 나타냄.
 161:                 printf("%d: %s\n", iaClient[iCnt], ucBuf);
 162:  
 163:                 for(iCnt = 0 ; iCNum > iCnt ; ++iCnt)
 164:                 {    // 접속자 모두에게 메시지 전송
 165:                     write(iaClient[iCnt], ucBuf, iRet);
 166:                 }
 167:             }
 168:         }                
 169:     }        
 170:  
 171:     write(iAccept, "Pong", sizeof("Pong"));
 172:     
 173:     close(iAccept);    // 커뮤니케이션 소켓 소멸 (닫기)
 174:     close(iDs);        // 랑데뷰 소켓 소멸 (닫기)
 175:     
 176:     return 0;
 177: }


● 실행결과

image image

             [스샷] 첫 번째 클라이언트





image

           [스샷] 두 전째 클라이언트





image

image

                        [스샷] 서버                                                                     [스샷] 세 번째 클라이언트



첫 번째와 두 번째 클라이언트가 접속하여 대화하다가 서버가 끼어들어 강제로 접속을 종요한 결과이다.
세 번째 클라이언트는 서버에서 차단시킨다.

728x90