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, 0, 0, 0);
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);
if( 0 == 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, 0, 0, 0);// 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);
}
if( 0 == strncmp(cbuf, MSG_END, strlen(MSG_END)))
{
break;
}
}
close(ifd);
return 0;
}
|
cs |
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 |
'코스웨어 > 15년 스마트컨트롤러' 카테고리의 다른 글
20150826 -22번-우대희-일일업무일지- 채팅프로그램2 (6) | 2015.08.27 |
---|---|
채팅 소스 입니다. (2) | 2015.08.26 |
20150825 -21번-여지윤-일일업무일지- 채팅프로그램 (6) | 2015.08.25 |
채팅소스파일입니다. (2) | 2015.08.25 |
20150821-20번-엄민웅-일일업무일지 - windbg 어셈블리 (8) | 2015.08.21 |
20150820-19번-안향진-일일업무일지 - 어셈블리 컴파일 (6) | 2015.08.21 |
20150819-18번-안해운-일일업무일지 - 초음파센서 SRF05, Timer/Counter (5) | 2015.08.20 |
20150818-16번-박태인-일일업무일지 - select 함수로 입출력 다중화 구현 (7) | 2015.08.18 |