我刚学过socket,自学的.看了一个例子.想和还不会的同志分享一下,如果你是高手那就算了.
注: 1表示自己写的.2表示提供的-不用自己写的.
void CListenDlg::OnButton1()
{
// TODO: Add your control notification handler code here
CWinThread *pThread=NULL; CButton* pBtn=(CButton *)GetDlgItem(IDC_BUTTON1); //2
int n=pBtn->GetCheck(); //2
m_HostIp=GetIp(); //1 得到本机IP
if(1==n) //开始监听
{
if(CreateSock()!=0) //1 - 建立createsock成=0
{
AfxMessageBox("WinSock设置失败");
DestroyWindow(); //2 销毁windows
}
else
{
b_IsRun=TRUE;
pThread=AfxBeginThread(RecvIpPro,this); //2 启动线程
}
pBtn->SetWindowText("停止监听"); //2
}
else //停止监听
{
b_IsRun=FALSE;
if(pThread) //pthread=null
{
TerminateThread(pThread->m_hThread, 0); //2 该函数用来结束由hThread
//参数指定的线程,并把0设成该线程的退出码
CloseHandle(pThread->m_hThread); //2
}
if(m_RawSock)
closesocket(m_RawSock);
pBtn->SetWindowText("开始监听");
}
}
//得到本机IP
char* GetIp()
{
WORD wVersionRequested;
WSADATA wsaData;
char name[255];
char *ip;
PHOSTENT hostinfo;
wVersionRequested = MAKEWORD( 2, 0 );
if ( WSAStartup( wVersionRequested, &wsaData ) == 0 )//wsastartup成功返回0
{
if( gethostname ( name, sizeof(name)) == 0) //2 获得本机的名字
{
if((hostinfo = gethostbyname(name)) != NULL)//2 得到IP地址
{
ip = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
//2 将参数in所指的网络二进制的数字转换成网络地址,然/后将指向此网络
// 地址字符串的指针返回。 返回值. 成功则返回字符串指针,失败则返回NULL。
}
}
WSACleanup( );
}
return ip;
}
//建立原始套接字
int CListenDlg::CreateSock()
{
int err;
char name[10];
hostent *pHostent;
int port=8310; //端口号,自定义5001,8080 ……
SOCKADDR_IN sockaddr;
m_RawSock=socket(AF_INET,SOCK_RAW,IPPROTO_IP); //2 互联网,流操作,0
if(m_RawSock==INVALID_SOCKET) //若socket没有创建成
{
return WSAGetLastError(); //2 socket创建失败
}
err=gethostname(name,10); //2 获得本机的名字
if(err==SOCKET_ERROR)
{
return WSAGetLastError(); //2 取本机用户名失败
}
pHostent=gethostbyname (name); //获得你的机器的IP 地址
sockaddr.sin_family=AF_INET;
sockaddr.sin_port=htons(port);
memcpy(&sockaddr.sin_addr.s_addr,pHostent->h_addr_list[0],
pHostent->h_length); //ip 地址
err=bind(m_RawSock,(SOCKADDR *)&sockaddr,sizeof(sockaddr));//绑定(将端口,ip和socket)
if(err==SOCKET_ERROR)
{
return WSAGetLastError(); //取本机用户名,失败未绑定
}
BOOL bOptval=TRUE;
//设置套节字选项
setsockopt(m_RawSock,SOL_SOCKET,SO_REUSEADDR,(char*)&bOptval,sizeof(bOptval));//2 置套接口选项
err=setsockopt(m_RawSock,IPPROTO_IP,IP_HDRINCL,(char*)&bOptval, //IP_HDRINCL该选项使之能操作IP头
sizeof(bOptval));
if(err==SOCKET_ERROR)
{
return WSAGetLastError(); //设置套节字选项失败
}
//把网卡置于混杂模式。获取IO操作的相关信息
DWORD dwBufferLen[10] ;
DWORD dwBufferInLen = 1 ;
DWORD dwBytesReturned = 0 ;
err=WSAIoctl ( //2
m_RawSock, //一个指定的套接字
SIO_RCVALL, //设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包 ,控制操作码
&dwBufferInLen, //指向输入数据流的指针
sizeof(dwBufferInLen), //输入数据流的大小(字节数)
&dwBufferLen, //指向输出数据流的指针
sizeof(dwBufferLen), //输出数据流的大小(字节数
&dwBytesReturned, //指向输出字节流数目的实数值
NULL, //指向一个WSAOVERLAPPED结构
NULL //指向操作完成时执行的例程
);//最后两参数设置非阻塞
if(err==SOCKET_ERROR)
{
return WSAGetLastError(); //2 设置失败
}
return 0;
}
//在线程chi中不断接受IP包
UINT RecvIpPro(LPVOID lpParam)
{
int err=0;
int recvLen;
CListenDlg* pDlg=(CListenDlg*)lpParam;
char recvBuf[MAX_PACK_LEN]={0};//接受的最大的报文
while(b_IsRun)
{
recvLen=recv(pDlg->m_RawSock,recvBuf,MAX_PACK_LEN,0);//接受数据
if(err==SOCKET_ERROR)
{
if(WSAGetLastError()==WSAEWOULDBLOCK) //如果错误为阻塞那么将继续接受
continue;
break;
}
//处理已经接受到的IP包
EnterCriticalSection(&pDlg->m_ls);
pDlg->SplitIpPack(recvBuf,recvLen); //分解IP包
pDlg->ShowIpInfo(recvBuf,recvLen); //显示数据
LeaveCriticalSection(&pDlg->m_ls);
}
return 0;
}
//分解IP包
void CListenDlg::SplitIpPack(char *pData, int len)
{
IP_HEADER* pIpHead;
pIpHead=(IP_HEADER*)pData; //转为IP头结构
SOCKADDR_IN saSource,saDest; //中间变量分别为源IP地址结构和目标IP地址结构
//得到包中协议
int iProtocol;
iProtocol=pIpHead->proto;
//得到协议字符形式表示m_szProtocol
strncpy(m_szProtocol,CheckProtocol(iProtocol),MAX_PROTO_TEXT_LEN);
//得到源IP
saSource.sin_addr.s_addr=pIpHead->sourceIP;
strncpy(m_szSourceIP,inet_ntoa(saSource.sin_addr),MAX_ADDR_LEN);
//得到目标IP
saDest.sin_addr.s_addr=pIpHead->destIP;
strncpy(m_szDestIP,inet_ntoa(saDest.sin_addr),MAX_ADDR_LEN);
//得到TTL
int ttl;
ttl=pIpHead->ttl;
wsprintf(m_szTTL,"%d",ttl);
//得到头长度
int ihLen=sizeof(unsigned long)*(pIpHead->h_lenver & 0xf);
m_ihLen=ihLen;
unsigned short srcPort=0,destPort=0;
switch(iProtocol) {
case IPPROTO_TCP:
TCP_HEADER* pTcpHead;
pTcpHead=(TCP_HEADER*)(pData+ihLen);
srcPort=ntohs(pTcpHead->th_sport);
destPort=ntohs(pTcpHead->th_dport);
wsprintf(m_szSourcePort,"%d",srcPort);
wsprintf(m_szDestPort,"%d",destPort);
break;
}
}
//将协议int转为字符串
char* CListenDlg::CheckProtocol(int iProtocol)
{
for(int i=0; i<MAX_PROTO_NUM; i++)
{
if(ProtoMap
.ProtoNum==iProtocol)
{
return ProtoMap.ProtoText;
}
}
return "";
}