sendto 可以发送 TCP数据报吗?

1、sendto函数,相信网上一查就一堆的资料。sendto似乎是为UDP而生的。因为这个sendto函数的参数,就要求了这个连接不需要提前建立。sendto函数不关心数据发送者的协议地址,只要知道了对方的地址就行。也就造就了sendto发送之后,你不知道这个数据会不会到达对方,只知道,从本机发送了。

2、那么TCP数据报文可以使用sendto发送吗?比如,我只想发送一个TCP报文给一个地址,进行一些探测。按照理论来说是应该可以的。sendto的参数,第一个是套接字,第二个是发送内容,第三个是发送内容的大小,第四个是标志,第五个是对方的地址结构,最后一个是地址结构大小。于是呼,我们可以构造TCP的内容发送出去吧。网上我也找了很多例子来求证。但是遗憾的是,统统失败了。

下面是一个网上的例子:

    #include <stdio.h>    
    #include <winsock2.h>    
    #include <ws2tcpip.h>    
    #include <time.h>   
    #include <windows.h>   
    #include <string.h>   
    #include <stdlib.h>   
    #include <iostream.h>   
    #pragma comment(lib,"ws2_32.lib")   
       
    #define IPVER   4           //IP协议预定   
    #define MAX_BUFF_LEN 65500  //发送缓冲区最大值   
       
    typedef struct ip_hdr    //定义IP首部    
    {    
    UCHAR h_verlen;            //4位首部长度,4位IP版本号    
    UCHAR tos;                //8位服务类型TOS    
    USHORT total_len;        //16位总长度(字节)    
    USHORT ident;            //16位标识    
    USHORT frag_and_flags;    //3位标志位    
    UCHAR ttl;                //8位生存时间 TTL    
    UCHAR proto;            //8位协议 (TCP, UDP 或其他)    
    USHORT checksum;        //16位IP首部校验和    
    ULONG sourceIP;            //32位源IP地址    
    ULONG destIP;            //32位目的IP地址    
    }IP_HEADER;    
       
    typedef struct tsd_hdr //定义TCP伪首部    
    {    
    ULONG saddr;    //源地址   
    ULONG daddr;    //目的地址    
    UCHAR mbz;        //没用   
    UCHAR ptcl;        //协议类型    
    USHORT tcpl;    //TCP长度    
    }PSD_HEADER;    
       
    typedef struct tcp_hdr //定义TCP首部    
    {    
    USHORT th_sport;            //16位源端口    
    USHORT th_dport;            //16位目的端口    
    ULONG th_seq;                //32位序列号    
    ULONG th_ack;                //32位确认号    
    UCHAR th_lenres;            //4位首部长度/6位保留字    
    UCHAR th_flag;                //6位标志位    
    USHORT th_win;                //16位窗口大小    
    USHORT th_sum;                //16位校验和    
    USHORT th_urp;                //16位紧急数据偏移量    
    }TCP_HEADER;    
       
    //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(int argc, char* argv[])    
    {    
        WSADATA WSAData;    
        SOCKET sock;    
           
        IP_HEADER ipHeader;    
        TCP_HEADER tcpHeader;    
        PSD_HEADER psdHeader;    
       
        char Sendto_Buff[MAX_BUFF_LEN];  //发送缓冲区   
        unsigned short check_Buff[MAX_BUFF_LEN]; //检验和缓冲区   
        const char tcp_send_data[]={"This is my homework of networt,I am happy!"};   
       
        BOOL flag;    
        int rect,nTimeOver;    
       
        if (argc!= 5)    
        {   
            printf("Useage: SendTcp soruce_ip source_port dest_ip dest_port \n");    
            return false;    
        }    
       
        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))==SOCKET_ERROR)    
        {    
            printf("setsockopt IP_HDRINCL error!\n");    
            return false;    
        }    
        nTimeOver=1000;    
        if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR)    
        {    
            printf("setsockopt SO_SNDTIMEO error!\n");    
            return false;    
        }    
       
        //填充IP首部    
        ipHeader.h_verlen=(IPVER<<4 | sizeof(ipHeader)/sizeof(unsigned long));    
        ipHeader.tos=(UCHAR)0;    
        ipHeader.total_len=htons((unsigned short)sizeof(ipHeader)+sizeof(tcpHeader)+sizeof(tcp_send_data));    
        ipHeader.ident=0;       //16位标识   
        ipHeader.frag_and_flags=0; //3位标志位   
        ipHeader.ttl=128; //8位生存时间    
        ipHeader.proto=IPPROTO_TCP; //协议类型   
        ipHeader.checksum=0; //检验和暂时为0   
        ipHeader.sourceIP=inet_addr(argv[1]);  //32位源IP地址   
        ipHeader.destIP=inet_addr(argv[3]);    //32位目的IP地址   
       
        //计算IP头部检验和   
        memset(check_Buff,0,MAX_BUFF_LEN);   
        memcpy(check_Buff,&ipHeader,sizeof(IP_HEADER));   
        ipHeader.checksum=checksum((USHORT*)check_Buff,sizeof(IP_HEADER));   
       
        //构造TCP伪首部   
        psdHeader.saddr=ipHeader.sourceIP;   
        psdHeader.daddr=ipHeader.destIP;   
        psdHeader.mbz=0;   
        psdHeader.ptcl=ipHeader.proto;   
        psdHeader.tcpl=htons(sizeof(TCP_HEADER)+sizeof(tcp_send_data));   
       
        //填充TCP首部    
        tcpHeader.th_dport=htons(atoi(argv[4])); //16位目的端口号   
        tcpHeader.th_sport=htons(atoi(argv[2])); //16位源端口号    
        tcpHeader.th_seq=0;                         //SYN序列号   
        tcpHeader.th_ack=0;                         //ACK序列号置为0   
        //TCP长度和保留位   
        tcpHeader.th_lenres=(sizeof(tcpHeader)/sizeof(unsigned long)<<4|0);    
        tcpHeader.th_flag=2; //修改这里来实现不同的标志位探测,2是SYN,1是FIN,16是ACK探测 等等    
        tcpHeader.th_win=htons((unsigned short)16384);     //窗口大小   
        tcpHeader.th_urp=0;                                   //偏移大小       
        tcpHeader.th_sum=0;                                   //检验和暂时填为0   
           
        //计算TCP校验和    
        memset(check_Buff,0,MAX_BUFF_LEN);   
        memcpy(check_Buff,&psdHeader,sizeof(psdHeader));    
        memcpy(check_Buff+sizeof(psdHeader),&tcpHeader,sizeof(tcpHeader));    
        memcpy(check_Buff+sizeof(PSD_HEADER)+sizeof(TCP_HEADER),tcp_send_data,sizeof(tcp_send_data));   
        tcpHeader.th_sum=checksum((USHORT*)check_Buff,sizeof(PSD_HEADER)+sizeof(TCP_HEADER)+sizeof(tcp_send_data));    
       
        //填充发送缓冲区   
        memset(Sendto_Buff,0,MAX_BUFF_LEN);   
        memcpy(Sendto_Buff,&ipHeader,sizeof(IP_HEADER));   
        memcpy(Sendto_Buff+sizeof(IP_HEADER),&tcpHeader,sizeof(TCP_HEADER));   
        memcpy(Sendto_Buff+sizeof(IP_HEADER)+sizeof(TCP_HEADER),tcp_send_data,sizeof(tcp_send_data));   
        int datasize=sizeof(IP_HEADER)+sizeof(TCP_HEADER)+sizeof(tcp_send_data);   
        //发送数据报的目的地址   
        SOCKADDR_IN dest;       
        memset(&dest,0,sizeof(dest));   
        dest.sin_family=AF_INET;    
        dest.sin_addr.s_addr=inet_addr(argv[3]);    
        dest.sin_port=htons(atoi(argv[4]));   
          
       rect=sendto(sock,Sendto_Buff,datasize, 0,(struct sockaddr*)&dest, sizeof(dest));    
       if (rect==SOCKET_ERROR)    
       {     
          printf("send error!:%d\n",WSAGetLastError());    
          return false;    
        }    
        else    
        printf("send ok!\n");    
        closesocket(sock);    
        WSACleanup();    
        return 1;    
    }  

我在电脑是试了一下,WSAGetlastError 返回值是10004。

10004的意思就是函数调用中断。 这个函数哪里会调用中断呢?

注意上面代码的红色。如果改成

ipHeader.proto=IPPROTO_UDP; //协议类型  
然后就没有问题。

然后用wireSHare 抓包,能够看到数据的确发出去了,但是是UDP。

那到底可不可以用sendto来发送TCP呢,

《Unix网络编程》 这本书上有明说,是可以的,尽管这样没有意义。

那如果要发送TCP,该怎么一个格式呢?


我的电脑是windows sp3。网上说sp2 是不行的。但是sp3 呢。


最后,在一个windows 7 上面运行成功了。也就是说sp3 也是不能支持的。害我一天。

系统原因,那具体是什么原因呢?不晓得了。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值