리눅스, 윈도우 소켓 함수 형식상 다른 부분 정리 |
| programming/server 2003/01/01 02:36 |
유닉스/리눅스랑 윈도우용용 소켓 프로그래밍시 약간 다른 점들을 - 약간만 시행 착오 겪으면 알만한 내용입니다만 - 몇 개 정리해봤습니다.
(개인적으론 윈도우 개발 환경이 편해서, 실제 타겟 서버가 유닉스 계열이더라도, 먼저 윈도우에서 디버깅까지 한 후에 리눅스 서버에 올려서 테스트하는 식의 작업 방식을 취할 거 같습니다.)
1. 매크로
- 윈소켓에선 유닉스 계열의 소켓에서 사용하는 일부 매크로 (SOCKET, INVALID_SOCKET, ...) 매크로를 사용하지 않습니다. (그래서 샘플에선 아래처럼 정의해서 유닉스 계열에서 사용하도록 했습니다.)
ex)
2. 구조체 구성이 틀린 경우
- select 함수를 사용할 때 사용하는 fd_set 의 경우 방식이 약간 다릅니다. FD_SET으로 소켓을 추가하면, 윈속은 리스트에 그 소켓을 추가하고 카운터를 늘리는 식이지만, 유닉스 계열은 그 소켓 핸들 부분에 체크만 하는 식이기 때문에 결과를 검색할 때는 약간 다르게 접근합니다.
ex)
- SOCKADDR_IN.sin_addr.s_addr 맴버의 경우 윈속은 맴버가 한번 더 걸쳐 선언되어 있습니다.
ex)
3. 함수가 틀린 경우
- 유닉스는 소켓도 그냥 일반 핸들 닫는 것처럼 close 로 닫습니다만 윈도우는 closesocket 함수로 닫습니다.
ex)
- ioctl 함수도 윈소켓에선 ioctlsocket 함수로 정의되어 있습니다.
ex)
4. 인자가 틀린 경우
accept 시 소켓 길이를 넘기는 인자가 윈도우는 int 형의 포인터이지만, 유닉스 계열은 socklen_t 구조체의 포인터입니다. (차이야 거의 없지만..)
ex)
5. 초기화
유닉스 계열은 별도의 초기화가 필요 없지만 윈속은 초기화 해주어야 하고 종료할 때는 WSACleanup 해주어야 합니다
ex)
6. 셈플
같이 있는 셈플은 간단한 echo 서버코드와 client 입니다.
먼저 echo 서버는 위에 정리된 것들을 바탕으로 select 를 사용해서 작성했습니다.
(개인적으로 무조건 먼저 select 로 처리가 불가능한지부터 고민할 정도로 select를 선호하는... ^^)
FreeBSD 와 Windows2000 환경에서 테스트를 했습니다.
서버를 실행하신후에 윈도우 콘솔에서 "> telnet ip port" 식으로 접속해서도 테스트 해보실 수 있습니다.
socket.c 를 같이 컴파일 하면 되고, 비주얼 C 에선 콘솔 프로젝트로 프로젝트 생성하시면 됩니다.
client는 그냥 서버에 연결해서 넌블럭킹 모드로 키랑 받은 데이타 체크해서 뿌려주는 간단한 셈플입니다.
이건 그냥 윈도우에서만 테스트 했습니다. (유닉스 계열에선 키 입력 부분을 조금 바꿔주어야 할지도...)
역시 socket.c 가 필요하겠습니다.
ps. 네트웍쪽은 경험도 없고, 교류도 없어서, 뭘 잘못했는 지도 전혀 모르니, 잘못될만한 부분이 있으면 지적 해주세요.
(개인적으론 윈도우 개발 환경이 편해서, 실제 타겟 서버가 유닉스 계열이더라도, 먼저 윈도우에서 디버깅까지 한 후에 리눅스 서버에 올려서 테스트하는 식의 작업 방식을 취할 거 같습니다.)
1. 매크로
- 윈소켓에선 유닉스 계열의 소켓에서 사용하는 일부 매크로 (SOCKET, INVALID_SOCKET, ...) 매크로를 사용하지 않습니다. (그래서 샘플에선 아래처럼 정의해서 유닉스 계열에서 사용하도록 했습니다.)
ex)
| #ifndef _WIN32 #define INVALID_SOCKET (~0) #define SOCKET int #define SOCKET_ERROR (~0) #define SOCKADDR_IN struct sockaddr_in #endif |
2. 구조체 구성이 틀린 경우
- select 함수를 사용할 때 사용하는 fd_set 의 경우 방식이 약간 다릅니다. FD_SET으로 소켓을 추가하면, 윈속은 리스트에 그 소켓을 추가하고 카운터를 늘리는 식이지만, 유닉스 계열은 그 소켓 핸들 부분에 체크만 하는 식이기 때문에 결과를 검색할 때는 약간 다르게 접근합니다.
ex)
| fd_set fdset; select(FD_SETSIZE, &fdset, 0, 0, 0); #ifdef _WIN32 for(i=0; i<fdset.fd_count; i++) { socket = testfds.fd_array[i]; #else for(i=0; i<FD_SETSIZE; i++) { if (!FD_ISSET(i, &fdset)) continue; socket = i; #endif .... } |
- SOCKADDR_IN.sin_addr.s_addr 맴버의 경우 윈속은 맴버가 한번 더 걸쳐 선언되어 있습니다.
ex)
| SOCKADDR_IN addr; #ifdef _WIN32 addr.sin_addr.S_un.S_addr = ip; #else addr.sin_addr.s_addr = ip; #endif |
3. 함수가 틀린 경우
- 유닉스는 소켓도 그냥 일반 핸들 닫는 것처럼 close 로 닫습니다만 윈도우는 closesocket 함수로 닫습니다.
ex)
| #ifdef _WIN32 closesocket(s); #else close(s); #endif |
- ioctl 함수도 윈소켓에선 ioctlsocket 함수로 정의되어 있습니다.
ex)
| #ifdef _WIN32 ioctlsocket(s, FIONBIO, &m); #else ioctl(s, FIONBIO, &m); #endif |
4. 인자가 틀린 경우
accept 시 소켓 길이를 넘기는 인자가 윈도우는 int 형의 포인터이지만, 유닉스 계열은 socklen_t 구조체의 포인터입니다. (차이야 거의 없지만..)
ex)
| SOCKET Accept(SOCKET s) { SOCKADDR_IN addr; #ifdef _WIN32 int addrlen; #else socklen_t addrlen; #endif addrlen = sizeof(addr); return accept(s, (struct sockaddr *)&addr, &addrlen); } |
5. 초기화
유닉스 계열은 별도의 초기화가 필요 없지만 윈속은 초기화 해주어야 하고 종료할 때는 WSACleanup 해주어야 합니다
ex)
| #ifdef _WIN32 WSADATA WSAData; if (WSAStartup(MAKEWORD(1, 1), &WSAData)) error("Winsock is uninstalled."); #endif |
6. 셈플
같이 있는 셈플은 간단한 echo 서버코드와 client 입니다.
먼저 echo 서버는 위에 정리된 것들을 바탕으로 select 를 사용해서 작성했습니다.
(개인적으로 무조건 먼저 select 로 처리가 불가능한지부터 고민할 정도로 select를 선호하는... ^^)
FreeBSD 와 Windows2000 환경에서 테스트를 했습니다.
서버를 실행하신후에 윈도우 콘솔에서 "> telnet ip port" 식으로 접속해서도 테스트 해보실 수 있습니다.
socket.c 를 같이 컴파일 하면 되고, 비주얼 C 에선 콘솔 프로젝트로 프로젝트 생성하시면 됩니다.
client는 그냥 서버에 연결해서 넌블럭킹 모드로 키랑 받은 데이타 체크해서 뿌려주는 간단한 셈플입니다.
이건 그냥 윈도우에서만 테스트 했습니다. (유닉스 계열에선 키 입력 부분을 조금 바꿔주어야 할지도...)
역시 socket.c 가 필요하겠습니다.
ps. 네트웍쪽은 경험도 없고, 교류도 없어서, 뭘 잘못했는 지도 전혀 모르니, 잘못될만한 부분이 있으면 지적 해주세요.
댓글을 달아 주세요
감사합니다 ^-^)/
관심을 끌. 너가 동일할 좋을 지점을 다시 배치할 것 을 나는 희망한다.
나는 배웠다 매우…
걸출한 블로그!
걸출한 위치! 많은 감사.
좋은 영역! 걸출한 영역!
친구는 위치의 너의 현재 팬이 되었다!
정보를 위한 감사합니다.
너의 방문한 위치를 즐기는!
위치에 그것을 중대한 일은 좋아했다!
좋은 위치는 찾아본 그것 즐겼다!
중대하고 유용한 위치!
좋은 영역! 걸출한 영역!
아주 좋은 나는 위치 그것을 감사 좋아한다!