学习Socket ,写简单网络监视程序心得!

主要思路是通过原始套接字来将通过本机网卡的IP层数据包捕获!

 

 #ifndef _PROTO_H #define _PROTO_H 0x2009 #include <winsock2.h> #include <ws2tcpip.h> #include <mstcpip.h> #pragma comment(lib, "Ws2_32.lib") #define MAX_PACK_LEN 65535 // The max IP packet to receive. #define MAX_ADDR_LEN 16 // The dotted addres's length. #define MAX_PROTO_TEXT_LEN 16 // The length of sub protocol name(like "TCP"). #define MAX_PROTO_NUM 12 // The count of sub protocols. #define MAX_HOSTNAME_LAN 256 // The max length of the host name. /* // The IP packet is like this. Took from RFC791. 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| IHL |Type of Service| Total Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identification |Flags| Fragment Offset | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time to Live | Protocol | Header Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ typedef struct _tagIPHEADER // 20 Bytes { unsigned char h_lenver; unsigned char tos; unsigned short total_len; unsigned short ident; unsigned short frag_and_flags; unsigned char ttl; unsigned char proto; unsigned short checksum; unsigned int sourceIP; unsigned int destIP; }IP_HEADER, *PIP_HEADER; /* // The TCP packet is like this. Took from RFC793. 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data | |U|A|P|R|S|F| | | Offset| Reserved |R|C|S|S|Y|I| Window | | | |G|K|H|T|N|N| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | data | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ typedef struct _tagTCPHEADER // 20 Bytes { unsigned short th_sport; unsigned short th_dport; unsigned int th_seq; unsigned int th_ack; unsigned char th_lenres; unsigned char th_flag; unsigned short th_win; unsigned short th_sum; unsigned short th_urp; }TCP_HEADER; /* // The TCP's pseudo header is like this. Took from RFC793. +--------+--------+--------+--------+ | Source Address | +--------+--------+--------+--------+ | Destination Address | +--------+--------+--------+--------+ | zero | PTCL | TCP Length | +--------+--------+--------+--------+ */ typedef struct _tagPSD_HEADER // 16 Bytes { unsigned long saddr; unsigned long daddr; char mbz; char ptcl; unsigned short tcpl; }PSD_HEADER; /* // The UDP packet is lick this. Took from RFC768. 0 7 8 15 16 23 24 31 +--------+--------+--------+--------+ | Source | Destination | | Port | Port | +--------+--------+--------+--------+ | | | | Length | Checksum | +--------+--------+--------+--------+ | | data octets ... +---------------- ... */ typedef struct _tagUDPHEADER // 8 Bytes { unsigned short uh_sport; unsigned short uh_dport; unsigned short uh_len; unsigned short uh_sum; } UDP_HEADER; typedef struct _tagICMPHEADER { unsigned char i_type; unsigned char i_code; unsigned short i_cksum; unsigned short i_id; unsigned short i_seq; unsigned long timestamp; }ICMP_HEADER; // //typedef struct _tagPROTOMAP //{ // int ProtoNum; // char ProtoText[MAX_PROTO_TEXT_LEN]; //}PROTOMAP; // // //static PROTOMAP ProtoMap[MAX_PROTO_NUM]= //{ // { 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 , "NP " }, // { IPPROTO_RAW , "RAW " }, // { IPPROTO_MAX , "MAX " }, // { NULL , "" } //}; #endif #pragma once #include "Proto.h" typedef void (*PCALLBACKFUNC)(void* pOwner , char *pData , int nLen); //定义回调函数 class CNetWatch { public: CNetWatch(void); void InitForWatch(CWnd *pWnd ,PCALLBACKFUNC pfnCallback); void StartWatch(); void StopWatch(); void CreateWatchThread(); char* GetLocalIP(); static unsigned _stdcall RecvThread(void* pParam); public: ~CNetWatch(void); private: CWnd *m_pOwner; PCALLBACKFUNC m_pfnCallback; BOOL m_bStopWatchThread; HANDLE m_hWatchThread; SOCKET m_Socket; }; .h文件! #include "StdAfx.h" #include "NetWatch.h" #include <process.h> #define DEFAULT_PORT 5678 #define MAX_BUFFER 65532 #define MAX_HOST_NAME 100 /////////////////////////////////////////////////////// //构造函数初始化加载套接字库 CNetWatch::CNetWatch(void) { WSADATA wsaData; if(0 != WSAStartup(MAKEWORD(2,2) ,&wsaData)) { OutputDebugStringW(_T("Startup Error /r/n")); } if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { OutputDebugStringW(_T("Version Error /r/n")); } } ////////////////////////////////////////////////////////// //关闭套接字,并卸载库.停止监听 CNetWatch::~CNetWatch(void) { if(m_Socket != SOCKET_ERROR) closesocket(m_Socket); StopWatch(); WSACleanup(); } ///////////////////////////////////////////////////////////////////// //初始化监视线程数据 void CNetWatch::InitForWatch(CWnd *pWnd , PCALLBACKFUNC pfnCallback) { ASSERT(pWnd != NULL); ASSERT(pfnCallback != NULL); m_pOwner = pWnd; m_pfnCallback = pfnCallback; } ///////////////////////////////////////////////////////////////////// //开始监听 void CNetWatch::StartWatch() { m_Socket = socket(AF_INET , SOCK_RAW , IPPROTO_IP); if(m_Socket == SOCKET_ERROR) { OutputDebugStringW(_T("创建套接字失败")); } int nRet = 0; SOCKADDR_IN addrLocal; addrLocal.sin_family = AF_INET; addrLocal.sin_addr.S_un.S_addr = inet_addr(GetLocalIP()); addrLocal.sin_port = DEFAULT_PORT; nRet = bind(m_Socket ,(SOCKADDR*)&addrLocal , sizeof(SOCKADDR)); if(nRet == SOCKET_ERROR) { OutputDebugStringW(_T("绑定出错/r/n")); } BOOL bReuse = TRUE; nRet = setsockopt(m_Socket , SOL_SOCKET ,SO_REUSEADDR , (char*)&bReuse , sizeof(int)); if(nRet == SOCKET_ERROR) { OutputDebugStringW(_T("设置套接字选项出错/r/n")); } BOOL bData = TRUE; nRet = setsockopt(m_Socket , IPPROTO_IP , IP_HDRINCL , (char*)&bData , sizeof(int)); if(nRet == SOCKET_ERROR) { OutputDebugStringW(_T("设置套接字IP选项出错/r/n")); } DWORD dwBufferLen[10]; DWORD dwBufferInLen = 1; DWORD dwBytesReturned = 0; nRet = WSAIoctl(m_Socket , SIO_RCVALL ,&dwBufferInLen ,sizeof(dwBufferInLen) , dwBufferLen ,sizeof(dwBufferLen),&dwBytesReturned ,NULL,NULL); if(nRet == SOCKET_ERROR) { OutputDebugStringW(_T("设置IO模式失败/r/n")); } m_bStopWatchThread = FALSE; CreateWatchThread(); } ///////////////////////////////////////////////////////// //接受数据线程 unsigned _stdcall CNetWatch::RecvThread(void *pParam) { CNetWatch* pWatch = (CNetWatch*)pParam; char szRecvBuf[MAX_BUFFER] ={0}; int nRead =0 ; while(1) { if(pWatch->m_bStopWatchThread) break; nRead = recv(pWatch->m_Socket , szRecvBuf ,sizeof(szRecvBuf) , 0); if(nRead == SOCKET_ERROR) { if(WSAGetLastError()==WSAEWOULDBLOCK) { continue; } OutputDebugStringW(_T("接收数据失败/r/n")); break; } else { if(pWatch->m_pOwner != NULL) { pWatch->m_pfnCallback(pWatch->m_pOwner , szRecvBuf , sizeof(szRecvBuf)); } } } return 0; } ///////////////////////////////////////////////////////////////////// //创建监视线程 void CNetWatch::CreateWatchThread() { m_hWatchThread = (HANDLE)_beginthreadex(NULL , 0 , CNetWatch::RecvThread , this , 0 , NULL); if(m_hWatchThread == NULL) { OutputDebugStringW(_T("创建接受线程失败/r/n")); return; } return; } ////////////////////////////////////////////////////////////////// //获取本地IP地址 char* CNetWatch::GetLocalIP() { char szHostName[MAX_HOST_NAME] = {0}; int nRet = 0 ; nRet = gethostname(szHostName ,sizeof(szHostName)); if(nRet == SOCKET_ERROR) { OutputDebugStringW(_T("获取主机名失败/r/n")); return NULL; } hostent* pHostInfo = NULL; pHostInfo = gethostbyname(szHostName); return inet_ntoa(*(in_addr *)(*pHostInfo->h_addr_list)); } ////////////////////////////////////////////////////////////////// //停止监视 void CNetWatch::StopWatch() { m_bStopWatchThread = TRUE; if(m_hWatchThread != NULL) { TerminateThread(m_hWatchThread , 0); return ; } } /////////////

中的来说,不是很麻烦,关键是设置套接字模式这块可能有点麻烦!!!

还有就是设计这个类的时候回调函数的运用!!!

你可能感兴趣的:(网络,tcp,socket,struct,header,null)