==================================Outline====================================
select함수를 사용한 채팅 프로그램
----------------------------------------------------------------------------
select함수를 사용하여 멀티프로세스가 아닌 파일 디스크럽터 감시로 다중화 입출력을 처리한다. select함수의 단점은 채널의 수가 2의 10승개(1024)로 제약된다는 점이다.
select함수로 감시할 파일을 지정하기 위해 FD_ZERO, FD_SET을 사용한다. 이 함수들을 사용하기 위해서 우선 fd_set 구조체를 선언해주어야 한다. FD_ZERO와 FD_SET의 인자로 생성한 fd_set구조체의 주소를 던져주어야 하기 때문이다.

fork함수를 활용하여 멀티 프로세스로 코딩하였던 채팅 프로그램을 select함수를 사용하여 만들어보자.
/*** client.c ***/
#include "smartsock.h"
int main(void) { int iFd; struct sockaddr_in stAddr; int iLen; int iRtn; char cBuf[BUF_SIZE]; fd_set fdRead;
/*** socket ***/ iFd = socket(AF_INET, SOCK_STREAM, 0); if(-1 == iFd) { perror("socket:"); return 100; }
/*** structure setting ***/ stAddr.sin_family = AF_INET; stAddr.sin_addr.s_addr = inet_addr(IP); stAddr.sin_port = htons(PORT);
iLen = sizeof(struct sockaddr_in);
/*** connect ***/ iRtn = connect(iFd, (struct sockaddr *)&stAddr, iLen); if(-1 == iRtn) { perror("connect:"); close(iFd); return 200; }
while(1) { FD_ZERO(&fdRead); FD_SET(0, &fdRead); FD_SET(iFd, &fdRead); select(iFd+1,&fdRead, 0, 0, 0);
if(0 == (FD_ISSET(0, &fdRead) ) ) { memset(cBuf, 0, MSG_SIZE); iRtn = read(0, cBuf, MSG_SIZE); cBuf[iRtn - 1] = 0; write(iFd, cBuf, MSG_SIZE); printf("[Send MSG]: [%s]\n", cBuf); } if(0 == (FD_ISSET(iFd, &fdRead) )) { memset(cBuf, 0, MSG_SIZE); iRtn = read(iFd, cBuf, MSG_SIZE); printf("[Server]: [%s]\n", cBuf); } if(0 == strncmp(cBuf, MSG_END, strlen(MSG_END))) { break; } }
/*** read & write ***/ //memset(cBuf, 0, BUF_SIZE); //iRtn = read(0, cBuf, BUF_SIZE);
close(iFd); return 0; }
|
/*** server.c ***/
#include "smartsock.h" #include <unistd.h>
int main(void) { int iSock; //소켓 함수의 반환 값을 받는 변수 int icSock[MAX_USER]; //accept의 반환 값을 받는 변수 int iRet; struct sockaddr_in stAddr; socklen_t uiSockLen=sizeof(struct sockaddr); char cBuff[BUF_SIZE]; const char * cP; fd_set fdRead; unsigned int uiUser; unsigned int uiCnt;
iSock = socket(AF_INET, SOCK_STREAM, 0); //AF_INET = 2, if(0 > iSock) { perror("socket : "); return -1; } // stAddr구조체에 socket연결을 위한 필수 정보 입력 setting bzero(&stAddr, sizeof(stAddr)); //구조체 비우기(0으로 채우기) stAddr.sin_family = AF_INET; //#define AF_INET 2 /* IP protocol family. */ stAddr.sin_addr.s_addr = inet_addr(IP); //IP와 PORT값은 헤더파일에 정의되어 있다. stAddr.sin_port = htons((PORT));
iRet = bind(iSock, (struct sockaddr *)&stAddr,sizeof(stAddr)); if(iRet < 0) { perror("bind : "); close(iSock);
return -2; } iRet = listen(iSock, 5); if(iRet != 0) { perror("listen : "); close(iSock);
return -3; } uiUser = 0; while(1) { FD_ZERO(0,&fdRead); FD_SET(0, &fdRead); FD_SET(iSock, &fdRead); for(uiCnt = 0; uiCnt <= uiUsert; ++uiCnt) { FD_SET(icSock[uiCnt], &fdRead) } select((iSock+1+uiCnt), &fdRead, 0, 0, 0);
if( 0 != FD_ISSET(iSock)) { icSock[uiUser] = accept(iSock, (struct sockaddr *)&stAddr, &uiSockLen); //접속자의 정보가 stAddr에 입력된다. if(icSock[uiUser] < 0) { perror("Accept : "); continue; } ++uiUser;
}
if(pid == 0) { break; } } close(iSock);
printf("Incoming Client \n"); //cP = inet_ntoa(stAddr.sin_addr); printf("Client IP :%s\n", inet_ntoa(stAddr.sin_addr)); printf("Client Port : %d\n", ntohs(stAddr.sin_port));
write(icSock, "Welcome :)", sizeof("Welcome :)"));
while(1) { read(icSock, cBuff, MSG_SIZE); printf("[client]: [%s]\n", cBuff);
write(icSock, cBuff, MSG_SIZE); if(0 == strncmp(MSG_END, cBuff, strlen(MSG_END) ) ) break;
} close(icSock); return 0; }
|
/*** smartsock.h ***/
#ifndef __SMARTSOCK_H__ #include <sys/select.h> #define __SMARTSOCK_H__
#include <stdio.h> #include <string.h> #include <strings.h> // socket & bind & listen & accept & connect #include <sys/types.h> #include <sys/socket.h>
// sockaddr_in #include <netinet/in.h>
// read & write #include <unistd.h>
// htonl #include <arpa/inet.h>
// errno, perror #include <errno.h>
// open #include <fcntl.h> #include <sys/stat.h>
//select #include <sys/time.h> #include <sys/types.h> #include <unistd.h> #include <sys/select.h>
#define PORT 7777 #define IP "192.168.0.173"
#define MSG_SIZE 255 #define BUF_SIZE (MSG_SIZE+1) #define MSG_END "quit"
#define MAX_USER 30
#endif /* __SMARTSOCK_H__ */
|
client.c
server.c
smartsock.h