어떻게 간단 한 ping 프로그램 을 씁 니까?
21813 단어 네트워크 프로 그래 밍
우선, ping 이 사용 하 는 프로 토 콜 은 네트워크 계층 의 ICMP 프로 토 콜 입 니 다. ICMP 메 시 지 를 보 내 거나 받 는 것 은 ICMP 메시지 입 니 다. 최종 형식 은 IP 메시지 로 네트워크 에서 전송 되 는 것 입 니까?다음은 IP 헤드 와 ICMP 프로 토 콜 의 관련 데이터 구 조 를 정의 합 니 다.
IP 헤드
IP
0 8 16 19 31
+------------+------------+-------------------------+
| ver + hlen | | |
+------------+------------+----+--------------------+
| |flag| (13 ) |
+------------+------------+----+--------------------+
| | | |
+------------+------------+-------------------------+
| IP |
+---------------------------------------------------+
| IP |
+---------------------------------------------------+
데이터 구 조 는 비트 필드 를 사용 하여 프로 토 콜 형식 을 호 환 하고 최종 컴 파일 할 때 1 바이트 로 정렬 합 니 다.
struct IPhead
{
// C , version 4bit, 8bit
uint8_t version : 4; //IP
uint8_t headLength : 4;//
uint8_t serverce;//
uint16_t totalLength;//
uint16_t flagbit;//
uint16_t flag : 3;//
uint16_t fragmentOffset : 13;//
char timetoLive;// ( )
uint8_t protocol;//
uint16_t headcheckSum;//
uint32_t srcIPadd;// IP
uint32_t dstIPadd;// IP
//
};
ICMP 프로 토 콜 관련:
ICMP
+--------+--------+---------------+
| | | |
+--------+--------+---------------+
| 8 | 0 | |
+--------+--------+---------------+
| 10 | 0 | |
+--------+--------+---------------+
| 13 | 0 | |
+--------+--------+---------------+
| 15 | 0 | ( )|
+--------+--------+---------------+
| 17 | 0 | |
+--------+--------+---------------+
ICMP
+--------+--------+---------------+
| | | |
+--------+--------+---------------+
| 0 | 0 | |
+--------+--------+---------------+
| 9 | 0 | |
+--------+--------+---------------+
| 14 | 0 | |
+--------+--------+---------------+
| 16 | 0 | ( )|
+--------+--------+---------------+
| 18 | 0 | |
+--------+--------+---------------+
ICMP /
0 8 16 32
+--------+--------+-----------------+
| | | |
+--------+--------+-----------------+
| | |
+-----------------+-----------------+
| |
+-----------------+-----------------+
ICMP / 。 ,ICMP , , 。 ,
ICMP 관련 데이터 구조
//ICMP
struct ICMPhead
{
uint8_t type;//
uint8_t code;//
uint16_t checkSum;//
uint16_t ident;//
uint16_t seqNum;//
};
//ICMP ( )
struct ICMPrecvReq
{
ICMPhead icmphead;//
uint32_t timeStamp;//
char data[32];//
};
//ICMP ( )
struct ICMPansReply
{
IPhead iphead;//IP
ICMPrecvReq icmpanswer;//ICMP
char data[1024];//
};
실현 해 야 할 함수 도 많 지 않 고 6 개 만 있 으 면 기본 적 인 ping 프로그램 을 만족 시 킬 수 있 습 니 다.
// , 1: , 。 2: 。
uint16_t getCheckSum(void* protocol,char* type);
//ping , 1: IP 。 . 2: -t,
bool ping(const char* dstIPaddr,const char* param='\0');
// ICMP , 1: . 2: . 3: num
bool sendICMPReq(SOCKET &mysocket, sockaddr_in &dstAddr, unsigned int num);
// ICMP , 1: . 2: . 3:
uint32_t readICMPanswer(SOCKET &mysocket, sockaddr_in &srcAddr, char &TTL);
// socket
int waitForSocket(SOCKET &mysocket);
// ping , 1: . 2: . 3: 。 4 ping
void doPing(SOCKET &mysocket,sockaddr_in &srcAddr,sockaddr_in &dstAddr,int num);
// , NULL , param ,
char* isParamEmpty(char *buffer, char *param);
//
void get_ctrl_stop(int signal);
이 프로그램 은 windows 플랫폼 에서 실 현 된 액 입 니 다. winsock 을 사용 하려 면 winsock 을 사용 할 수 있 는 lib 의 사용 을 위 한 사전 처리 명령
#pragma comment(lib,"ws2_32.lib")
을 추가 해 야 합 니 다. 다음은 주제 입 니 다. ICMP 메 시 지 는 TCP 나 UDP 의 패 키 징 을 거치 지 않 고 sock 계층 의 API 는 사용자 (프로그래머) 를 위 한 것 임 을 알 고 있 습 니 다. 일반적인 sock 은 사용자 가 읽 을 때 입 니 다.시스템 은 IP 헤드 의 정 보 를 제거 해 줍 니 다. 그러면 전송 층 이하 의 프로 토 콜 에 관 한 정 보 를 얻 을 수 없습니다. 따라서 우 리 는 일반적인 sock 을 사용 하여 ping 프로그램 을 작성 할 수 없습니다. 원본 소켓 SOCK_RAW
을 사용 하려 면 원본 소켓 을 사용 하면 sock 이 데 이 터 를 요청 하고 싶 을 때 시스템 은 sock 에 대해 너무 많은 처 리 를 하지 않 습 니 다.우 리 는 최소한 데이터 링크 층 의 데 이 터 를 얻 을 수 있 기 때문에 네트워크 층 의 IP 헤더 의 데이터 도 얻 을 수 있다.전체 ping 프로그램의 기본 절 차 는 다음 과 같 습 니 다. RAW 소켓 을 만 듭 니 다. - > ping 대기 주소 와 매개 변수 수신 - > 추출 매개 변수 - > 매개 변수 에 따라 해당 하 는 ping (일반 ping 4 회 또는 무한 순환 ping) - > ping 대기 주소 에 ICMP 응답 요청 메 시 지 를 보 냅 니 다. - > 답장 메시지 수신 - > 해당 정 보 를 출력 합 니 다.그 중에서 무한 ping 에서 캡 처
Ctrl+C
종료 명령 을 처리 하 는 신호 함수 도 있 습 니 다. 그것 은 큰 절차 에 영향 을 주지 않 고 절차 에서 말 하지 않 습 니 다.8 개의 API 만 있 으 면 ping 프로그램 을 실현 할 수 있 기 때문에 저 는 하나씩 API 를 풀 려 고 합 니 다. 구체 적 인 프로젝트 코드 는 github 에 두 고 필요 한 사람 이 직접 가 져 가세 요.
파라미터 검사 및 추출
char *isParamEmpty(char *buffer, char *param)
{
char *temp = NULL;
temp = buffer;
while (*temp != '\0')
{
if (*temp == ' ')
{
*temp = '\0';
param = ++temp;
}
temp++;
}
return param;
}
계산 검사 합
uint16_t getCheckSum(void * protocol, char * type)
{
uint32_t checkSum = 0;
uint16_t* word = (uint16_t*)protocol;
uint32_t size = 0;
if (type == "ICMP") {//
size = (sizeof(ICMPrecvReq));
}
while (size >1)// 32 16 , 16
{
checkSum += *word++;
size -=2;
}
if (size == 1)
{
checkSum += *(uint8_t*)word;
}
// , ,
//
while (checkSum >> 16) checkSum = (checkSum >> 16) + (checkSum & 0xffff);
//
return (~checkSum);
}
ping 프로 세 스 선택
bool ping(const char * dstIPaddr,const char* param)
{
SOCKET rawSocket;//socket
sockaddr_in srcAddr;//socket
sockaddr_in dstAddr;//socket
int Ret;//
char TTL = '0';//
//
//TCP/IP ,RAW ,ICMP
//RAW , , IP 。
rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
// IP
dstAddr.sin_addr.S_un.S_addr = inet_addr(dstIPaddr);
//
dstAddr.sin_port = htons(0);
//
dstAddr.sin_family = AF_INET;
//
std::cout << " Ping " << inet_ntoa(dstAddr.sin_addr) << " " << sizeof(ICMPrecvReq::data) << " :" << std::endl;
if(!strcmp(param,"-t"))
{
uint32_t i=0;
while (keepping)
{
// ping
doPing(rawSocket, srcAddr, dstAddr,i);
// 1ms
Sleep(1000);
i++;
}
keepping = 1;
}
else if(!strcmp(param,"no_param"))
{ // 4 ping
for (int i = 0; i < 4; i++)
{
doPing(rawSocket, srcAddr, dstAddr, i);
Sleep(1000);
}
}
Ret = closesocket(rawSocket);
if (Ret == SOCKET_ERROR)
{
std::cerr << "socket :" << WSAGetLastError() << std::endl;
}
return true;
}
ping 실행
void doPing(SOCKET & mysocket, sockaddr_in & srcAddr, sockaddr_in & dstAddr, int num)
{
uint32_t timeSent;//
uint32_t timeElapsed;//
char TTL;//
// ICMP
sendICMPReq(mysocket, dstAddr, num);
//
int Ret = waitForSocket(mysocket);
if (Ret == SOCKET_ERROR)
{
std::cerr << "socket :" << WSAGetLastError() << std::endl;
return;
}
if (!Ret)
{
std::cout << " :" << std::endl;
return;
}
timeSent = readICMPanswer(mysocket, srcAddr, TTL);
if (timeSent != -1) {
timeElapsed = GetTickCount() - timeSent;
// , TTL ASCII ,
std::cout << " " << inet_ntoa(srcAddr.sin_addr) << " : = " << sizeof(ICMPrecvReq::data) << " = " << timeElapsed << "ms TTL= " << fabs((int)TTL) << std::endl;
}
else {
std::cout << " " << std::endl;
}
}
ICMP 메시지 보 내기
bool sendICMPReq(SOCKET &mysocket,sockaddr_in &dstAddr,unsigned int num)
{
// ICMP
//
ICMPrecvReq myIcmp;//ICMP
myIcmp.icmphead.type = 8;
myIcmp.icmphead.code = 0;
// 0
myIcmp.icmphead.checkSum = 0;
//
myIcmp.icmphead.ident = (uint16_t)GetCurrentProcessId();
// 0
myIcmp.icmphead.seqNum = ++num;
//
myIcmp.timeStamp = GetTickCount();
//
myIcmp.icmphead.checkSum = getCheckSum((void*)&myIcmp, "ICMP");
//
int Ret = sendto(mysocket, (char*)&myIcmp, sizeof(ICMPrecvReq), 0, (sockaddr*)&dstAddr, sizeof(sockaddr_in));
if (Ret == SOCKET_ERROR)
{
std::cerr << "socket :" <std::endl;
return false;
}
return true;
}
ICMP 메시지 의 답장 을 기다 리 고 있 습 니 다.
int waitForSocket(SOCKET &mysocket)
{
//5S
timeval timeOut;
fd_set readfd;
readfd.fd_count = 1;
readfd.fd_array[0] = mysocket;
timeOut.tv_sec = 5;
timeOut.tv_usec = 0;
return (select(1, &readfd, NULL, NULL, &timeOut));
}
답장 한 ICMP 메시지 읽 기
uint32_t readICMPanswer(SOCKET &mysocket, sockaddr_in &srcAddr, char &TTL)
{
ICMPansReply icmpReply;//
int addrLen = sizeof(sockaddr_in);
//
int Ret = recvfrom(mysocket, (char*)&icmpReply, sizeof(ICMPansReply), 0, (sockaddr*)&srcAddr, &addrLen);
if (Ret == SOCKET_ERROR)
{
std::cerr << "socket :" << WSAGetLastError() << std::endl;
return false;
}
//
uint16_t checkSum = icmpReply.icmpanswer.icmphead.checkSum;
// 0
icmpReply.icmpanswer.icmphead.checkSum = 0;
//
if (checkSum== getCheckSum((void*)&icmpReply.icmpanswer, "ICMP")) {
// TTL
TTL = icmpReply.iphead.timetoLive;
return icmpReply.icmpanswer.timeStamp;
}
return -1;
}
처리 종료 신호 함수
static volatile int keepping = 1;
// , ping
void get_ctrl_stop(int signal)
{
if (signal == SIGINT)
{
keepping = 0;
}
}
모든 코드 를 원한 다 면 아래 링크 에서 ping 프로그램 전체 프로젝트 를 가 져 올 수 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
자바 네트워크 프로 그래 밍 -> 상용 모듈스 트림 소켓 을 만 들 고 지정 한 IP 주소 의 지정 한 포트 번호 에 연결 합 니 다. 이 소켓 의 입력 흐름 을 되 돌려 줍 니 다. 이 소켓 의 출력 흐름 을 되 돌려 줍 니 다. 이 IP 주소 의 호스트 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.