티스토리 뷰
목차
[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 |
아주 간단한 프로그램입니다.
[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 객체가 아직도 연결되지 않은 상태라면 연결을 시도합니다. 이것도 아주 간단하죠?
[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 |
[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 메시지를 통해서만 알 수 있습니다.
[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 속성을 변경해주는 게 좋다고 봅니다.
마지막으로, 아래는 진행하면서 참고했던 사이트들입니다.
참조 사이트
- Ping and QProcess (exitcode() question) [클릭]
- running ping with Qprocess, exit code always 2 if host reachable or not [클릭]
- QAbstractSocket Class [클릭]
- Run Linux commands from Qt4 [클릭]
- How to Detect “Network is Unreachable” via Ping using QProcess? [클릭]
- 간단한 ping 명령어 사용하기(QProcess::execute) [클릭]
- QT - TCP/IP 소켓 프로그래밍(클라이언트) [클릭]
[C++] Qt 인터넷 네트워크 연결 상태 확인 (QTcpSocket)
written by vicddory