Windows网络程序设计
课程设计
课 程 名 称 ping程序设计
姓 名
系 专 业 计算机科学系网络工程班
导师姓名职 称
完 成 时 间 2013年X月X日
目 录
概述······························································1
11 设计目·························································1
12 功描述·························································1
二 技术理概述·····················································1
21 RAW模式SOCKET编程·········································1
22 基设计·························································2
三 程序具体操作···················································2
31 Ping模块 ······················································2
32 功控制模块·····················································5
33 数报解析模块··················································6
四 程序具体实现·····················································8
41初始化模块设计实现···············································8
42功控制模块实现···············································9
43数块解读模块实现············································13
44 ping设置模块实现··············································14
五 实验总结源代码··············································15
51实验总结························································16
52部分关键源码····················································16
概述
11设计目
PING程序较测试网络连通性程序PING程序基ICMPICMP回送请求回送应答工作计算机网络课程知道ICMP基IP协议ICMP包通IP封装传递
12功描述
设计 C语言实现 ping命令测试机机间联通情况程序提供选项实现功
(1)实现ping功程序实现基ping操作发送ICMP回显请求报文接收显应答报文
(2)记录路程序提供r选项记录源机目机路
(3)输出指定条数记录程序提供n选项输出指定条数记录
(4)指定输出条记录程序提供datasize选项指定输出数报
(5)输出户帮助程序提供户帮助显示程序提供选项选项格
二技术理概述
21 RAW模式SOCKET编程
PING程序面户应程序该程序ICMP封装机制通IP协议工作实现直接IPICMP包进行操作实验中RAW模式SOCKET编程
ICMPTCPIP协议集中子协议属网络层协议机路器间传递控制信息包括报告错误交换受限控制状态信息等遇IP数法访问目标IP路器法前传输速率转发数包等情况时会动发送ICMP消息通Ping命令发送ICMP回应请求消息记录收ICMP回应回复消息通消息网络机障提供参考
该协议进行相应ICMP设置Windows XP中首先开网络连接右键单击启Internet连接防火墙网络连接选择属性开属性窗口接着选择高级选项卡单击右角设置钮然高级设置窗口中选择ICMP选项卡中进行相应设置包括允许传入回显请求等
熟悉SOCKET编程包括基系统调SOCKETBINDLISTEN等
22基设计
221定义数结构
需定义IP数报ICMP包等相关数结构程序定义3结构体:iphdricmphdripotionhdr分存放IP报头信息ICM P报头信息IP路选项信息
222程序实现
WINDOWS环境实现PING程序
223程序求
命令提示符输入:
PING ΧΧΧΧΧΧΧΧΧΧΧΧ
中ΧΧΧ目机IP址求支持域名否带开关变量做求带开关变量时求返回4次响应
返回信息格式:
REPLY FROM ΧΧΧΧΧΧΧΧΧΧΧΧ
REQUEST TimeOut (法PING通情况)
三程序具体操作
31 Ping模块
Ping()函数程序核心部分基调模块函数实现终功布骤包括:定义初始化全局变量开socket动态库设置接收发送超时值域名址解析分配存创建初始化ICMP报文发送ICMP请求报文接收ICMP 应答报文解读应答报文输出Ping结果释放占资源流程页图31示
注释:
(1) 该模块非处理包括判断输出判断结果含义
(2) 程序没运行次输出四行结果(前提输入址效)欲次PING址必须重新启动程序
(3) 输入时输入目标机名然ping结果TIMEOUT
开始
定义初始化全局变量
判断WSAStartup函数否调成功
输出调失败
否
创建套接字设置socket接收超时发送超时选项
输入PINGIP址
解析输入容设置PING参数
创建填充ICMP数报文
判断否已发送四次
Break
发送接收解析数包
输出PIING结果
结束
清残余
否
图31 模块流程图
32功控制模块
功控制模块模块提供调函数该模块包括参数获取功计算ICMP数报文检验清SOCKETICMP包数接受缓区占资源释放功显示尸帮助功该模块包含三函数实现流程图22示
Checksum开始
定义初始化cksum
(size > 1)
确定cksumsize
if (size)
计算校验cksum获结果
cksum + *(UCHAR*)buffer
否
结束
Cleanup开始
if (m_hSocket INVALID_SOCKET)
关闭套接字
释放占资源
清ICMP包数接受缓区
F
WSACleanup()
结束
图32 功控制模块
注释:
(1) illICMPData系列初始化语句流程图中画出
(2) Cleanup() 函数中WSACleanup()HeapFree()closesocket()库函数
(3) checksum()校验函数冗余校验种形式 通错误检测方法空间(通信)者时间(计算机存储)传送数完整性进行检查种简单方法
33数报解析模块
数报解析模块提供解读IP选项解读IcMP报文功机收目机返回1cMP回显应答报文开始逐解读IcMP报文果需记录路情况IcMP解析函数调IP选项解读函数实现IP路输出(程序没功该模块DecodeICMPHeader函数实现中间会调模块相应函数流程图图23
注释:
(1) 判断否数报回应前判断回应少容语句未呈现出
(2) 函数GetTickCount()记录时机处现时间(毫秒级)
DecodeICMPHeader开始
定义相关变量初始化
tick GetTickCount()
回应报文
输出
tick0[icmpcount]tick icmphdr>timestamp
判断时间否1ms
printf(Reply from s dytesd time<1ms icmp_seq d\ninet_ntoa(from>sin_addr) bytes icmphdr>i_seq )
printf(Reply from s dytesd timed icmp_seq d\ninet_ntoa(from>sin_addr) bytestick0[icmpcount] icmphdr>i_seq)
icmpcount++
结束
结束
否
图33 数报解析模块
四程序具体实现
41 初始化模块设计实现
init_ping_packet(send_buf packet_size seq_no)
if (send_ping(sd dest send_buf packet_size) > 0)
{
while (1)
{
int feed_back
feed_back recv_ping(sd source recv_buf MAX_PING_PACKET_SIZE)
if (feed_back (1))
{
Pull the sequence number out of the ICMP header If
it's bad we just complain but otherwise we take
off because the read failed for some reason
unsigned short header_len recv_buf>h_len * 4
ICMPHeader* icmphdr (ICMPHeader*)
((char*)recv_buf + header_len)
if (icmphdr>seq seq_no) {
continue
}
else {
SendMessage(WM_MYMESSAGE)
break
}
}
if (feed_back0) {
Success or fatal error (as opposed to a minor error)
so take off
if((decode_reply(recv_buf packet_size &source) 2))
{SendMessage(WM_MYMESSAGE)
break}
}
if(feed_back2) {SendMessage(WM_MYMESSAGE)break}
}
}
}
42 功控制模块实现
421部分界面功实现函数:
int CMypingDlgsetup_for_ping(unsigned long IP int ttl SOCKET &sd sockaddr_in &dest)
{
Create the socket
sd socket(AF_INET SOCK_RAW IPPROTO_ICMP)
unsigned long arg 1
ioctlsocket(sdFIONBIO&arg)
if (sd INVALID_SOCKET) {
m_listctlInsertString(linenum++ Failed to create raw socket )
return 1
}
if (setsockopt(sd IPPROTO_IP IP_TTL (const char*)&ttl
sizeof(ttl)) SOCKET_ERROR) {
m_listctlInsertString(linenum++ TTL setsockopt failed )
return 1
}
Initialize the destination host info block
memset(&dest 0 sizeof(dest))
Turn first passed parameter into an IP address to ping
unsigned int addr IP
if (addr INADDR_NONE) {
It was a dotted quad number so save result
destsin_addrs_addr addr
destsin_family AF_INET
}
return 0
}
int CMypingDlgdecode_reply(IPHeader *reply int bytes sockaddr_in *from)
{
Skip ahead to the ICMP header within the IP packet
unsigned short header_len reply>h_len * 4
ICMPHeader* icmphdr (ICMPHeader*)((char*)reply + header_len)
Make sure the reply is sane
if (bytes < header_len + ICMP_MIN) {
FILE *fp
char str1send[100]
fpfopen(cceshitxtw+)
fprintf(fptoo few bytes from sinet_ntoa(from>sin_addr))
rewind(fp)
fgets(str1send100fp)
m_listctlInsertString(linenum++str1send)
fclose(fp)
return 1
}
else if (icmphdr>type ICMP_ECHO_REPLY) {
if (icmphdr>type ICMP_TTL_EXPIRE) {
if (icmphdr>type ICMP_DEST_UNREACH) {
m_listctlInsertString(linenum++Destination unreachable)
}
return 1
}
If TTL expired fall through Next test will fail if we
try it so we need a way past it
}
else if (icmphdr>id (USHORT)GetCurrentProcessId()) {
Must be a reply for another pinger running locally so just
ignore it
return 2
}
Figure out how far the packet travelled
int nHops int(reply>ttl)
Okay we ran the gamut so the packet must be legal dump it
if (icmphdr>type ICMP_TTL_EXPIRE) {
stroutFormat(Reply from s idd bytesd TTL expiredinet_ntoa(from>sin_addr)icmphdr>idbytes)
m_listctlInsertString(linenum++ strout)fflush(stdout)
}
else {
stroutFormat(Reply from s idd bytesd TTLd timedmsinet_ntoa(from>sin_addr)icmphdr>idbytesnHops(GetTickCount() icmphdr>timestamp))
m_listctlInsertString(linenum++ strout)fflush(stdout)
}
return 0
}
unsigned short CMypingDlgip_checksum(unsigned short *buffer int size)
{
unsigned long cksum 0
Sum all the words together adding the final byte if size is odd
while (size > 1) {
cksum + *buffer++
size sizeof(unsigned short)
}
if (size) {
cksum + *(unsigned char*)buffer
}
Do a little shuffling
cksum (cksum >> 16) + (cksum & 0xffff)
cksum + (cksum >> 16)
Return the bitwise complement of the resulting mishmash
return (unsigned short)(~cksum)
}
void CMypingDlgOnTestMessage(WPARAM wParamLPARAM lParam)
{
TODO Add your message handler code here andor call default
if(times0)m_button1EnableWindow(TRUE)
ICMPHeader* send_buf 0
IPHeader* recv_buf 0
unsigned long int IP
取入设置参数
UpdateData(TRUE)
报文
int packet_size m_size
packet_size max(sizeof(ICMPHeader)
min(MAX_PING_DATA_SIZE (unsigned int)packet_size))
423校验函数
unsigned short CMypingDlgip_checksum(unsigned short *buffer int size)
{
unsigned long cksum 0
Sum all the words together adding the final byte if size is odd
while (size > 1) {
cksum + *buffer++
size sizeof(unsigned short)
}
if (size) {
cksum + *(unsigned char*)buffer
}
Do a little shuffling
cksum (cksum >> 16) + (cksum & 0xffff)
cksum + (cksum >> 16)
Return the bitwise complement of the resulting mishmash
return (unsigned short)(~cksum)
}
43 数块解读模块实现
431数包头函数
unsigned short header_len recv_buf>h_len * 4
ICMPHeader* icmphdr (ICMPHeader*)
((char*)recv_buf + header_len)
if (icmphdr>seq seq_no) {
continue
}
else {
SendMessage(WM_MYMESSAGE)
break
}
}
432初始化套接字函数
WSAData wsaData
if (WSAStartup(MAKEWORD(2 1) &wsaData) 0) {
m_listctlInsertString(linenum++ Failed to find Winsock 21 or better )
UpdateData(FALSE)
m_button1EnableWindow(TRUE)
goto cleanup
}
433解读IP头函数
int CMypingDlgallocate_buffers(ICMPHeader *&send_buf IPHeader *&recv_buf int packet_size)
{
First the send buffer
send_buf (ICMPHeader*)new char[packet_size]
if (send_buf 0) {
m_listctlInsertString(linenum++ Failed to allocate output buffer )
return 1
}
And then the receive buffer
recv_buf (IPHeader*)new char[MAX_PING_PACKET_SIZE]
if (recv_buf 0) {
m_listctlInsertString(linenum++ Failed to allocate output buffer )
return 1
}
return 0
}
44 ping设置模块实现
int CMypingDlgsetup_for_ping(unsigned long IP int ttl SOCKET &sd sockaddr_in &dest)
{
Create the socket
sd socket(AF_INET SOCK_RAW IPPROTO_ICMP)
unsigned long arg 1
ioctlsocket(sdFIONBIO&arg)
if (sd INVALID_SOCKET) {
m_listctlInsertString(linenum++ Failed to create raw socket )
return 1
}
if (setsockopt(sd IPPROTO_IP IP_TTL (const char*)&ttl
sizeof(ttl)) SOCKET_ERROR) {
m_listctlInsertString(linenum++ TTL setsockopt failed )
return 1
}
Initialize the destination host info block
memset(&dest 0 sizeof(dest))
Turn first passed parameter into an IP address to ping
unsigned int addr IP
if (addr INADDR_NONE) {
It was a dotted quad number so save result
destsin_addrs_addr addr
destsin_family AF_INET
}
return 0
}
五 实验总结源代码
51实验总结
次课程设计较实现求做功时遇少困难挑战通次设计加深Socket原始套接字编程理解实现Ping程序熟悉IPICMP等掌握TCPIP网络协议基实现方法熟悉Window网络编程技术熟悉套接字进行网络通信熟悉数通信网络技术时学会学合作交流完成项目讨方法解决问题力学会果通讨交流找资料独立解决遇问题懂更锻炼独立解决问题力
编写程中基常见函数会应组发现知识匮乏学程中努力阅读复杂程序解基函数算法精良编程思想更动手写定难度程序应该害怕写程序出错应该胆写出想法出现错误解决错误找出知识漏洞模糊点通阅读错误程序试着帮查找错误样证书技头脑中规发现初学者番错误少走弯路
52部分关键源码
void CMypingDlgOnButton1()
{
TODO Add your control notification handler code here
m_button1EnableWindow(FALSE)
seq_no int(GetCurrentProcessId())
ICMPHeader* send_buf 0
IPHeader* recv_buf 0
unsigned long int IP
ttlDEFAULT_TTL
取入设置参数
UpdateData(TRUE)
报文
int packet_size m_size
packet_size max(sizeof(ICMPHeader)
min(MAX_PING_DATA_SIZE (unsigned int)packet_size))
ping次数
if(m_times <0)
{
m_times1
times1
}
else
timesm_times
UpdateData(FALSE)
目IP
if(m_radioctlGetCheck()BST_CHECKED)
{
if (m_ipGetAddress(IP)<4) 取IP
{
MessageBox(_T(请重新输入IP址)_T(错误IP址)MB_OK |
MB_ICONEXCLAMATION)
m_button1EnableWindow(TRUE)
goto end2
}
IPhtonl(IP)
}
else
{
sockaddr_in sa
WSAData wsaData
WSAStartup(MAKEWORD(2 1) &wsaData)
char str[150]
int j
CString host
this>GetDlgItemText(IDC_EDIT1host)
for( j 0 j < hostGetLength() j++)
str[j] hostGetAt(j)
str[j]'\0'
hostent *hp
if((hpgethostbyname(str))NULL)
{
m_listctlInsertString(linenum++ Something wrong with the host name )
m_button1EnableWindow(TRUE)
goto end1
}
memcpy ((char *)&sasin_addr(char *)hp>h_addrhp>h_length)
IP sasin_addrs_addr
WSACleanup()
}
Start Winsock up
WSAData wsaData
if (WSAStartup(MAKEWORD(2 1) &wsaData) 0) {
m_listctlInsertString(linenum++ Failed to find Winsock 21 or better )
UpdateData(FALSE)
m_button1EnableWindow(TRUE)
goto cleanup
}
Set up for pinging
SOCKET sd
sockaddr_in dest source
if (setup_for_ping(IP ttl sd dest) < 0) {
m_button1EnableWindow(TRUE)
goto cleanup
}
if (allocate_buffers(send_buf recv_buf packet_size) < 0) {
m_button1EnableWindow(TRUE)
goto cleanup
}
Send the ping and receive the reply
if(times)
{
延时
int i GetTickCount()
for( (GetTickCount() i)<1000 )
init_ping_packet(send_buf packet_size seq_no)
if (send_ping(sd dest send_buf packet_size) > 0)
{
while (1)
{
int feed_back
feed_back recv_ping(sd source recv_buf MAX_PING_PACKET_SIZE)
Receive replies until we either get a successful read
or a fatal error occurs
if (feed_back (1))
{
Pull the sequence number out of the ICMP header If
it's bad we just complain but otherwise we take
off because the read failed for some reason
unsigned short header_len recv_buf>h_len * 4
ICMPHeader* icmphdr (ICMPHeader*)
((char*)recv_buf + header_len)
if (icmphdr>seq seq_no) {
continue
}
else {
SendMessage(WM_MYMESSAGE)
break
}
}
if (feed_back0) {
Success or fatal error (as opposed to a minor error)
so take off
if((decode_reply(recv_buf packet_size &source) 2))
{SendMessage(WM_MYMESSAGE) break}
}
if(feed_back2) {SendMessage(WM_MYMESSAGE)break}
}
}
}
void CMypingDlginit_ping_packet(ICMPHeader *icmp_hdr int packet_size int seq_no)
{
Set up the packet's fields
icmp_hdr>type ICMP_ECHO_REQUEST
icmp_hdr>code 0
icmp_hdr>checksum 0
icmp_hdr>id (USHORT)GetCurrentProcessId()
icmp_hdr>seq seq_no
icmp_hdr>timestamp GetTickCount()
You're dead meat now packet
const unsigned long int deadmeat 0xDEADBEEF
char* datapart (char*)icmp_hdr + sizeof(ICMPHeader)
int bytes_left packet_size sizeof(ICMPHeader)
while (bytes_left > 0) {
memcpy(datapart &deadmeat min(int(sizeof(deadmeat))
bytes_left))
bytes_left sizeof(deadmeat)
datapart + sizeof(deadmeat)
}
Calculate a checksum on the result
icmp_hdr>checksum ip_checksum((USHORT*)icmp_hdr packet_size)
}
int CMypingDlgsend_ping(SOCKET sd const sockaddr_in &dest ICMPHeader *send_buf int packet_size)
{
Send the ping packet in send_buf asis
if (times(m_times1))
{
stroutFormat(Sending d bytes to s packet_sizeinet_ntoa(destsin_addr))
m_listctlInsertString(linenum++ )
m_listctlInsertString(linenum++ strout)fflush(stdout)
m_listctlInsertString(linenum++ )
}
int bwrote sendto(sd (char*)send_buf packet_size 0 (sockaddr*)&dest sizeof(dest))
if (bwrote SOCKET_ERROR) {
stroutFormat(Send failed error Cd WSAGetLastError())
m_listctlInsertString(linenum++ strout)
return 1
}
else if (bwrote < packet_size) {
stroutFormat(Send d bytes bwrote)
m_listctlInsertString(linenum++ strout)
}
return 0
}
int CMypingDlgrecv_ping(SOCKET sd sockaddr_in &source IPHeader *recv_buf int packet_size)
{
调select进行处理
timeval timeout
timeouttv_sec1
timeouttv_usec0
fd_set readfds
FD_ZERO(&readfds)
FD_SET(sd&readfds)
select(0&readfds00&timeout)
if(FD_ISSET(sd&readfds)){
m_listctlInsertString(linenum++ Request time out)
return 2}
Wait for the ping reply
int fromlen sizeof(source)
int bread recvfrom(sd (char*)recv_buf packet_size + sizeof(IPHeader) 0
(sockaddr*)&source &fromlen)
if (bread SOCKET_ERROR) {
m_listctlInsertString(linenum++ read failed)
if (WSAGetLastError() WSAEMSGSIZE) {
m_listctlInsertString(linenum++ buffer too small)
}
else {
m_listctlInsertString(linenum++ error #)
}
return 1
}
return 0
}
int CMypingDlgsetup_for_ping(unsigned long IP int ttl SOCKET &sd sockaddr_in &dest)
{
Create the socket
sd socket(AF_INET SOCK_RAW IPPROTO_ICMP)
unsigned long arg 1
ioctlsocket(sdFIONBIO&arg)
if (sd INVALID_SOCKET) {
m_listctlInsertString(linenum++ Failed to create raw socket )
return 1
}
if (setsockopt(sd IPPROTO_IP IP_TTL (const char*)&ttl
sizeof(ttl)) SOCKET_ERROR) {
m_listctlInsertString(linenum++ TTL setsockopt failed )
return 1
}
Initialize the destination host info block
memset(&dest 0 sizeof(dest))
Turn first passed parameter into an IP address to ping
unsigned int addr IP
if (addr INADDR_NONE) {
It was a dotted quad number so save result
destsin_addrs_addr addr
destsin_family AF_INET
}
return 0
}
int CMypingDlgdecode_reply(IPHeader *reply int bytes sockaddr_in *from)
{
Skip ahead to the ICMP header within the IP packet
unsigned short header_len reply>h_len * 4
ICMPHeader* icmphdr (ICMPHeader*)((char*)reply + header_len)
Make sure the reply is sane
if (bytes < header_len + ICMP_MIN) {
FILE *fp
char str1send[100]
fpfopen(cceshitxtw+)
fprintf(fptoo few bytes from sinet_ntoa(from>sin_addr))
rewind(fp)
fgets(str1send100fp)
m_listctlInsertString(linenum++str1send)
fclose(fp)
return 1
}
else if (icmphdr>type ICMP_ECHO_REPLY) {
if (icmphdr>type ICMP_TTL_EXPIRE) {
if (icmphdr>type ICMP_DEST_UNREACH) {
m_listctlInsertString(linenum++Destination unreachable)
}
return 1
}
If TTL expired fall through Next test will fail if we
try it so we need a way past it
}
else if (icmphdr>id (USHORT)GetCurrentProcessId()) {
Must be a reply for another pinger running locally so just
ignore it
return 2
}
Figure out how far the packet travelled
int nHops int(reply>ttl)
Okay we ran the gamut so the packet must be legal dump it
if (icmphdr>type ICMP_TTL_EXPIRE) {
stroutFormat(Reply from s idd bytesd TTL expiredinet_ntoa(from>sin_addr)icmphdr>idbytes)
m_listctlInsertString(linenum++ strout)fflush(stdout)
}
else {
stroutFormat(Reply from s idd bytesd TTLd timedmsinet_ntoa(from>sin_addr)icmphdr>idbytesnHops(GetTickCount() icmphdr>timestamp))
m_listctlInsertString(linenum++ strout)fflush(stdout)
}
return 0
}
unsigned short CMypingDlgip_checksum(unsigned short *buffer int size)
{
unsigned long cksum 0
Sum all the words together adding the final byte if size is odd
while (size > 1) {
cksum + *buffer++
size sizeof(unsigned short)
}
if (size) {
cksum + *(unsigned char*)buffer
}
Do a little shuffling
cksum (cksum >> 16) + (cksum & 0xffff)
cksum + (cksum >> 16)
Return the bitwise complement of the resulting mishmash
return (unsigned short)(~cksum)
}
WSAData wsaData
if (WSAStartup(MAKEWORD(2 1) &wsaData) 0) {
m_listctlInsertString(linenum++ Failed to find Winsock 21 or better )
UpdateData(FALSE)
m_button1EnableWindow(TRUE)
goto cleanup
}
Set up for pinging
SOCKET sd
sockaddr_in dest source
if (setup_for_ping(IP ttl sd dest) < 0) {
m_button1EnableWindow(TRUE)
goto cleanup
}
if (allocate_buffers(send_buf recv_buf packet_size) < 0) {
m_button1EnableWindow(TRUE)
goto cleanup
}
湘nan学院
文档香网(httpswwwxiangdangnet)户传
《香当网》用户分享的内容,不代表《香当网》观点或立场,请自行判断内容的真实性和可靠性!
该内容是文档的文本内容,更好的格式请下载文档