問題描述
我有一個 QTcpSocket 并且我正在讀入一個循環.每次讀完一個完整的數據包,或者出現錯誤時,我都會手動檢查循環內套接字的狀態,用:
I have a QTcpSocket and I am reading into a loop. Each time a full packet has been read, or there has been an error, I manually check the status of the socket inside the loop, with:
while(true){
if(socket->state()==QAbstractSocket::ConnectedState){
qDebug()<<"Socket status: connected. Looking for packets...";
if(socket->waitForReadyRead(2000)){
//...
}
當我執行de程序時,一旦連接并且循環開始,它總是打印qDebug()<<Socket status: connected.尋找數據包..."
;然后停留在 waitForReadyRead
直到一些數據準備好被讀取.
When I execute de program, once connected and the loop starts, it always prints qDebug()<<"Socket status: connected. Looking for packets..."
; and then stucks at waitForReadyRead
until some data is ready to be read.
問題是未檢測到斷開連接.如果我從操作系統選項斷開網絡連接,或者即使我拔掉以太網線,它的行為也是一樣的:套接字狀態等于 QAbstractSocket::ConnectedStat
e,所以它繼續,但沒有收到任何當然.
The problem is that disconnections are not detected. If I disconnect from network from the OS options, or even if I unplug the ethernet wire, it behaves the same: Socket state equals QAbstractSocket::ConnectedStat
e, so it goes on, but without receiving anything of course.
我還嘗試檢測將 disconnected()
信號(在第一次連接后)連接到重新連接函數的斷開連接:
I also tried to detect disconnections connecting disconnected()
signal (after fist connection) to a reconnect function:
// Detect disconnection in order to reconnect
connect(socket, SIGNAL(disconnected()), this, SLOT(reconnect()));
void MyClass::reconnect(){
qDebug()<<"Signal DISCONNECTED emitted. Now trying to reconnect";
panelGUI->mostrarValueOffline();
socket->close();
prepareSocket((Global::directionIPSerialServer).toLocal8Bit().data(), 8008, socket);
qDebug()<<"Reconnected? Status: "<<socket->state();
}
但是信號永遠不會發出,因為這段代碼永遠不會被執行.這是合乎邏輯的,因為看起來套接字狀態總是 ConnectedState
.
But signal is never emited, because this code is never executed. Which is logical, since it looks like socket state is always ConnectedState
.
如果我再次插入,連接將恢復并再次開始接收數據,但我確實想檢測斷開連接以在 GUI 上顯示斷開連接".
If I plug again, connection is restored and starts to receive data again, but I do want to detect disconnections to show "Disconnected" at the GUI.
為什么 QTcpSocket 會這樣,我該如何解決這個問題?
Why is QTcpSocket behaving this way, and how can I solve this problem?
我在類構造函數中創建套接字,然后初始化調用 prepareSocket 函數:
I'm creating socket at the class constructor, and then initialising calling prepareSocket function:
socket = new QTcpSocket();
socket->moveToThread(this);
bool prepareSocket(QString address, int port, QTcpSocket *socket) {
socket->connectToHost(address, port);
if(!socket->waitForConnected(2000)){
qDebug()<<"Error creating socket: "<<socket->errorString();
sleep(1);
return false;
}
return true;
}
推薦答案
終于在這個找到解決方案Qt論壇:
如果一段時間沒有數據交換,TCP 將開始發送保持活動段(基本上,帶有確認的 ACK 段number 設置為當前序列號減一).另一個同行然后回復另一個確認.如果這個確認是在一定數量的探測段內沒有收到,連接被自動丟棄.小問題是內核啟動連接后 2 小時后發送保持活動的段變得空閑!因此,您需要更改此值(如果您的操作系統允許)或在您的系統中實現您自己的保持活動機制協議(就像許多協議一樣,例如 SSH).Linux 允許你使用 setsockopt 更改它:
If no data is exchanged for a certain while, TCP will start sending keep-alive segments (basically, ACK segments with the acknowledgement number set to the current sequence number less one). The other peer then replies with another acknowledgement. If this acknowledgment is not received within a certain number of probe segments, the connection is automatically dropped. The little problem is that the kernel starts sending keep-alive segments after 2 hours since when the connection becomes idle! Therefore, you need to change this value (if your OS allows that) or implement your own keep-alive mechanism in your protocol (like many protocols do, e.g. SSH). Linux allows you to change it using setsockopt:
int enableKeepAlive = 1;
int fd = socket->socketDescriptor();
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enableKeepAlive, sizeof(enableKeepAlive));
int maxIdle = 10; /* seconds */
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &maxIdle, sizeof(maxIdle));
int count = 3; // send up to 3 keepalive packets out, then disconnect if no response
setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &count, sizeof(count));
int interval = 2; // send a keepalive packet out every 2 seconds (after the 5 second idle period)
setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
這篇關于QTcpSocket 狀態始終連接,甚至拔掉以太網線的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!