본문 바로가기
코스웨어/15년 스마트컨트롤러

20150824-14번-박제혁-일일업무일지 - FD_ISSET, select 함수를 이용한 채팅프로그램

by 알 수 없는 사용자 2015. 8. 25.
728x90
반응형

FD_ISSET(

int fd, 

fd_set *fdset

);


*fdset 중 소켓 fd에 해당하는 비트가 세트되어 있으면 양수값인 fd를 리턴한다.


출처 : http://jsnim.blogspot.kr/2010/02/select-fdzero-fdset-fdclr-fdisset.html





int select (

int nfds, 

fd_set *readfds, 

fd_set *writefds, 

fd_set *exceptfds, 

struct timeval *timeout

);


nfds : 관리할 파일 개수를 적는다. 저수준 파일 지시자 중 가장 큰 숫자의 +1 값을 적는다.


fd_set : 관리하는 파일의 지정번호가 등록되어 있는 비트 배열 구조체

readfds : 읽을 데이터가 있는지 검사하기 위한 파일 목록

writefds : 쓰여진 데이터가 있는지 검사하기 위한 파일 목록

exceptfds : 파일에 예외 사항들이 있는지 검사하기 위한 파일 목록


timeout : select함수는 fd_set에 등록된 파일들에 데이터 변경이 있는지를 timeout동안 기다린다. 

만약 timeout시간동안 변경이 없다면 0을 반환 한다. timeout을 NULL로 하면, 데이터가 있을 때까지 무한정 기다리고, 멤버 값이 모두 0이면 즉시 반환한다. 


출처 : http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/Network_Programing/Documents/selectIntro






 server.c 

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include "selectchat.h"
 
int main(void)
{
    int isock;                //랑데뷰 소켓
    int icsock[MAX_USER];    //커뮤니케이션 소켓
    int iret;
    struct sockaddr_in staddr;
    socklen_t uiSockLen = sizeof(struct sockaddr);
    unsigned char cBuf[BUF_SIZE];
    fd_set fdRead;
    unsigned int uiUser;
    unsigned int uiCnt;
 
    isock = socket(AF_INET, SOCK_STREAM, 0);
    if(isock < 0)
    {
        perror("socket() error : ");
        return 10;
    }
 
    bzero(&staddr, sizeof(staddr));
    staddr.sin_family = AF_INET;
    staddr.sin_addr.s_addr = inet_addr(IP);
    staddr.sin_port = htons(PORT);
 
    iret = bind(isock, (struct sockaddr *)&staddr, sizeof(staddr));
    if(iret < 0)
    {
        perror("bind() error : ");
        close(isock);
        return 20;
    }
 
    iret = listen(isock, 5);
    if(iret < 0)
    {
        perror("listen() error : ");
        close(isock);
        return 30;
    }
 
    uiUser = 0;
    while(1)
    {
        FD_ZERO(&fdRead);
        FD_SET(0, &fdRead);    //키보드 감지
        FD_SET(isock, &fdRead); //접속이 들어옴을 감지함
        for(uiCnt = 0; uiCnt < uiUser ; ++uiCnt)
        {
            FD_SET(icsock[uiCnt], &fdRead);    //접속자들의 입력을 감지함
        }
        select(isock + 1, &fdRead, 000);
 
        if(FD_ISSET(isock, &fdRead) != 0)//접속이 들어옴을 감지했다면
        {
            icsock[uiUser] = accept(isock, (struct sockaddr *)&staddr, &uiSockLen);
            if(icsock[uiUser] < 0)
            {
                perror("accept() error : ");
                continue;
            }
            ++uiUser;
        }
 
    }
 
 
    close(isock);
    printf("incomming client \n");
 
    write(icsock, "welcome"sizeof("welcome"));    
 
    printf("client ip : %s \n",  inet_ntoa(staddr.sin_addr));
    printf("client port : %d \n", ntohs(staddr.sin_port)); 
 
    while(1)
    {
        read(icsock, cBuf, BUF_SIZE);
        printf("[client]::[%s] \n", cBuf);
 
        write(icsock, cBuf, MSG_SIZE);
        if0 == strncmp( MSG_END , cBuf, strlen(MSG_END)))
        {
            break;
        }
    }
 
 
    close(icsock);
    return 0;
}
cs




 client.c 

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "selectchat.h"
 
int main()
{
    int ifd;    // 소켓 번호
    struct sockaddr_in stAddr;
    int ilen;
    int iret;
    fd_set fdRead;    // select 함수 쓰기 위한 fd_set 변수
    char cbuf[MSG_SIZE];    
 
    ifd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == ifd)
    {
        perror("socket() call error");
        return 100;
    }
 
    stAddr.sin_family = AF_INET;
    stAddr.sin_addr.s_addr = inet_addr(IP);
    stAddr.sin_port = htons(PORT);
    
    ilen = sizeof(struct sockaddr_in);
 
    iret = connect(ifd, (struct sockaddr *)&stAddr, ilen);
    if(-1 == iret)
    {
        perror("connect() call error");
        close(ifd);
        return 200;
    }
 
    while(1)
    {
        FD_ZERO(&fdRead);
        FD_SET(0,&fdRead);    // 키보드 감시
        FD_SET(ifd, &fdRead); // 서버와 통신하는 소켓을 감시
        select(ifd + 1, &fdRead, 000);// select가 2개를 동시에 감시
        
        if( FD_ISSET(0, &fdRead) != 0  )
        {
            iret = read(0, cbuf, MSG_SIZE);
            cbuf[iret - 1= 0;
            write(ifd, cbuf, MSG_SIZE);
            printf("Send MSG : [%s]\n", cbuf);
        }
        if( FD_ISSET(ifd, &fdRead) != 0  )
        {
            read(ifd, cbuf, MSG_SIZE);
            printf("Server MSG : [%s]\n", cbuf);
        }
        if0 == strncmp(cbuf, MSG_END, strlen(MSG_END)))
        {
            break;
        }
    }
 
    close(ifd);
 
    return 0;
}
 
cs



 selectchat.h 

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
29
30
31
32
33
34
35
#ifndef    __SELECTCHAT_H__ 
#define    __SELECTCHAT_H__
 
 
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
 
 
#define PORT    7777
 
 
#define IP      "192.168.0.115"
 
#define MSG_SIZE    255             // message size
#define BUF_SIZE    (MSG_SIZE+1)
 
#define MSG_END     "quit"
 
#define MAX_USER    30
 
 
#endif    // __SELECTCHAT_H__
cs






  참고  


접속자가 늘어나면 icsock 배열에 차곡차곡 접속자의 커뮤니케이션 소켓번호가 쌓일 것이다.

접속자가 도중에 나갔을 경우, 제일 뒷번호를 도중에 나간 자리로 이동시킨다.




위 그림의 경우 접속자가 3명이므로 uiUser 는 3이다.

위 그림을 코드로 표현하면 아래와 같다.


1
2
3
close(icsock[0]);                    //3번이 나감.
icsock[0= icsock[uiUser - 1];      //5번이 3번의 자리를 채움.
--uiUser;                            //접속자 수 1 감소.
cs



728x90