티스토리 뷰
소켓 통신에 대해 공부를 하고 windows환경에서 개발을 하려고 보니 리눅스 소켓과 윈도우 소켓은 많이 다르다는 것을 알게 되었다.
그중 하나가 리눅스에서 멀티플렉싱(Multiplexing)을 위해 사용하던 select를 윈도우에서 그대로 사용할 수 없다는 것이다.
Multiplexing
하나의 프로세스가 하나의 전송로를 사용해서 여러 사용자들과 통신하여 효율성을 높이는 기술
리눅스에서는 멀티플렉싱을 구현하기 위해 select 함수를 사용하였다.
int select(int nfds, // 최대 소켓 번호+1
fd_set* read_fds, // 읽기를 감지할 fds
fd_set* write_fds, // 쓰기를 감지할 fds
fd_set* error_fds, // 예외를 감지할 fds
struct timeval* timeout); // 대기 시간 (0=INFINITE)
select 함수는 fd_set을 사용하는데 리눅스에서는 socket이 파일과 함께 관리되기 때문에 select로 input, output, error를 감지할 수 있었다.
리눅스 시스템에 예약되어있는 file discripter
0 : st_input
1 : st_output
2 : st_error
위처럼 0, 1, 2번 fd(file discripter)가 예약이 되어있어서 소켓을 생성하면 일반적인 경우 3번부터 생성이 되고 아래와 같은 코드로 input을 감지할 수 있었다.
FD_SET(0, &read_fds);
select(nfds, &read_fds, NULL, NULL, NULL);
if(FD_ISSET(0, &read_fds)){
// do
}
winsock은 리눅스 소켓과 다르게 소켓과 파일을 다르게 인식한다. 즉 위와 같은 코드는 10038에러가 발생한다.
10038(WSAENOTSOCKET)
소켓이 아닌 곳에 시도를 할 때 발생하는 error
따라서 winsock으로 멀티 플렉싱을 하려면 다른 방식을 사용해야 한다.
WSAEventSelect
윈도우의 이벤트 객체를 소켓마다 지정해서 이벤트가 발생하는 것을 기다린다.
이벤트 타입이 다를 뿐 리눅스의 select와 비슷한 원리를 가지고 있다.
동작 순서는 다음과 같다.
1. 소켓을 생성할 때 마다 WSACreateEvent() 로 이벤트 생성한다.
WSAEVECT WSACreateEvent();
2. WSAEventSelect() 로 소켓과 이벤트를 연결한다.
int WSAEvectSelect(SOCKET s, // 설정할 소켓
WSAEVENT hEvectObject, // 연결할 이벤트
long INetworkEvect);// 네트워크 이벤트
등록할 수 있는 이벤트
FD_READ : 데이터 수신이 준비되었을 때
FD_WRITE : 데이터 전송이 준비되었을 때
FD_ACCEPT : 접속 요청이 들어왔을 때
FD_CONNECT : 접속 요청이 완료되었을 때
FD_CLOSE : 접속이 종료되었을 때
3. WSAWaitForMultipleEvent() 로 이벤트를 기다린다.
DWORD WSAWaitForMultipleEvents(DWORD cEvents, // 대기할 이벤트 개수
const WSAEVENT* lphEvents, // 대기할 이벤트 배열
BOOL fWaitAll, // TRUE=모든 이벤트 배열이 signal되면 return FALSE=하나라도 signal되면 return
DWORD dwTimeout, // 대기시간 (WSA_INFINITE=이벤트가 발생할 때까지 대기)
BOOL fAlertable);// I/O completion routine과 관련된 부분 (false)
사용 예
while(1){
index = WSAWaitForMultipleEvents(numSocket, hEvents, FALSE, WSA_INFINITE, FALSE);
// ...
}
4. WSAEnumNetworkEvents() 로 발생한 이벤트를 알아내어 처리한다.
int WSAEnumNectworkEvents(SOCKET s, // 알고자 하는 소켓
WSAEVENT hEventObject, // 알고자 하는 이벤트
LPWSANETWORKEVENTS lpNetworkEvents);// 네트워크 이벤트 정보 구조체 포인터
사용 예
for(int i=0; i<numSockets; i++){
WSAEnumNetworkEvents(sockets[i], hEvents[i], &nwEvent);
if(nwEvent.lNetworkEvent & FD_READ)
recv(s, recvLine, MAX_LINE, 0);
}
사용하지 않는 이벤트는 WSACloseEvent() 로 삭제한다.
WSAEvectSelect() 를 사용하면 소켓이 자동으로 비동기 모드로 설정된다. 그래서 recv/send 함수를 사용해야 한다. read/write 함수를 사용하면 WSAEWOULDBLOCK 에러가 발생할 수 있다.
'Programming > Socket' 카테고리의 다른 글
socket : socket이란? (0) | 2017.01.30 |
---|---|
socket : TCP/IP란? (0) | 2017.01.30 |
윈속(Winsock)으로 채팅 프로그램을 만들어보자 (0) | 2016.08.13 |
소켓 종료 명령 - close()와 shutdown() (2) | 2016.07.26 |
소켓 멀티플렉싱 함수 select() (0) | 2016.07.20 |
- Total
- Today
- Yesterday
- 데이터베이스
- 운영체제
- scala
- C/C++
- mongoDB
- ios
- C++
- game
- SOCKET
- machine learing
- 자료구조
- Cocos2d-x
- OS
- DesignPattern
- winsock
- SwiftUI
- 드라마
- 수학
- Git
- ue4
- Java
- JSP
- C
- rxswift
- database
- 국내여행
- SHADER
- swift
- 알고리즘
- Spring
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |