概述
以下的结构体在实际工程中经过了测试是可以的,自定义函数也经过了测试,到目前为止没有出现问题。
// ---------------------------------------------
// TCP/IP基础结构体和通用函数
// ---------------------------------------------
#ifndef TCPIPCOMMON_H
#define TCPIPCOMMON_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <winsock2.h>
typedef unsigned char u_char;
typedef unsigned short int u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
// Ethernet
#define ETHERNET_HEAD_LENGTH 14
#define ARP_TYPE 0x0806 //以太头类型:ARP类型
#define IP_TYPE 0x0800 //以太头类型:IPV4类型
#define IPV6_TYPE 0x86dd //以太头类型,IPV6类型
// ARP Body 28bytes
// ARP Packet(42bytes) = Ethernet(14bytes) + ARP Body(28bytes)
#define ARP_BODY_LENGTH 28
#define ARP_PACKET_LENGTH 42
#define MPLS_TYPE 0x8847
#define IPX_TYPE 0x8137
#define IS_IS_TYPE 0x8000
#define LACP_TYPE 0x8809
#define _802_1x_TYPE 0x888E
#define ARP_HARDWARE 0x0001 //ARP包中:以太网
#define ARP_REQUEST 0x0001
#define ARP_REPLY 0x0002
// IP Header 20bytes
#define IP_HEAD_LENGTH 20
#define IP_VERSION_4 0x04 //IPV4头,版本4
#define IP_VERSION_6 0x06 //IPV4头,版本6
#define IP_TCP_TYPE 0x06 //IPV4头中的协议类型:TCP
#define IP_UDP_TYPE 0x11 //IPV4头中的协议类型:UDP
#define IP_ICMP_TYPE 0x01 //IPV4头中的协议类型:ICMP
// TCP Header 20bytes 因为还没用到,所以没写
#define TCP_HEAD_LENGTH 20
//***********************************************************************************
//常用网络协议自定义结构体
//***********************************************************************************
// Ethernet addresses are 6 bytes
#define ETHER_ADDR_LEN 6
typedef struct _EthernetHeader
{
u_char DestMAC[ETHER_ADDR_LEN]; //目的MAC地址 6字节
u_char SourMAC[ETHER_ADDR_LEN]; //源MAC地址 6字节
u_short EthType; //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp 2字节
}EthernetHeader;
// 4 bytes IP address
typedef struct _IPAddress{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}IPAddress;
// IPv4 header 20bytes
// IPv6 header 40bytes,这里只是IPv4的协议头
typedef struct _IpHeader{
u_char VerIhl; // 版本4 + 首部长度4Version (4 bits) + Internet header length (4 bits)
u_char Tos; // 服务类型Type of service
u_short Tlen; // 总长度Total length,包括IP20字节的头
u_short Identification; // 标识Identification
u_short FlagsFo; // 标志(4 bits)+片偏移(12 bits)Flags (3 bits) + Fragment offset (13 bits)
u_char Ttl; // 生存时间Time to live
u_char Proto; // 协议类型:TCP(6)、UDP(17)、ICMP(1)
u_short Crc; // 首部校验和Header checksum
u_char SourceIpAdd[4]; // 源地址Source address
u_char DestIpAdd[4]; // 目标地址Destination address
}IPHeader;
// TCP数据包的头部 20 bytes
typedef struct _TCPPacketHeader {
u_short SrcPort; //源端口
u_short DestPort; //目的端口
u_int Seq; //序列号
u_int Ack; //确认序列号
u_short Lenres; //数据偏移4+保留区6+URG+ACK+PSH+RST+SYN+FIN
u_short Win; //窗口
u_short Sum; //校验和
u_short Urp; //紧急指针
}TCPPacketHeader;
// UDP header
typedef struct _UDPHeader{
u_short SrcPort; // Source port
u_short DestPort; // Destination port
u_short Len; // Datagram length
u_short Crc; // Checksum
}UDPHeader;
// 28 bytes ARP request/reply
typedef struct _ArpHeader {
u_short HardwareType; //硬件类型,2字节,定义运行ARP的网络的类型,以太网是类型1
u_short ProtocolType; //协议类型,2字节,定义上层协议类型,对于IPV4协议,该字段值为0800
u_char HardwareAddLen; //硬件地址长度,8位字段,定义对应物理地址长度,以太网中这个值为6
u_char ProtocolAddLen; //协议地址长度,8位字段,定义以字节为单位的逻辑地址长度,对IPV4协议这个值为4
u_short OperationField; //操作字段,数据包类型,ARP请求(值为1),或者ARP应答(值为2)
u_char SourceMacAdd[6]; //源(发送端)mac地址,可变长度字段,对以太网这个字段是6字节长
u_char SourceIpAdd[4]; //源(发送短)ip地址,发送端协议地址,可变长度字段,对IP协议,这个字段是4字节长
u_char DestMacAdd[6]; //目的(接收端)mac地址
u_char DestIpAdd[4]; //目的(接收端)ip地址,注意不能为u_int型,结构体对其
}ArpHeader;
//arp packet = 14 bytes ethernet header + 28 bytes request/reply
typedef struct _ArpPacket {
EthernetHeader ed;
ArpHeader ah;
}ArpPacket;
// host infomation
typedef struct _HostInfo{
u_char mac[6];
char ip[16];
char netmask[16];
char getwayIp[16];
u_char gatewayMac[6];
}HostInfo;
//***********************************************************************************
//网络常用转换函数声明和说明
//***********************************************************************************
//my_htonl函数,本机字节序转网络字节序(32位字节序)
//my_ntohl函数,网络字节序转本机字节序(32位字节序)
//my_htons函数,本机字节序转网络字节序(16位字节序)
//my_ntohs函数,网络字节序转本机字节序(16位字节序)
//my_iptos函数,将字节序ip地址转为点分十进制的字符串地址
//iptos 函数,将字节序ip地址转为点分十进制的字符串地址,并获取
//my_inet_addr
// 本机大端返回1,小端返回0
inline int checkCPUendian();
// 模拟htonl函数,本机字节序转网络字节序
inline u_long my_htonl(u_long h);
// 模拟ntohl函数,网络字节序转本机字节序
inline u_long my_ntohl(u_long n);
// 模拟htons函数,本机字节序转网络字节序
inline u_short my_htons(u_short h);
// 模拟ntohs函数,网络字节序转本机字节序
inline u_short my_ntohs(u_short n);
// 数字类型的IP地址转换成点分十进制字符串类型的
inline char *iptos(u_long in,char * ipStr);
// 将字节序ip地址转为点分十进制的字符串地址,并获取
inline char *my_iptos(u_long in);
// 将点分十进制的字符串地址转网络字节整形
inline u_int my_inet_addr(const char *ptr);
//***********************************************************************************
//网络常用转换函数和宏集
//***********************************************************************************
// 短整型大小端互换
#define BigLittleSwap16(A) ((((u_short)(A) & 0xff00) >> 8) |
(((u_short)(A) & 0x00ff) << 8))
// 长整型大小端互换
#define BigLittleSwap32(A) ((((u_long)(A) & 0xff000000) >> 24) |
(((u_long)(A) & 0x00ff0000) >> 8) |
(((u_long)(A) & 0x0000ff00) << 8) |
(((u_long)(A) & 0x000000ff) << 24))
// 本机大端返回1,小端返回0
int checkCPUendian()
{
union{
u_long i;
u_char s[4];
}c;
c.i = 0x12345678;
return (0x12 == c.s[0]);
}
// 模拟htonl函数,本机字节序转网络字节序
u_long my_htonl(u_long h)
{
// 若本机为大端,与网络字节序同,直接返回
// 若本机为小端,转换成大端再返回
return checkCPUendian() ? h : BigLittleSwap32(h);
}
// 模拟ntohl函数,网络字节序转本机字节序
u_long my_ntohl(u_long n)
{
// 若本机为大端,与网络字节序同,直接返回
// 若本机为小端,网络数据转换成小端再返回
return checkCPUendian() ? n : BigLittleSwap32(n);
}
// 模拟htons函数,本机字节序转网络字节序
u_short my_htons(u_short h)
{
// 若本机为大端,与网络字节序同,直接返回
// 若本机为小端,转换成大端再返回
return checkCPUendian() ? h : BigLittleSwap16(h);
}
// 模拟ntohs函数,网络字节序转本机字节序
u_short my_ntohs(u_short n)
{
// 若本机为大端,与网络字节序同,直接返回
// 若本机为小端,网络数据转换成小端再返回
return checkCPUendian() ? n : BigLittleSwap16(n);
}
// 数字类型的IP地址转换成点分十进制字符串类型的
char *iptos(u_long in,char * ipStr)
{
u_char *p;
p = (u_char *)∈
sprintf(ipStr, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return ipStr;
}
#define IPTOSBUFFERS 12
char *my_iptos(u_long in)
{
static char output[IPTOSBUFFERS][3*4+3+1];
static short which;
u_char *p;
p = (u_char *)∈
which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return output[which];
}
u_int my_inet_addr(const char *ptr)
{
int a[4],i=0;
char str[255] = {0};
u_long num;
strcpy(str,ptr);
char *p1=str,*p2,*p3;
while(*p1!='