반응형


- 본 내용은 Linux (Ubuntu 14.04 lts)를 기반으로 제작되었습니다. -




I/O Multiplexing Select 개념 및 예제 코드 :: http://www.crocus.co.kr/542


I/O Multiplexing Select를 이용하여 간단한 에코 서버를 제작하는 방법이다.


클라이언트에서 메시지를 보내면 서버가 그 메시지를 확인하고, 

select에 의해 감지되면 메시지를 복사하여 다시 클라이언트로 보내주는 방식이고, 


5초동안 아무런 일이 없으면 Time Out이라고 서버에 출력해주는 방식을 취한다.



소스 코드 : 


<header.h>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//header.h
 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/select.h>
 
#define PORT 20162
#define BUFFER_SIZE 100
#define LISTEN_QUEUE_SIZE 5
 
 
//                                                       This source code Copyright belongs to Crocus
//                                                        If you want to see more? click here >>
Crocus

<select.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include "header.h"
 
 
int main(int argc, char* argv[])
{
    int listenFD, connectFD;
    struct sockaddr_in listenSocket, connectSocket;
    struct timeval timeout;
 
    // reads, cpyReads 생성
    // 이때 cpyReads는 while에서 reads의 복제를 위해 이용
    fd_set reads, cpyReads;
 
    socklen_t addrSz; // address size를 구할 변수
 
    int fdMax, strLen, fdNum, i;
    char buf[BUFFER_SIZE];
 
    //if (argc != 2)
    //{
    //    printf("Usage : %s <port>\n", argv[0]);
    //    exit(1);
    //}
 
    listenFD = socket(PF_INET, SOCK_STREAM, 0);
    memset(&listenSocket, 0sizeof(listenSocket));
 
    listenSocket.sin_family = AF_INET;
    listenSocket.sin_addr.s_addr = htonl(INADDR_ANY);
    listenSocket.sin_port = htons(PORT);
 
 
    if (bind(listenFD, (struct sockaddr *&listenSocket, sizeof(listenSocket)) == -1) {
        printf("Can not bind.\n");
        return -1;
    }
 
    if (listen(listenFD, LISTEN_QUEUE_SIZE) == -1) {
        printf("Listen fail.\n");
        return -1;
    }
 
 
    FD_ZERO(&reads); // 소켓 셋 초기화
    FD_SET(listenFD, &reads); //  listenFD 소켓 셋 1로 설정
    fdMax = listenFD; // 소켓 마지막 번호를 받아온다
 
    while (1)
    {
        cpyReads = reads; // 복제
 
        timeout.tv_sec = 5;  // 5초
        timeout.tv_usec = 0;
 
        if ((fdNum = select(fdMax + 1&cpyReads, 00&timeout)) == -1// 타임아웃은 5초로 지정한다.
            break// select 실패시
 
        if (fdNum == 0// select의 return값이 0이면 즉, 타임아웃이면 서버 창에 timeout 출력 후 진행
        {
            printf("Time Out!\n");
            continue;
        }
 
        for (i = 0; i < fdMax + 1; i++)
        {
            if (FD_ISSET(i, &cpyReads)) // fd가 켜져있다면
            {
                if (i == listenFD) // 그때 i가 FD와 같다면
                {
                    addrSz = sizeof(connectSocket);
 
                    connectFD = accept(listenFD, (struct sockaddr*)&connectSocket, &addrSz);
 
                    FD_SET(connectFD, &reads); // reads 소켓 셋에 connectFD를 부분을 1로 바꾼다
 
                    if (fdMax < connectFD)
                        fdMax = connectFD;
 
                    printf("connected client : %d\n", connectFD);
                }
 
                else
                {
                    strLen = read(i, buf, BUFFER_SIZE);
 
                    // close request
                    if (strLen == 0)
                    {
                        FD_CLR(i, &reads); // 0으로 지운다
                        close(i);
                        printf("close client : %d\n", i);
                    }
 
                    else
                    {
                        // echo
                        write(i, buf, strLen);
                    }
                }
            }
        }
    }
 
    close(listenFD);
 
    return 0;
}
 
//                                                       This source code Copyright belongs to Crocus
//                                                        If you want to see more? click here >>
Crocus


<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
//client.cpp
 
# include "header.h"
 
int main(int argc, char** argv)
{
    if (argc != 2
    {
        printf("Usage: %s IPv4-address\n", argv[0]);
        return -1;
    }
 
    struct sockaddr_in connectSocket;
 
    memset(&connectSocket, 0sizeof(connectSocket));
 
    connectSocket.sin_family = AF_INET;
    inet_aton(argv[1], (struct in_addr*&connectSocket.sin_addr.s_addr);
    connectSocket.sin_port = htons(PORT);
 
    int connectFD = socket(AF_INET, SOCK_STREAM, 0);
 
    if (connect(connectFD, (struct sockaddr*&connectSocket, sizeof(connectSocket)) == -1
    {
        printf("Can not connect.\n");
        return -1;
    }
 
    else 
    {
        int readBytes, writtenBytes;
        char sendBuffer[BUFFER_SIZE];
        char receiveBuffer[BUFFER_SIZE];
 
    while(1)
    {
            //서버에 문자열을 보낸 뒤 서버가 보낸 echo를 받아 출력.
            printf("input :: ");
 
            fgets(sendBuffer,BUFFER_SIZE,stdin);
 
            write(connectFD, sendBuffer, strlen(sendBuffer));
            
 
            readBytes = read(connectFD, receiveBuffer, BUFFER_SIZE);
            printf("%d bytes read\n", readBytes);
            receiveBuffer[readBytes] = '\0';
        
        fputs(receiveBuffer, stdout);
            fflush(stdout);
     }
        
        
        
    }
 
    close(connectFD);
    return 0;
}    
 
//                                                       This source code Copyright belongs to Crocus
//                                                        If you want to see more? click here >>
Crocus















반응형