免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4971 | 回复: 5
打印 上一主题 下一主题

ping 代码中关于sendto()和recvfrom()的疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-12-29 14:43 |只看该作者 |倒序浏览
主代码如下:
#include "winsock2.h"
#include "stdio.h"
#pragma comment(lib,"WS2_32")
#pragma   comment(lib,"winmm.lib")  
#include "comm.h"
#include "initsock.h"
#include "Ws2tcpip.h"
#include "protoinfo.h"
typedef struct icmp_hdr
{
                unsigned char icmp_type;
                unsigned char icmp_code;
                unsigned short icmp_checksum;
                unsigned short icmp_id;
                unsigned short icmp_sequence;
                unsigned long icmp_timestamp;
}ICMP_HDR,*PICMP_HDR;

USHORT checksum(USHORT* buff, int size)
{
        unsigned long cksum = 0;
        while(size>1)
        {
                cksum += *buff++;
                size -= sizeof(USHORT);
        }
        // 是奇数
        if(size)
        {
                cksum += *(UCHAR*)buff;
        }
        // 将32位的chsum高16位和低16位相加,然后取反
        cksum = (cksum >> 16) + (cksum & 0xffff);
        //cksum += (cksum >> 16);                       
        return (USHORT)(~cksum);
}

BOOL SetTTL(SOCKET s, int nValue)
{
        int ret = ::setsockopt(s, IPPROTO_IP, IP_TTL, (char*)&nValue, sizeof(nValue));
        return ret != SOCKET_ERROR;
}

BOOL SetTimeout(SOCKET s, int nTime, BOOL bRecv)
{
        int ret = ::setsockopt(s, SOL_SOCKET,
                bRecv ? SO_RCVTIMEO : SO_SNDTIMEO, (char*)&nTime, sizeof(nTime));
        return ret != SOCKET_ERROR;
}


int main(int argc, char* argv[])
{
        WSADATA wsaData;
        int wsaret = WSAStartup(0x101,&wsaData);
        SOCKET sRaw = ::socket(AF_INET , SOCK_RAW , IPPROTO_ICMP );
        SetTimeout(sRaw , 5000 , true);
        sockaddr_in dest;
        dest.sin_family = AF_INET;
        dest.sin_port = htons(0);
        dest.sin_addr.S_un.S_addr = inet_addr(argv[1]);
//         dest.sin_addr.S_un.S_addr = inet_addr(ip);
        char buff[sizeof(ICMP_HDR)+32];
        ICMP_HDR* pIcmp = (ICMP_HDR*)buff;
        pIcmp->icmp_type = 8;
        pIcmp->icmp_code = 0;
        pIcmp->icmp_id = (USHORT)::GetCurrentProcessId();
        pIcmp->icmp_checksum = 0;
        pIcmp->icmp_sequence= 0;
       
        memset(&buff[sizeof(ICMP_HDR)], 'a' ,32);
        USHORT nSeq = 0;
        char recvBuf[1024];
        sockaddr_in from;
        int nLen = sizeof(from);
        while(true)
        {
                            static int nCount = 0;
                            int nRet;
                            if (nCount++ ==4) break;
                            pIcmp->icmp_checksum = 0;
//                            pIcmp->icmp_timestamp = ::GetTickCount();
                           pIcmp->icmp_timestamp = ::timeGetTime();
                            pIcmp->icmp_sequence = nSeq++;
                            pIcmp->icmp_checksum = checksum((USHORT*)buff,sizeof(ICMP_HDR)+32);

                            nRet = ::sendto(sRaw , buff , sizeof(ICMP_HDR)+32 , 0,(sockaddr*)&dest,sizeof(dest));
                            if(nRet == SOCKET_ERROR)
                            {
                                              printf("sendto() failed:%d\n",::WSAGetLastError());
                                              return -1;
               }
                           memset(recvBuf,'\0',1024);
               nRet = ::recvfrom(sRaw,recvBuf,1024,0,(sockaddr*)&from,&nLen);
               if(nRet == SOCKET_ERROR)
               {
                       if(::WSAGetLastError() == WSAETIMEDOUT)
                       {
                           printf("time out\n");
                           continue;
                           }

                                       printf("recvfrom() failed\n");
                                       return -1;
                                             }
                int nTick = ::timeGetTime();
                if(nRet < sizeof(IPHeader)+sizeof(ICMP_HDR))
                {
                                                 printf("Too few bytes from %s \n",::inet_ntoa(from.sin_addr));
                                                }
                         ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf +sizeof(IPHeader));
                         if (pRecvIcmp->icmp_type !=0)
                         {
                                            printf("nonecho type %d recvd \n",pRecvIcmp->icmp_type);
                                            return -1;
                                        }
                                if(pRecvIcmp->icmp_id != ::GetCurrentProcessId())
                                {
                                 printf("someone else's packet!\n");
                                 return -1;
                                 }
                                printf("%s\n",recvBuf+sizeof(IPHeader)+sizeof(ICMP_HDR));
                                printf("%d bytes from %s:",nRet,inet_ntoa(from.sin_addr));
                                printf("icmp_seq = %d:",pRecvIcmp->icmp_sequence);
                                printf("time:%d ms", nTick - pRecvIcmp->icmp_timestamp);
                                printf("\n");

                                ::Sleep(1000);
    }
        return 0;
}


在其中有::sendto()以及recvfrom()函数。
这两个函数究竟是什么关系?
可不可以不使用sendto 直接使用recvfrom()?

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
2 [报告]
发表于 2007-12-29 15:07 |只看该作者
你不向外发送,怎么能收到别人的应答?

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
3 [报告]
发表于 2007-12-29 17:19 |只看该作者
呵呵,版主说的对啊。sendto是先给别人发信息,然后可以用recvfrom信息。不过这是指一般作为客户端时的情形。

论坛徽章:
0
4 [报告]
发表于 2007-12-30 10:00 |只看该作者
但是,如果我使用系统自带的ping程序向外发送数据,不就可以收到别人发回的数据了吗?

论坛徽章:
0
5 [报告]
发表于 2007-12-30 10:42 |只看该作者
原帖由 bdren 于 2007-12-30 10:00 发表
但是,如果我使用系统自带的ping程序向外发送数据,不就可以收到别人发回的数据了吗?

当然可以. 见 http://msdn2.microsoft.com/en-us/library/ms740548.aspx

论坛徽章:
0
6 [报告]
发表于 2007-12-30 16:01 |只看该作者

回复 #4 bdren 的帖子

晕 两个不同的socket 句柄 ,你自己的程序怎么去收,又不是自己抓包
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP