336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
소켓 통신 #3 - ICMP 클라이언트 구현하기(2)
- by Tapito
ICMP로 통신하기 위해서는 저수준 소켓을 만듭니다. 만일 Windows 운영체제에서 이 단계에 INVALID_SOCKET이 반환되고 GetLastError 함수 등을 통해 10013 오류가 확인되었다면 해당 프로그램을 관리자모드로 실행하면 됩니다.
SOCKET icmpSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
struct sockaddr_in icmpDestination에 ping을 보낼 대상이 미리 저장되어있다고 하면 sendto 소켓함수를 통해 상대방의 수신 여부와 무관하게 일방적으로 데이터(ICMP를 포함한 패킷 전체)를 쏩니다. 전송 성공 시 전송된 바이트 수를 반환하고 그렇지 않으면 SOCKET_ERROR를 반환합니다. 4번째 매개변수는 전송 옵션으로 보통 0을 넣습니다.
sendto(icmpSocket, (char *)패킷, sizeof(패킷), 0, (struct sockaddr *)icmpDestination, sizeof(struct sockaddr_in));
에코가 되돌아올 때까지 잠시 대기합니다. select 소켓 함수가 그 역할을 합니다. Windows 운영체제에서 첫 번째 매개변수는 신경쓰지 않아도 됩니다. 반환 값으로서 -1은 소켓 오류, 0은 타임아웃, 양수는 수신된 바이트 수입니다.
select(1, 읽기소켓, 쓰기소켓, 오류출력소켓, 제한시간);
select 함수로 에코가 되돌아왔음이 확인되면 recvfrom으로 데이터를 가져옵니다. 가져오는 패킷의 형식은 IP 헤더-ICMP 헤더-전송시 프로그램 작성자가 부가적으로 보낸 데이터의 순서입니다. 소켓 오류 시 SOCKET_ERROR, 성공 시 수신한 패킷의 바이트 수가 반환됩니다.
recvfrom(icmpSocket, (char *)&icmpResponse, sizeof(icmpResponse), 0, pSocketAddress, &nSocketAddress);
구글 서버로 ping을 1회 보내보겠습니다. 분량상 오류 발생 시 처리 사항은 생략하겠습니다.
/* 예제 */ SOCKET icmpSocket; // 저수준 소켓 struct sockaddr_in icmpDestination; // 수신지 주소 (서버) struct sockaddr_in icmpSource; // 발신지 주소 (여러분 PC) /* 1 단계. 저수준 소켓 생성 */ icmpSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); // Windows 운영체제에서 여기가 10013 오류나면 관리자 모드로 실행 memset(&icmpDestination, sizeof(icmpDestination), 0); memset(&icmpSource, sizeof(icmpSource), 0); icmpDestination.sin_family = AF_INET; // 인터넷 망에 접속 icmpDestination.sin_port = 0; // 포트 번호: 0번 icmpDestination.sin_addr.s_addr = inet_addr("173.194.127.212"); // 구글 www.google.com의 IP 주소 /* 2 단계. 시험 데이터 일방적 전송 */ ICMPREQUEST icmpRequest; // 전송할 패킷 ZeroMemory(&icmpRequest, sizeof(icmpRequest)); icmpRequest.icmpHeader.bType = 8; icmpRequest.icmpHeader.bCode = 0; icmpRequest.icmpHeader.wChecksum = 0; icmpRequest.icmpHeader.wIdentification = (WORD)(_getpid() & 0xFFFF); // ID와 Sequence 값은 임의로 설정 가능 icmpRequest.icmpHeader.wSequence = 1; icmpRequest.icmpHeader.wChecksum = GetChecksumWord((LPBYTE)&icmpRequest, sizeof(icmpRequest)); // 전송할 패킷 모두 구성한 후에 체크섬 구하기 sendto(icmpSocket, (LPSTR)&icmpRequest, sizeof(ICMPREQUEST), 0, (struct sockaddr *)pDestination, sizeof(struct sockaddr_in)); // 전송 /* 3 단계. 에코가 돌아올 때까지 대기 */ struct timeval timeOut; // 제한 시간 fd_set fdset; // fd_set 구조체를 통해 여러개의 소켓을 동시에 감지할 수 있습니다. 여기서는 1개만 FD_ZERO(&fdset); // fd_set 구조체 초기화 FD_SET(icmpSocket, &fdset); // fd_set 구조체에 감시할 소켓 하나씩 추가 timeOut.tv_sec = 1; // 제한 시간은 1.5sec로 설정 timeOut.tv_usec = 500; select(1, &fdset, NULL, NULL, &timeOut); // -1: 오류 발생, 0: 타임아웃, 양수: 수신된 데이터 크기 반환 /* 3 단계. 되돌아온 패킷 수신 */ ICMPRESPONSE icmpResponse; struct sockaddr * pSocketAddress = (struct sockaddr *)pSource; // 에코를 보낸 서버의 주소 (sendto로 지정한 주소와 다를 수 있음) int nSocketAddress = sizeof(struct sockaddr_in); int iReturn; memset(&icmpResponse, sizeof(icmpResponse), 0); // 받을 버퍼를 0으로 초기화 recvfrom(icmpSocket, (char *)&icmpResponse, sizeof(icmpResponse), 0, pSocketAddress, &nSocketAddress); // 받기 /* 4 단계. 소켓 닫기 */ closesocket(icmpSocket);
'Programming Language > C&C++' 카테고리의 다른 글
소켓 통신 #3 - ICMP 클라이언트 구현하기(3) (0) | 2014.11.14 |
---|---|
윈도우에서 IP 주소 얻는 방법 (0) | 2014.11.13 |
소켓 통신 #3 - ICMP 클라이언트 구현하기(1) (0) | 2014.11.11 |
소켓 함수를 사용하여 도메인을 IP주소간 상호 변환하기 (0) | 2014.11.05 |
소켓 통신 #2 - AF_INET 사용하기 (4) (0) | 2014.09.20 |