原始套接字,即rawsocket,可以接收本机网卡上的数据帧或者数据包,对与监听网络的流量和分析是很有作用的.一共可以有3种方式创建这种socket1.socket(AF_INET,SOCK_RAW,IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)发送接收ip数据包2.socket(PF_PACKET,SOCK_RAW,htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))发送接收以太网数据帧3.socket(AF_INET,SOCK_PACKET,htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))过时了,不要用啊理解一下SOCK_RAW的原理,比如网卡收到了一个14+20+8+100+4的udp的以太网数据帧.首先,网卡对该数据帧进行硬过滤(根据网卡的模式不同会有不同的动作,如果设置了promisc混杂模式的话,则不做任何过滤直接交给下一层输入例程,否则非本机mac或者广播mac会被直接丢弃).按照上面的例子,如果成功的话,会进入ip输入例程.但是在进入ip输入例程之前,系统会检查系统中是否有通过socket(AF_PACKET,SOCK_RAW,..)创建的套接字.如果有的话并且协议相符,在这个例子中就是需要ETH_P_IP或者ETH_P_ALL类型.系统就给每个这样的socket接收缓冲区发送一个数据帧拷贝.然后进入下一步.其次,进入了ip输入例程(ip层会对该数据包进行软过滤,就是检查校验或者丢弃非本机ip或者广播ip的数据包等,具体要参考源代码),例子中就是如果成功的话会进入udp输入例程.但是在交给udp输入例程之前,系统会检查系统中是否有通过socket(AF_INET,SOCK_RAW,..)创建的套接字.如果有的话并且协议相符,在这个例子中就是需要IPPROTO_UDP类型.系统就给每个这样的socket接收缓冲区发送一个数据帧拷贝.然后进入下一步.最后,进入udp输入例程...ps:如果校验和出错的话,内核会直接丢弃该数据包的.而不会拷贝给sock_raw的套接字,因为校验和都出错了,数据肯定有问题的包括所有信息都没有意义了.进一步分析他们的能力.1.socket(AF_INET,SOCK_RAW,IPPROTO_UDP);能:该套接字可以接收协议类型为(tcpudpicmp等)发往本机的ip数据包,从上面看的就是20+8+100.不能:不能收到非发往本地ip的数据包(ip软过滤会丢弃这些不是发往本机ip的数据包).不能:不能收到从本机发送出去的数据包.发送的话需要自己组织tcpudpicmp等头部.可以setsockopt来自己包装ip头部这种套接字用来写个ping程序比较适合2.socket(PF_PACKET,SOCK_RAW,htons(x));这个套接字比较强大,创建这种套接字可以监听网卡上的所有数据帧.从上面看就是20+20+8+100.最后一个以太网crc从来都不算进来的,因为内核已经判断过了,对程序来说没有任何意义了.能:接收发往本地mac的数据帧能:接收从本机发送出去的数据帧(第3个参数需要设置为ETH_P_ALL)能:接收非发往本地mac的数据帧(网卡需要设置为promisc混杂模式)协议类型一共有四个ETH_P_IP0x800只接收发往本机mac的ip类型的数据帧ETH_P_ARP0x806只接受发往本机mac的arp类型的数据帧ETH_P_ARP0x8035只接受发往本机mac的rarp类型的数据帧ETH_P_ALL0x3接收发往本机mac的所有类型iparprarp的数据帧,接收从本机发出的所有类型的数据帧.(混杂模式打开的情况下,会接收到非发往本地mac的数据帧)3.socket(AF_INET,SOCK_PACKET,htons(ETH_P_ALL)),这个一般用于抓包程序。总结使用方法:1.只想收到发往本机某种协议的ip数据包的话用第一种就足够了2.更多的详细的内容请使用第二种.包括ETH_P_ALL参数和混杂模式都可以使它的能力不断的加强.下面的程序利用RawSocket发送TCP报文,并完全手工建立报头:intsendTcp(unsignedshortdesPort,unsignedlongdesIP){WSADATAWSAData;SOCKETsock;SOCKADDR_INaddr_in;IPHEADERipHeader;TCPHEADERtcpHeader;PSDHEADERpsdHeader;charszSendBuf[MAX_LEN]={0};BOOLflag;intrect,nTimeOver;if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0){printf(WSAStartupError!\n);returnfalse;}if((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET){printf(SocketSetupError!\n);returnfalse;}flag=true;if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&flag,sizeof(flag))==SOCKET_ERROR){printf(setsockoptIP_HDRINCLerror!\n);returnfalse;}nTimeOver=1000;if(setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&nTimeOver,sizeof(nTimeOver))==SOCKET_ERROR){printf(setsockoptSO_SNDTIMEOerror!\n);returnfalse;}addr_in.sin_family=AF_INET;addr_in.sin_port=htons(desPort);addr_in.sin_addr.S_un.S_addr=inet_addr(desIP);//填充IP报头ipHeader.h_verlen=(44|sizeof(ipHeader)/sizeof(unsignedlong));//ipHeader.tos=0;ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader));ipHeader.ident=1;ipHeader.frag_and_flags=0;ipHeader.ttl=128;ipHeader.proto=IPPROTO_TCP;ipHeader.checksum=0;ipHeader.sourceIP=inet_addr(localhost);ipHeader.destIP=desIP;//填充TCP报头tcpHeader.th_dport=htons(desPort);tcpHeader.th_sport=htons(SOURCE_PORT);//源端口号tcpHeader.th_seq=htonl(0x12345678);tcpHeader.th_ack=0;tcpHeader.th_lenres=(sizeof(tcpHeader)/44|0);tcpHeader.th_flag=2;//标志位探测,2是SYNtcpHeader.th_win=htons(512);tcpHeader.th_urp=0;tcpHeader.th_sum=0;psdHeader.saddr=ipHeader.sourceIP;psdHeader.daddr=ipHeader.destIP;psdHeader.mbz=0;psdHeader.ptcl=IPPROTO_TCP;psdHeader.tcpl=htons(sizeof(tcpHeader));//计算校验和memcpy(szSendBuf,&psdHeader,sizeof(psdHeader));memcpy(szSendBuf+sizeof(psdHeader),&tcpHeader,sizeof(tcpHeader));tcpHeader.th_sum=checksum((unsignedshort*)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));memcpy(szSendBuf,&ipHeader,sizeof(ipHeader));memcpy(szSendBuf+sizeof(ipHeader),&tcpHeader,sizeof(tcpHeader));memset(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader),0,4);ipHeader.checksum=checksum((unsignedshort*)szSendBuf,sizeof(ipHeader)+sizeof(tcpHeader));memcpy(szSendBuf,&ipHeader,sizeof(ipHeader));rect=sendto(sock,szSendBuf,sizeof(ipHeader)+sizeof(tcpHeader),0,(structsockaddr*)&addr_in,sizeof(addr_in));if(rect==SOCKET_ERROR){printf(senderror!:%d\n,WSAGetLastError());returnfalse;}elseprintf(sendok!\n);closesocket(sock);WSACleanup();returnrect;}