347上位机VC MFC实现网络监听功能
实现网络监听功能
功能展示
网络监听可以用来监听网络确保自身电脑安全。在同一网络,如网卡被设为混合模式,当网络有数据报传输,无论数据报属于本机,网卡都会接收到此数据报,我们当前例程就是使用此特点实现网络监听功能,效果如图。点击<开始监听>可开启一线程进行网络数据的实时监听,点击<停止监视>可以终止线程,停止网络监听
要点提示
在网络中数据以帧形式进行传输。以TCP协议为例,当我们发送数据时,在传输层用户数据会被附加TCP首部,(TCP首部包含源端口号,目标端口号,位序号,确认序号等,具体结构参阅例程的HEADTCP结构体)。
在网线层会附加IP首部,IP首部包含数据报源地址和目标地址等,具体结构可参阅例程的HEADIP结构体。
在链路层附加地址解析协议和逆向地址解析协议用于转换IP层我网络接口层使用的地址。
获取网络中的传输数据,首先要创建一个原始套接字,此套接字获取的数据是IP层的数据报,包含IP首部,TCP或UDP首部,用户数据等信息。然后对获取的数据报去除IP首部,根据IP首部去获得数据报的源地址,目地地址,采用的协议及数据报的长度等信息,接着再根据不同的协议去除TCP或UDP首部,根据此首部去除源端口及目的端口,最后数据报剩余的部分就是用户的数据;
实现功能
1.新建基于对话框的应用程序
2.添加一列表框IDC_LIST1,关联变量CListCtrl m_List;用于显示监听到的信息,添加两按钮<开始监听><停止监视>,关联按钮的点击函数
void CGkbc8Dlg::OnMonitor()
{
m_Sock = socket(AF_INET,SOCK_RAW, IPPROTO_IP );//创建套接字
char name[128];
memset(name,0,128);
hostent* phostent;
phostent = gethostbyname(name);
DWORD ip;
ip = inet_addr(inet_ntoa(*(in_addr*)phostent->h_addr_list[0]));
int timeout = 4000; //超时4秒
setsockopt(m_Sock,SOL_SOCKET,SO_RCVTIMEO,(const char*)&timeout,sizeof(timeout));
sockaddr_in skaddr;
skaddr.sin_family = AF_INET;
skaddr.sin_port = htons(700);
skaddr.sin_addr.S_un.S_addr = ip;
if ( bind(m_Sock,(sockaddr*)&skaddr,sizeof(skaddr))==SOCKET_ERROR)//绑定地址
{
MessageBox("地址绑定错误");
return;
}
DWORD inBuffer=1;
DWORD outBuffer[10];
DWORD reValue = 0;
if (WSAIoctl(m_Sock,SIO_RCVALL,&inBuffer,sizeof(inBuffer),&outBuffer,sizeof(outBuffer),&reValue,NULL,NULL)==SOCKET_ERROR)
{
MessageBox("设置缓冲区错误.");
closesocket(m_Sock);
return;
}
m_List.DeleteAllItems();
m_bThreadStop = FALSE;
AfxBeginThread(ThreadFun,(void*)this);
}
void CGkbc8Dlg::OnStop()
{
m_bThreadStop = TRUE;
while(!m_bIsThreadStop);
closesocket(m_Sock);
}
3.上面两函数调用了一系列的自定义函数及成员变量,结构体,我们依次添加。在主对话框类源文件顶部添加线程函数(过长不贴出)及函数调用自定义函数与结构体;
PROTONAME protos[11] = {
{IPPROTO_IP ,"IP"},
{IPPROTO_ICMP,"ICMP"},
{IPPROTO_IGMP,"IGMP"},
{IPPROTO_GGP,"GGP"},
{IPPROTO_TCP,"TCP"},
{IPPROTO_PUP,"PUP"},
{IPPROTO_UDP,"UDP"},
{IPPROTO_IDP,"IDP"},
{IPPROTO_ND,"ND"},
{IPPROTO_RAW,"RAW"},
{IPPROTO_MAX,"MAX"}
};
char* get_protoname(int protoID)
{
for (int i= 0; i<11; i++)
if (protoID == protos.value)
{
return protos.protoname;
}
return "";
}
4.在主对话框类头文件添加变量,自定义结构体及网络函数所在的头文件
#include "winsock2.h"
#pragma comment (lib,"ws2_32.lib")
#include "AFXSOCK.H"
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
#define SIO_RCVALL_MCAST _WSAIOW(IOC_VENDOR,2)
#define SIO_RCVALL_IGMPMCAST _WSAIOW(IOC_VENDOR,3)
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
#define SIO_ABSORB_RTRALERT _WSAIOW(IOC_VENDOR,5)
#define SIO_UCAST_IF _WSAIOW(IOC_VENDOR,6)
#define SIO_LIMIT_BROADCASTS _WSAIOW(IOC_VENDOR,7)
#define SIO_INDEX_BIND _WSAIOW(IOC_VENDOR,8)
#define SIO_INDEX_MCASTIF _WSAIOW(IOC_VENDOR,9)
#define SIO_INDEX_ADD_MCAST _WSAIOW(IOC_VENDOR,10)
#define SIO_INDEX_DEL_MCAST _WSAIOW(IOC_VENDOR,11)
//定义Ip数据报头结构,20个字节
typedef struct HeadIP {
unsigned char headerlen:4; //首部长度,占4位
unsigned char version:4; //版本,占4位
unsigned char servertype; //服务类型,占8位,即1个字节
unsigned short totallen; //总长度,占16位
unsigned short id; //与idoff构成标识 ,共占16位,前3位是标识,后13位是片偏移
unsigned short idoff;
unsigned char ttl; //生存时间 ,占8位
unsigned char proto; //协议,占8位
unsigned short checksum; //首部检验和,占16位
unsigned int sourceIP; //源IP地址,占32位
unsigned int destIP; //目的IP地址,占32位
}HEADIP;
5.在程序初始化函数OnInitDialog()中初始化控件等
//初始化套接字
WSADATA data;
AfxSocketInit(&data);
//<>
m_bThreadStop = TRUE;
m_bIsThreadStop = TRUE;
m_List.SetExtendedStyle(LVS_EX_FLATSB|LVS_EX_GRIDLINES|LVS_EX_TWOCLICKACTIVATE);
m_List.ModifyStyle(0,LVS_REPORT,0);
m_List.InsertColumn(0,"协议",LVCFMT_LEFT,40);
m_List.InsertColumn(1,"源IP地址",LVCFMT_LEFT,100);
m_List.InsertColumn(2,"目的IP地址",LVCFMT_LEFT,100);
m_List.InsertColumn(3,"端口",LVCFMT_LEFT,40);
m_List.InsertColumn(4,"大小",LVCFMT_LEFT,100);
m_List.InsertColumn(5,"数据",LVCFMT_LEFT,220);
我们来演示下功能实现的整个过程
如果您认可,可联系功能定制! 如果您着急,充值会员可直接联系发您资料!
|