// 注意:原始套接字只在系统管理员权限下起作用,其它情况下socket创建失败,所以开发时首先以管理员权限启动VS
SOCKET nAnniSock = socket(AF_INET, SOCK_RAW, IPPROTO_IP); // 指定为原始套接字(IP层抓取)
// 设置IP_HDRINCL选项,以便自己构造(解析)IP头部
BOOL bRaw = TRUE;
setsockopt(nAnniSock, IPPROTO_IP, IP_HDRINCL, (const char*)&bRaw, sizeof(bRaw));
// socket本地信息
sockaddr_in stAnniSock;
stAnniSock.sin_family = AF_INET;
stAnniSock.sin_port = htons(0); // 设置为任意端口
// 不设置IP地址会导致后面bind失败,设置为INADDR_ANY的话后面的WSAIoctl会产生参数错误而失败
// 所以只能设置为指定网卡的IP地址(据说设置无线网卡的IP地址也会失败)
stAnniSock.sin_addr.S_un.S_addr = htonl(0xc0a8010a); //htonl(INADDR_ANY);
// 绑定套接字,如果不绑定则后面的recvfrom会立即返回空值
bind(nAnniSock, (sockaddr*)&stAnniSock, sizeof(stAnniSock));
// 设置套接字接收所有数据包(混杂模式)(必须在bind之后调用),#define SIO_RCVALL (IOC_IN|IOC_VENDOR|1)
DWORD uiOptval = 1;
char charRecv[10];
DWORD dwBytesRet = 0;
WSAIoctl(nAnniSock, (IOC_IN | IOC_VENDOR | 1), &uiOptval, sizeof(uiOptval), charRecv, sizeof(charRecv), &dwBytesRet, NULL, NULL);
// socket发送源信息
sockaddr_in stSockCamera;
int nLen = sizeof(sockaddr_in);
// 超时设定
timeval timeoutonce;
timeoutonce.tv_sec = 1;
timeoutonce.tv_usec = 0;
// 循环接收
while(TRUE)
{
// 调用select前需要从新设置,否则可能只有第一次select到数据包后,以后select就不管用了
fd_set udpSetAnni;
FD_ZERO(&udpSetAnni);
FD_SET(nAnniSock, &udpSetAnni);
// 调用select函数检查是否有数据包到达,否则直接用recvfrom会导致阻塞
if (select(NULL, &udpSetAnni, NULL, NULL, &timeoutonce))
{
// 接收缓冲区}
}