如何通过原始套接字发送UDP数据?

如何通过原始套接字发送UDP数据?

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>

#pragma pack (push ,1)
typedef struct _iphdr //定义IP首部
{
unsigned char h_lenver; //4位首部长度+4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //16位总长度(字节)
unsigned short ident; //16位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校验和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IP_HEADER;

typedef struct _udphdr// UDP 数据报
{
unsigned short souceport;//源端口
unsigned short destport;//目的端口
unsigned short length;//数据长度
unsigned short checksum;//带数据!检查和
}UDP_HEADER;
#pragma pack (pop , 1)


//换机
/*
typedef struct _HuanJi
{
char HuanJi;
}HUANJI;*/


//Client To Server 换机数据
char Huanji_Buf1[] = {0x08, 0x00, 0x00, 0x00, 0xCE, 0x8A, 0x31, 0x75};
char Huanji_Buf2[] = {0x08, 0x00, 0x00, 0x00, 0x23, 0x00, 0x01, 0x00};

//判断连接
char strFlags_Buf1[] = {0x08, 0x00, 0x00, 0x00, 0x24, 0x01, 0x01, 0x00}; //Client To Server
char strFlags_Buf2[] = {0x08, 0x00, 0x00, 0x00, 0x57, 0x13, 0xA8, 0xEC}; //Server To Client


//函数名: SendUdpData
//函数功能: 发送原始套接字的UDP数据包
//参数说明:
// Socket: 发送此数据的套接字
// buf: 发送的数据缓冲区
// nLen: 发送的数据长度
// ServIp: 接收此数据的服务器IP
// ServPort: 接收此数据的服务器端口
// VirtualIp: 发送此数据的机器IP
// VirtualPort:发送此数据的机器端口
// nTimeOver: 超时时间,单位毫秒
//返回值, 成功为True,失败为False
BOOL SendUdpData(char *buf, int nLen, char *ServIp, int ServPort, char *VirtualIP, int VirtualPort, int nTimeOver)
{
IP_HEADER ipHeader;
UDP_HEADER udpHeader;
SOCKET Socket;
struct sockaddr_in addr_in;
char szSendBuf[128] = {0};
char ErrorMsg[128] = {0};
char *strTemp;
unsigned short itotalsize, iudpsize, iIPsize;
BOOL blnFlag = TRUE;
int rect;

try
{
Socket = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if(setsockopt(Socket, IPPROTO_IP, IP_HDRINCL, (char *)&blnFlag, sizeof(blnFlag)) == SOCKET_ERROR)
{
return FALSE;
}
if(setsockopt(Socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver)) == SOCKET_ERROR)
{
return FALSE;
}

addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(ServPort);
addr_in.sin_addr.S_un.S_addr = inet_addr(ServIp);

itotalsize = sizeof(ipHeader) + sizeof(udpHeader) + nLen;
iIPsize = sizeof(ipHeader) / sizeof(unsigned long);
//填充IP首部
ipHeader.h_lenver = (4<<4 | iIPsize);
ipHeader.tos = 0;
ipHeader.total_len = htons(itotalsize);
ipHeader.ident = 0;
ipHeader.frag_and_flags = 0;
ipHeader.ttl = 128;
ipHeader.proto = IPPROTO_UDP;
ipHeader.checksum = 0;
ipHeader.sourceIP = inet_addr(VirtualIP);
ipHeader.destIP = inet_addr(ServIp);

iudpsize = sizeof(udpHeader) + nLen;
//填充UDP首部
udpHeader.souceport = htons(VirtualPort);
udpHeader.destport = htons(ServPort);
udpHeader.length = htons(iudpsize);//数据长度
udpHeader.checksum = 0;

//合成数据
ZeroMemory(szSendBuf, 128);
strTemp = szSendBuf;
memcpy(strTemp, &ipHeader, sizeof(ipHeader));
strTemp += sizeof(ipHeader);
memcpy(strTemp, &udpHeader, sizeof(udpHeader));
strTemp += sizeof(udpHeader);
memcpy(strTemp, buf, nLen);

//发送数据
rect = sendto(Socket, szSendBuf, itotalsize, 0, (struct sockaddr*)&addr_in, sizeof(addr_in));
if(rect == SOCKET_ERROR)
{
sprintf(ErrorMsg, "%s: %d", "错误代码:", WSAGetLastError());
MessageBox(NULL, ErrorMsg, "发送失败", MB_OK);
return FALSE;
}
}
catch(...)
{
sprintf(ErrorMsg, "%s: %d", "错误代码:", WSAGetLastError());
MessageBox(NULL, ErrorMsg, "发送失败", MB_OK);
return FALSE;
}
if(Socket != NULL)
{
closesocket(Socket);
}

return TRUE;
}
//===========================================================================