我想通过原始套接字发送数据包,但是到最后sendto的时候总是会出错,用函数WSAGetLa
stError()得到的错误说明是10004,我查了MSDN后得到10004错误代表的是One or more
 arguments were reported invalid by the provider.但是我还是不明白错在哪个地方,
请高手指点一下,谢谢。
使用的测试代码是从网上下载的,经过一定的修改后如下:
//调试时再要加上ws2_32.lib这个库
#include <stdio.h> 
#include <winsock2.h> 
#include <ws2tcpip.h> 
#define SOURCE_PORT 7234 
#define MAX_RECEIVEBYTE 255 
//前面部分为数据包的IP首部和TCP首部的定义
typedef struct ip_hdr //定义IP首部 

unsigned char h_verlen; //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地址 
}IPHEADER; typedef struct tsd_hdr //定义TCP伪首部 

unsigned long saddr; //源地址 
unsigned long daddr; //目的地址 
char mbz; 
char ptcl; //协议类型 
unsigned short tcpl; //TCP长度 
}PSDHEADER; typedef struct tcp_hdr //定义TCP首部 

USHORT th_sport; //16位源端口 
USHORT th_dport; //16位目的端口 
unsigned int th_seq; //32位序列号 
unsigned int th_ack; //32位确认号 
unsigned char th_lenres; //4位首部长度/6位保留字 
unsigned char th_flag; //6位标志位 
USHORT th_win; //16位窗口大小 
USHORT th_sum; //16位校验和 
USHORT th_urp; //16位紧急数据偏移量 
}TCPHEADER; //CheckSum:计算校验和的子函数 
USHORT checksum(USHORT *buffer, int size) 

unsigned long cksum=0; 
while(size >1) 

cksum+=*buffer++; 
size -=sizeof(USHORT); 

if(size ) 

cksum += *(UCHAR*)buffer; 


cksum = (cksum >> 16) + (cksum & 0xffff); 
cksum += (cksum >>16); 
return (USHORT)(~cksum); 
} int main() 

WSADATA WSAData; 
SOCKET sock; 
SOCKADDR_IN addr_in; 
IPHEADER ipHeader; 
TCPHEADER tcpHeader; 
PSDHEADER psdHeader; 

char szSendBuf[100]={0}; //发送缓冲区
BOOL flag; 
int rect,nTimeOver; 

if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0) 

printf("WSAStartup Error!\n"); 
return false; 


if ((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))
==INVALID_SOCKET) 

printf("Socket Setup Error!\n"); 
return false; 
}  flag=true; 
if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKE
T_ERROR) 

printf("setsockopt IP_HDRINCL error!\n"); 
return false; 


nTimeOver=1000; 
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTime
Over))==SOCKET_ERROR) 

printf("setsockopt SO_SNDTIMEO error!\n"); 
return false; 

addr_in.sin_family=AF_INET; 
addr_in.sin_port=htons(10000); 
addr_in.sin_addr.S_un.S_addr=inet_addr("202.114.0.242"); 

//填充IP首部 
ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long)); 
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("192.168.0.200"); //此处设定本地IP地址
ipHeader.destIP=inet_addr("202.114.0.242"); //设定访问的IP地址

//填充TCP首部 
tcpHeader.th_dport=htons(10000); 
tcpHeader.th_sport=htons(SOURCE_PORT); //源端口号 
tcpHeader.th_seq=htonl(0x12345678); 
tcpHeader.th_ack=0; 
tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0); 
tcpHeader.th_flag=2; //修改这里来实现不同的标志位探测,2是SYN,1是FIN,16是AC
K探测 等等 
tcpHeader.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((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHea
der)); 

memcpy(szSendBuf, &ipHeader, sizeof(ipHeader)); 
memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader)); 
memset(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), 0, 4); 
ipHeader.checksum=checksum((USHORT *)szSendBuf, sizeof(ipHeader)+sizeof(tcpHe
ader)); 

memcpy(szSendBuf, &ipHeader, sizeof(ipHeader)); 

rect=sendto(sock, szSendBuf, 100, 0, (struct sockaddr*)&addr_in, sizeof(addr_
in)); //问题就出在这一步,发送后总是返回错误,请高手指点
if (rect==SOCKET_ERROR) 

printf("send error!:%d\n",WSAGetLastError()); 
return false; 

else 
printf("send ok!\n"); 

closesocket(sock); 
WSACleanup(); 

return 0; 

解决方案 »

  1.   

    可能是你用阻塞模式的api向非阻塞模式的socket发送了数据.将SOCKET指定非阻塞模式来发送数据.unsigned long ul = 1;
    int           nRet;
    nRet = ioctlsocket(socket, FIONBIO, (unsigned long *) &ul);
      

  2.   

    加上这几行代码还是没能解决那个发送错误,ioctlsocket运行后返回值是0,加上后的这几行代码也没有错,错的地方还是在发送函数上,有那位高手还看的出问题出在哪里吗?
      

  3.   

    朋友,你好~
    你的代码我试了,我的机子是vc6.0,2003,跑了很我次,都是send ok对了,请问你知道那里有tcp/ip的源代码下载吗?要BSD的
      

  4.   

    我也用2003试了一下,也是好的,就是在XP下不行,也不清楚原因,不知是不是XP下用不成原始套接字。tcp/ip的源代码我也不知道在哪里下,不好意思啊。
      

  5.   

    xp2不能用rawsocket发数据的
    另外:
    你的结构体没有用字节对齐方式也能正常使用吗?
    缺省是哪怕一个char也占用一个字的。