QT實現ping功能

菜鳥的快樂發表於2020-12-11

QT實現ping功能

1.問題描述:

  • 介面點選“建立連線”按鈕實現測試主機和目的主機的通訊鏈路是否正常。

2.解決思路:

  • "建立連線"按鈕響應槽函式,槽函式實現ping操作,返回ping通的結果。

3.解決方法:

方法(1) QProcess呼叫命令列,讀取標準輸出即可。

QProcess物件可以直接執行cmd的命令,但是ping操作是會阻塞的,所以需要在子執行緒裡ping
QProcess *tempCmd = new QProcess();
tempCmd->start(orderInfo);
tempCmd->waitForFinished(1000);//阻塞等待執行命令完成,否則返回的很可能是空字串
QString resultInfo = QString::fromLocal8Bit(tempCmd->readAllStandardOutput());//resultStr就是返回結果,需要fromLocal8Bit來接收中文

方法二(2) 不建議使用QProcess呼叫命令列然後解析返回字串來判斷。我曾經用過這種方法,會程式崩潰。我的程式碼是完全沒問題。後來我是重寫了ping來實現的。就是自己從更底層去實現這個ping,其實程式碼量不大的。原始碼也是有標準的。你拿下來改改就OK

```ctypedef struct tagIPHDR
    {
        u_char VIHL; // Version and IHL
        u_char TOS; // Type Of Service
        short TotLen; // Total Length
        short ID; // Identification
        short FlagOff; // Flags and Fragment Offset
        u_char TTL; // Time To Live
        u_char Protocol; // Protocol
        u_short Checksum; // Checksum
        struct in_addr iaSrc; // Internet Address - Source
        struct in_addr iaDst; // Internet Address - Destination
    }IPHDR, *PIPHDR;
 
    // ICMP Header - RFC 792
    typedef struct tagICMPHDR
    {
        u_char Type; // Type
        u_char Code; // Code
        u_short Checksum; // Checksum
        u_short ID; // Identification
        u_short Seq; // Sequence
        char Data; // Data
    }ICMPHDR, *PICMPHDR;
 
    // ICMP Echo Request
    typedef struct tagECHOREQUEST
    {
        ICMPHDR icmpHdr;
        struct timeval echoTime;
        char cData[32];
    }ECHOREQUEST, *PECHOREQUEST;
 
    // ICMP Echo Reply
    typedef struct tagECHOREPLY
    {
        IPHDR ipHdr;
        ECHOREQUEST echoRequest;
        char cFiller[256];
    }ECHOREPLY, *PECHOREPLY;
 
bool Utilities::ping(const char *hostName)
{
    if (NULL == hostName)
    {
        XgsLogger::log("", QtWarningMsg, "(%s,%d), Invalid IP address!", __FILE__, __LINE__ );
        return false;
    }
    int sockfd = 0;
    int nRet;
    int nCount;
    int iSuccess = 0;
    struct sockaddr_in addrDest;
    struct hostent *Dest;
    float spenttime;
 
    if ((Dest=gethostbyname(hostName)) == NULL)
    {
        return false;
    }
    if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
    {
        return false;
    }
 
    memset((char *)&addrDest, 0, sizeof(struct sockaddr_in));
    addrDest.sin_addr = *((struct in_addr *)Dest->h_addr);
    addrDest.sin_family = AF_INET;
    bzero(&(addrDest.sin_zero), sizeof( addrDest.sin_zero ) );
 
    ECHOREQUEST echoReq;
    memset((ECHOREQUEST*)&echoReq, 0, sizeof(struct tagECHOREQUEST));
    echoReq.icmpHdr.Type = ICMP_ECHO;
    echoReq.icmpHdr.Code = 0;
    echoReq.icmpHdr.ID = getpid();
    int Seq = 0;
    for (nRet = 0; nRet < 32; nRet++)
        echoReq.cData[nRet] = ' '+nRet;
    nCount = 0;
    while(nCount < 3)
    {
        echoReq.icmpHdr.Seq = Seq++;
        echoReq.icmpHdr.Checksum = 0;
        gettimeofday(&echoReq.echoTime,NULL);
        echoReq.icmpHdr.Checksum = checksum((unsigned short*)&echoReq, sizeof(struct tagECHOREQUEST));
        if (sendto(sockfd, (ECHOREQUEST*)&echoReq, sizeof(tagECHOREQUEST), 0, (struct sockaddr *)&addrDest, sizeof(addrDest)) < 0)
        {
            close(sockfd);
            return false;
        }
        if(WaitForEchoReply(sockfd) == -1)
        {
            close(sockfd);
            return false;
        }
        ECHOREPLY icmpRecv;
        int addr_len;
        addr_len = sizeof(struct sockaddr);
        if (recvfrom(sockfd, (ECHOREPLY*)&icmpRecv, sizeof(struct tagECHOREPLY), 0, (struct sockaddr *)&addrDest, (socklen_t *)&addr_len) < 0)
        {
 
            close(sockfd);
            return false;
        }
        else if(icmpRecv.echoRequest.icmpHdr.Type == ICMP_ECHOREPLY)
        {
            gettimeofday(&icmpRecv.echoRequest.echoTime, NULL);
            tv_sub(&icmpRecv.echoRequest.echoTime, &echoReq.echoTime);
            spenttime=icmpRecv.echoRequest.echoTime.tv_sec*1000+icmpRecv.echoRequest.echoTime.tv_usec*0.001;
            if (strcmp(Dest->h_name, inet_ntoa(icmpRecv.ipHdr.iaSrc))==0)
            {
                iSuccess ++;
            //    printf("Reply from %s: Bytes=%d Id_seq = %d time=%4.3fms TTL=%d\n",/*Dest->h_name*/inet_ntoa(icmpRecv.ipHdr.iaSrc), sizeof(icmpRecv.echoRequest), icmpRecv.echoRequest.icmpHdr.Seq, spenttime,icmpRecv.ipHdr.TTL);
            }
            else
            {
            ;    //printf("From %s Id_seq %d Destination Host Unreachable ", inet_ntoa(icmpRecv.ipHdr.iaSrc), icmpRecv.echoRequest.icmpHdr.Seq);
            }
        //    sleep(1);
        }
        nCount ++;
    }
 
    close(sockfd);
    if (iSuccess >0)
        return true;
    else
        return false;
 
}

方法(3) 不實現ping功能,更為簡單的方法

//判斷IP地址及埠是否線上
    static bool IPLive(QString ip, int port, int timeout = 1000) {
        QTcpSocket tcpClient;
        tcpClient.abort();
        tcpClient.connectToHost(ip, port);
        //100毫秒沒有連線上則判斷不線上
        return tcpClient.waitForConnected(timeout);
    }
//判斷是否通外網
    static bool IsWebOk() {
        //能接通百度IP說明可以通外網
        return IPLive("115.239.211.112", 80);
    }

非原創,個人學習筆記,侵權必刪!
參考部落格:https://bbs.csdn.net/topics/391873625
https://www.cnblogs.com/judes/p/7069051.html

相關文章