有没有办法知道局域网哪台机子是服务器。
如何判断本地是否与服务器连接。
开机后没有与服务器连接上,后来连上了应该怎样获得连接的信息。
由于编写的软件是运行在客户端的,服务器端什么都没有,只是被动的接受消息。如果用PING来判断是否连通,应该怎么写,请教达人。最好能有个例子或代码,谢谢!急用,今天就要搞定

解决方案 »

  1.   

    ping的代码#define TIMEOUT 3
    static int toflag;static int sock;
    static char sendbuf[1500],recvbuf[1500];
    static int datalen=56;
    static int nsend=0;
    static pid_t pid;
    static char *host,namebuf[50];
    static struct sockaddr_in to;
    static struct sockaddr_in from;extern CLog  g_log;void err_quit(char *msg)
    {
    //perror(msg);        
    printf("%s\n", msg);
    //exit(1);
    }unsigned short in_cksum(unsigned short *addr,int len)
    {
    int nleft=len;
    int sum=0;
    unsigned short *w=addr;
    unsigned short answer=0;
    while(nleft>1)
    {
    sum+=*w++;
    nleft-=2;
    }
    if(nleft==1)
    {
    *(unsigned char *)(&answer)=*(unsigned char *)w;
    sum+=answer;
    }
    sum=(sum>>16)+(sum&0xffff);
    sum+=(sum>>16);
    answer=~sum;
    return(answer);
    }void pinger(void)
    {
    struct icmp *icp;
    int cc;
    int i;
    bzero(sendbuf,1500);
    icp=(struct icmp *)sendbuf;
    icp->icmp_type=ICMP_ECHO;
    icp->icmp_code=0;
    icp->icmp_seq=nsend++;
    icp->icmp_id=pid;
    gettimeofday((struct timeval *)icp->icmp_data,NULL);
    cc=datalen+8;
    icp->icmp_cksum=in_cksum((unsigned short *)icp,cc);
    i=sendto(sock,sendbuf,cc,0,
    (struct sockaddr *)&to,sizeof(struct sockaddr));
    if(i<0||i!=cc)
    err_quit("sendto error");
    }        int proc_pack(ssize_t len,struct timeval *tvrecv)
    {
    int hlen1,icmplen;
    double rtt;
    struct ip *ip;
    struct icmp *icmp;        
    struct timeval *tvsend;
    char buf[50];
    ip=(struct ip *)recvbuf;
    hlen1=ip->ip_hl<<2;
    icmp=(struct icmp *)(recvbuf+hlen1);
    if((icmplen=len-hlen1)<8)
    {
    err_quit("icmplen1");
    return -1;
    }
    if(icmp->icmp_type==ICMP_ECHOREPLY)
    {
    if(icmp->icmp_id!=pid)
    return -1;
    if(icmplen<16)
    return -1; return 0;
    }
    return -1;
    }void sig_alrm(int signo)
    {
    signal(SIGALRM,sig_alrm);
    pinger();
    alarm(TIMEOUT);
    //return;
    }static void _alarmproc(int sig_num)
    {
    signal(SIGALRM, _alarmproc);
    toflag = 1;
    }int ping_loop(void)
    {        
    int size;
    int i;
    int len;
    ssize_t n;
    fd_set rset, wset;
    struct timeval tv;
    int timeout = 1;
    int bread; size = 60 * 1024;
    if((sock=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP))<0)        
    {
    //err_quit("create raw socket erro\n");
    return -1;
    } setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
    FD_ZERO(&rset);
    FD_SET(sock, &rset);
    wset = rset;
    tv.tv_sec = TIMEOUT;
    tv.tv_usec = 0;
    if(select(sock + 1, &rset, &wset, NULL, &tv) == 0)
    {
    //printf("in select()...\n");
    } for(i = 0; i < 3; i++)
    {        
    len=sizeof(from);
    pinger();
    if(errno==ETIMEDOUT)
    {
    //printf("pinger time out...\n");
    g_log.printlog(93001);
    return -1;
    } n=recvfrom(sock,recvbuf,1500,0,(struct sockaddr *)&from,&len); if(n<0)
    {
    if(errno==EINTR)
    return -1;
    //continue;
    else
    return -1;
    //err_quit("recvfrom");
    }
    gettimeofday(&tv,NULL);
    if(proc_pack(n,&tv) == 0)
    return 0;
    }
    return -1;
    }int gsnping(char *hostip)
    {
    struct sigaction act;
    struct hostent *ht;
    int ret;
    pid=getpid();
    act.sa_handler=sig_alrm;
    act.sa_flags=0;         signal(SIGALRM,sig_alrm);
    to.sin_family=AF_INET;
    to.sin_addr.s_addr=inet_addr(hostip);
    if(to.sin_addr.s_addr!=(unsigned int)-1)
    host=hostip;
    else
    {
    if(!(ht=gethostbyname(hostip)))
    err_quit("gethostbyname");
    to.sin_family=ht->h_addrtype;
    memmove(&to.sin_addr,ht->h_addr,ht->h_length);
    strncpy(namebuf,ht->h_name,sizeof(namebuf)-1);
    host=namebuf;
    } ret = ping_loop(); close(sock);
    return ret;
    }
      

  2.   

    不好意思,忘了我这代码是unix下用的了。你自己移植一下吧:)
      

  3.   

    ///////////////////////////////////////////
    // ping.cpp文件#include "../common/initsock.h"
    #include "../common/protoinfo.h"
    #include "../common/comm.h"#include <stdio.h>
    CInitSock theSock;
    typedef struct icmp_hdr
    {
        unsigned char   icmp_type; // 消息类型
        unsigned char   icmp_code; // 代码
        unsigned short  icmp_checksum; // 校验和
    // 下面是回显头
        unsigned short  icmp_id; // 用来惟一标识此请求的ID号,通常设置为进程ID
        unsigned short  icmp_sequence; // 序列号
        unsigned long   icmp_timestamp; // 时间戳
    } ICMP_HDR, *PICMP_HDR;
    int main()
    {
    // 目的IP地址,即要Ping的IP地址
    char szDestIp[] = "10.16.115.178"; // 127.0.0.1 // 创建原始套节字
    SOCKET sRaw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); // 设置接收超时
    SetTimeout(sRaw, 1000, TRUE); // 设置目的地址
    SOCKADDR_IN dest;
    dest.sin_family = AF_INET;
    dest.sin_port = htons(0);
    dest.sin_addr.S_un.S_addr = inet_addr(szDestIp); // 创建ICMP封包
    char buff[sizeof(ICMP_HDR) + 32];
    ICMP_HDR* pIcmp = (ICMP_HDR*)buff;
    // 填写ICMP封包数据
    pIcmp->icmp_type = 8; // 请求一个ICMP回显
    pIcmp->icmp_code = 0;
    pIcmp->icmp_id = (USHORT)::GetCurrentProcessId();
    pIcmp->icmp_checksum = 0;
    pIcmp->icmp_sequence = 0;
    // 填充数据部分,可以为任意
    memset(&buff[sizeof(ICMP_HDR)], 'E', 32);

    // 开始发送和接收ICMP封包
    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_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;
    }
    nRet = ::recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen);
    if(nRet == SOCKET_ERROR)
    {
    if(::WSAGetLastError() == WSAETIMEDOUT)
    {
    printf(" timed out\n");
    continue;
    }
    printf(" recvfrom() failed: %d\n", ::WSAGetLastError());
    return -1;
    } // 下面开始解析接收到的ICMP封包
    int nTick = ::GetTickCount();
    if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR))
    {
    printf(" Too few bytes from %s \n", ::inet_ntoa(from.sin_addr));
    }
    // 接收到的数据中包含IP头,IP头大小为20个字节,所以加20得到ICMP头
    ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20); // (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(" %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;
    }
      

  4.   

    //////////////////////////////////////////////////
    // comm.h文件// 包含一些公共函数#ifndef __COMM_H__
    #define __COMM_H__
    // 校验和的计算
    // 以16位的字为单位将缓冲区的内容相加,如果缓冲区长度为奇数,
    // 则再加上一个字节。它们的和存入一个32位的双字中
    USHORT checksum(USHORT* buff, int size);BOOL SetTTL(SOCKET s, int nValue);
    BOOL SetTimeout(SOCKET s, int nTime, BOOL bRecv = TRUE);
    #endif // __COMM_H__//////////////////////////////////////////////////
    // comm.cpp文件
    #include <winsock2.h>
    #include <windows.h>
    #include "Ws2tcpip.h"#include "comm.h"
    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;
    }
      

  5.   

    //////////////////////////////////////////////////////////
    // initsock.h文件#include <winsock2.h>
    #pragma comment(lib, "WS2_32") // 链接到WS2_32.libclass CInitSock
    {
    public:
    CInitSock(BYTE minorVer = 2, BYTE majorVer = 2)
    {
    // 初始化WS2_32.dll
    WSADATA wsaData;
    WORD sockVersion = MAKEWORD(minorVer, majorVer);
    if(::WSAStartup(sockVersion, &wsaData) != 0)
    {
    exit(0);
    }
    }
    ~CInitSock()
    {
    ::WSACleanup();
    }
    };
    //////////////////////////////////////////////////
    // protoinfo.h文件/*定义协议格式
    定义协议中使用的宏 */
    #ifndef __PROTOINFO_H__
    #define __PROTOINFO_H__
    #define ETHERTYPE_IP    0x0800
    #define ETHERTYPE_ARP   0x0806typedef struct _ETHeader         // 14字节的以太头
    {
    UCHAR dhost[6]; // 目的MAC地址destination mac address
    UCHAR shost[6]; // 源MAC地址source mac address
    USHORT type; // 下层协议类型,如IP(ETHERTYPE_IP)、ARP(ETHERTYPE_ARP)等
    } ETHeader, *PETHeader;
    #define ARPHRD_ETHER  1// ARP协议opcodes
    #define ARPOP_REQUEST 1 // ARP 请求
    #define ARPOP_REPLY 2 // ARP 响应
    typedef struct _ARPHeader // 28字节的ARP头
    {
    USHORT hrd; // 硬件地址空间,以太网中为ARPHRD_ETHER
    USHORT eth_type; //  以太网类型,ETHERTYPE_IP ??
    UCHAR maclen; // MAC地址的长度,为6
    UCHAR iplen; // IP地址的长度,为4
    USHORT opcode; // 操作代码,ARPOP_REQUEST为请求,ARPOP_REPLY为响应
    UCHAR smac[6]; // 源MAC地址
    UCHAR saddr[4]; // 源IP地址
    UCHAR dmac[6]; // 目的MAC地址
    UCHAR daddr[4]; // 目的IP地址
    } ARPHeader, *PARPHeader;
    // 协议
    #define PROTO_ICMP    1
    #define PROTO_IGMP    2
    #define PROTO_TCP     6
    #define PROTO_UDP     17typedef struct _IPHeader // 20字节的IP头
    {
        UCHAR     iphVerLen;      // 版本号和头长度(各占4位)
        UCHAR     ipTOS;          // 服务类型 
        USHORT    ipLength;       // 封包总长度,即整个IP报的长度
        USHORT    ipID;   // 封包标识,惟一标识发送的每一个数据报
        USHORT    ipFlags;       // 标志
        UCHAR     ipTTL;       // 生存时间,就是TTL
        UCHAR     ipProtocol;     // 协议,可能是TCP、UDP、ICMP等
        USHORT    ipChecksum;     // 校验和
        ULONG     ipSource;       // 源IP地址
        ULONG     ipDestination;  // 目标IP地址
    } IPHeader, *PIPHeader; 
    // 定义TCP标志
    #define   TCP_FIN   0x01
    #define   TCP_SYN   0x02
    #define   TCP_RST   0x04
    #define   TCP_PSH   0x08
    #define   TCP_ACK   0x10
    #define   TCP_URG   0x20
    #define   TCP_ACE   0x40
    #define   TCP_CWR   0x80typedef struct _TCPHeader // 20字节的TCP头
    {
    USHORT sourcePort; // 16位源端口号
    USHORT destinationPort; // 16位目的端口号
    ULONG sequenceNumber; // 32位序列号
    ULONG acknowledgeNumber; // 32位确认号
    UCHAR dataoffset; // 高4位表示数据偏移
    UCHAR flags; // 6位标志位
    //FIN - 0x01
    //SYN - 0x02
    //RST - 0x04 
    //PUSH- 0x08
    //ACK- 0x10
    //URG- 0x20
    //ACE- 0x40
    //CWR- 0x80 USHORT windows; // 16位窗口大小
    USHORT checksum; // 16位校验和
    USHORT urgentPointer; // 16位紧急数据偏移量 
    } TCPHeader, *PTCPHeader;typedef struct _UDPHeader
    {
    USHORT sourcePort; // 源端口号
    USHORT destinationPort;// 目的端口号
    USHORT len; // 封包长度
    USHORT checksum; // 校验和
    } UDPHeader, *PUDPHeader;#endif // __PROTOINFO_H__
      

  6.   

    谢谢两位,但是我感觉我用不到这么复杂,我使用WinExec (_T("ping 192.168.1.100"),  SW_SHOW); 虽然可以显示网络是否接通,但是却没有办法得到是否接通的消息,请问应该怎么办,有办法得到执行WinExec 后在DOS窗口显示的字符串吗
      

  7.   

    fulingwei,能把你的代码改成一个工程文件发给我吗,谢谢