티스토리 뷰

목차

    반응형

    [C++] Qt 인터넷 네트워크 연결 상태 확인 (QTcpSocket)


    ■ Unplugging ethernet (물리적 문제로 인터넷 끊김)

    Qt에서 소켓을 사용하다 보면 끊어진 경우를 확인해야 할 상황이 발생합니다. 굳이 Qt가 아니더라도 언제나 서비스 제공자는 확인해야 합니다만, Qt를 이용한 프로그래밍을 할 땐, 단순히 플러그가 뽑힌 경우를 체크하기엔 까다롭습니다. 


    왜냐면 QAbstractSocket 클래스가 제공하는 ConnectedState는 연결된 이후, 물리적인 플러그 뽑힘을 확인하지 못합니다.


    슬프게도, Qt가 제공하는 그 어떤 소켓 클래스들도 물리적인 플러그 Unconnected를 확인하질 못합니다. 그래서 조금 돌아가는 방법을 사용해야 합니다.




    ■ Simple Main Code

    우선, 간단한 Socket Program을 만들어 봅니다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    main.h
     
    #include <QProcess>
    #include <QTcpSocket>
     
    QProcess ping_process_;
    QStringList ping_params_;
     
    private slots:
        void HandleConnected();
        void HandleDisconnected();
        void HandleReadyRead();
        void HandleStateChange(QAbstractSocket::SocketState state);
    cs


    1
    2
    3
    4
    5
    6
    7
    8
    9
    main.cpp
     
    tcp_socket_ = new QTcpSocket(this);
     
    connect(tcp_socket_, SIGNAL(connected()), this, SLOT(HandleConnected()));
    connect(tcp_socket_, SIGNAL(readyRead()), this, SLOT(HandleReadyRead()));
    connect(tcp_socket_, SIGNAL(disconnected()), this, SLOT(HandleDisconnected()));
    connect(tcp_socket_, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this,
    SLOT(HandleStateChange(QAbstractSocket::SocketState)));
    cs


    1
    ping_params_ << "-c" << "1" << server_ip_;
    cs


    아주 간단한 프로그램입니다.


    Qt QTcpSocket 네트워크[C++] Qt 인터넷 네트워크 연결 상태 확인 (QTcpSocket)


    4개의 Qt slot은 연결, 끊김, 읽기, 상태 변화를 의미합니다. 메인 코드의 마지막엔 연결이 잘 이루어졌는지 ping을 날려보는 간단한 코드도 들어있습니다.


    ■ Ping and QProcess

    Ping 테스트를 할 땐, http://를 넣으면 오류가 발생하고, Window와 Linux에선 서로 다른 인자를 사용하니 그것도 확인해 줘야 합니다.


    이를 확인하지 않으면 아래와 유사한 에러 메시지가 뜰 겁니다.


    • error, message


    Try removing "http://" in line number

    Ping expects an IP or an hostname, "http://" isn't part of the hostname.

    cout<<"\n\nexitCode,exitStatus=="<<exitCode<<","<<exitStatus


    ping 코드를 작성할 아래처럼 http://를 제거하고 난 뒤에 시도하셔야 합니다.


    그러면 아래와 같은 코드를 작성하실 수 있습니다.


    아주 간단하게 말이죠.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #if defined(WIN32)
       QString parameter = "-n 1";
    #else
       QString parameter = "-c 1";
    #endif
     
    int exitCode = QProcess::execute("ping", QStringList() << parameter << "1.1.1.11");
     
    if (exitCode==0
    {
        // it's alive
    else 
    {
        // it's dead
    }
     
    .....
    params << "-c" << "1" << "www.google.com";
    cs

    ConnectToServer function


    1
    2
    3
    4
    5
    6
    7
    void TcpClient::ConnectToServer()
    {
        if (tcp_socket_->state() != QAbstractSocket::ConnectedState &&
                tcp_socket_->state() != QAbstractSocket::ConnectingState) {
            tcp_socket_->connectToHost(server_ip_, server_port_);
        }
    }
    cs


    위에서 선언만 했던 Qt ConnecToServer 함수를 정의합니다.


    socket 객체가 아직도 연결되지 않은 상태라면 연결을 시도합니다. 이것도 아주 간단하죠?


    Qt 네트워크 프로그래밍[C++] Qt 인터넷 네트워크 연결 상태 확인 (QTcpSocket)


    ■ HandleConnected function


    1
    2
    3
    4
    5
    6
    7
    8
    void TcpClient::HandleConnected()
    {
        qWarning() << "connect Complete";
     
        bla~ bla~ bla~
     
        emit ConnectionComplete();
    }
    cs


    이어서 HandleConnected 함수도 정의합니다. 이름 그대로 연결이 되면 구동되는 함수입니다.


    내부의 코드는 각자 입맛에 맞춰 구성하면 됩니다.


    ■ StateChange property

    StateChange 속성은 아래와 같습니다.


    Constant

     Value

     Description

     QAbstractSocket::UnconnectedState

    0

     The socket is not connected.

     QAbstractSocket::HostLookupState

    1

     The socket is performing a host name lookup.

     QAbstractSocket::ConnectingState

    2

     The socket has started establishing a connection.

     QAbstractSocket::ConnectedState

    3

     A connection is established.

     QAbstractSocket::BoundState

    4

     The socket is bound to an address and port

     (for servers).

     QAbstractSocket::ClosingState

    5

     The socket is about to close

     (data may still be waiting to be written).

     QAbstractSocket::ListeningState

    6

     For internal use only.


    일반적으로 주로 사용하는 Constant는 굵게 표시된 위의 두 개입니다.


    아무튼, 저 표를 통해서 유추할 수 있는 아주 간단한 사실은,


    1
    2
    3
    4
    5
    // Normal
    QAbstractSocket::ConnectedState
     
    // Abnormal
    QAbstractSocket::UnconnectedState
    cs


    이겁니다. 그래서 아래와 같은 한 줄로 코드에서 분기가 가능합니다.


    1
    tcp_socket_->state() == QAbstractSocket::UnconnectedState
    cs


    Qt QTcpSocket 소켓 프로그래밍[C++] Qt 인터넷 네트워크 연결 상태 확인 (QTcpSocket)

    아래엔 실제 구현할 수 있는 소켓 프로그램의 전체 코드입니다. (위와 이어지는 내용)


    1
    2
    3
    4
    5
    6
    7
    void TcpClient::HandleStateChange(QAbstractSocket::SocketState state)
    {
        if (tcp_socket_->state() == QAbstractSocket::UnconnectedState)
            HandleDisconnected();
     
        qWarning() << "State Changed : " << state;
    }
    cs


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void TcpClient::HandleDisconnected()
    {
        if (timer_connecte_->isActive() == false) {
            tcp_socket_->close();
       bla~ bla~
        }
     
        emit ConnectionError();
     
        qWarning() << "HandleDisconnected";
    }
    cs


    1
    2
    3
    4
    5
    void TcpClient::HandleReadyRead()
    {
        recv_data_ = tcp_socket_->readAll();
        CheckPacketID();
    }
    cs


    자, 이제 몇 가지 케이스를 들어 Qt의 소켓이 여러 끊김 현상을 감지할 수 있는지 확인합니다.


    물론 위에 나온 코드를 이용해 테스트를 진행할 겁니다. (위의 코드만 복사하면 프로그램 하나가 만들어지니깐요)


    ■ Case1 : Unplugged ethernet

    QProcess에서 과연 ethernet의 끊김을 확인할 수 있을까?


    output 메시지와 error 메시지를 확인하면 알 수 있습니다.


    output message


    정상적인 상황 : 아래 메시지


    "PING 192.168.1.17 (192.168.1.17) 56(84) bytes of data.

    64 bytes from 192.168.1.17: icmp seq=1 ttl=128 time=0.830ms


    --- 192.168.1.17 ping statistics ---

    1 packets transmitted, 1 received, 0% packet loss, time 0ms

    rtt min/avg/max/mdev = 0.830/0.830/0.830/0.000 ms"


    비정상적인 상황 : 없음


    error message


    정상적인 상황 : 없음

    비정상적인 상황 : 아래 메시지


    connect: Network is unreachable


    분명히 error 메시지를 통해서 이더넷의 연결 끊김은 확실히 확인 할 수 있습니다.


    ■ Case2 : Power off the target (thing..)

    어떤 게 연결된진 모르겠지만, 하여간에 연결된 장치 쪽의 전원이 꺼진 상태입니다.

    PLC가 될 수도 있고, 작은 임베디드 보드일 수도 있고, 데스크톱일 수도 있고, 경우는 많습니다.


    output message


    정상적인 상황 : 아래 메시지

    "PING 192.168.1.17 (192.168.1.17) 56(84) bytes of data.

    64 bytes from 192.168.1.17: icmp seq=1 ttl=128 time=0.830ms


    --- 192.168.1.17 ping statistics ---

    1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.830/0.830/0.830/0.000 ms"


    비정상적인 상황 : 없음


    error message


    정상적인 상황 : 아래 메시지


    QProcess: Destroyed while process ("ping") is still running.


    비정상적인 상황 : 없음


    Qt ping을 통해서 연결 끊김이 확인됩니다. Case 1에선 ethernet이 끊어짐을 확인했으나 이번엔 그러질 못했습니다. 오직 ping 메시지를 통해서만 알 수 있습니다.


    Qt 통신 네트워크 QTcpSocket[C++] Qt 인터넷 네트워크 연결 상태 확인 (QTcpSocket)


    ■ Solution

    단순히 StateChange 속성만 가지고선 언플러그를 확인할 수가 없습니다. 그래서 Case2와 같이 ping을 전달하는 방법으로 언플러그를 확인해야 합니다.


    Ping을 다루는 소스는 위의 소스처럼 아주 간단합니다.


    1
    2
    3
    4
    5
    6
    QProcess p;
    p.start( /* whatever your command is, see the doc for param types */ );
    p.waitForFinished(-1);
     
    QString p_stdout = p.readAllStandardOutput();
    QString p_stderr = p.readAllStandardError();
    cs


    원형은 위와 같은데 실제 응용하기 위해선 뭔가 변화를 줘야 합니다.


    저는 아래처럼 소스를 구성해 메인 클래스에 추가했습니다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    /** ping 테스트 */
    ping_process_.start("ping", ping_params_, QIODevice::ReadOnly);
    ping_process_.waitForFinished(kInterval1500);
     
    QString out = ping_process_.readAllStandardOutput();
    QString err = ping_process_.readAllStandardError();
     
    if (out.compare(""== 0 && err.compare(""== 0)
        HandleDisconnected();
    cs


    넣고 싶은 곳에 적당히 넣어주면 되는 소스입니다.


    그리고 아래와 같은 소스도 구동해 볼 수 있습니다.



    그렇지만 이 코드는 프로세스 자체가 아예 wait 상태로 진입해 버리는 문제가 있습니다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #include <qapplication>
    #include <qprocess>
    #include <qtgui>
     
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        QMessageBox *box = new QMessageBox;
        int res = -1;
        QStringList list;
     
        list << "66.249.89.99";
     
        res = QProcess::execute("ping", list);
     
        if(res == 0)
        {
            box->setText("ping success");
        }
        else
        {
            box->setText("ping failure");
        }
     
        box->show();
     
        return app.exec();
    }
    </qtgui></qprocess></qapplication>
    cs


    위에서 살펴봤지만, 플러그 뽑힘 증상을 기본 QTcpSocket으로는 확인하질 못합니다.


    부득이하게 ping을 이용해 확인할 순 있는데 이것도 임시방편에 지나지 않기에, Qt에선 이 부분을 반영하는 형태로 Disconnected 속성을 변경해주는 게 좋다고 봅니다.


    마지막으로, 아래는 진행하면서 참고했던 사이트들입니다.




    [C++] Qt 인터넷 네트워크 연결 상태 확인 (QTcpSocket)

     written by vicddory

    반응형