我有一个和与QTcpSocket我读成一个圈。 每一个完整的数据包已经被阅读,或出现了一个错误的时间,我手动检查插座的状态内循环,用:
while(true){
if(socket->state()==QAbstractSocket::ConnectedState){
qDebug()<<"Socket status: connected. Looking for packets...";
if(socket->waitForReadyRead(2000)){
//...
}
当我执行程序去,一旦连接,并在循环开始,它总是打印qDebug()<<"Socket status: connected. Looking for packets..."
; 然后在stucks waitForReadyRead
直到一些数据已准备好被读取。
问题是,没有检测到断线。 如果我从网络断开OS选项,否则即使我拔掉网线,它的行为是一样的:套接字状态等于QAbstractSocket::ConnectedStat
E,所以它的推移,但没有接受,当然任何事情。
我还试图检测连接断开disconnected()
信号(拳头连接之后),以重新连接功能:
// 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();
}
但信号也决不emited,因为永远不会执行该代码。 这是合乎逻辑的,因为它看起来像座状态总是ConnectedState
。
如果我再次插入,连接恢复并重新开始接收数据,但我确实想发现断开,以示“断开连接”的GUI。
为什么表现与QTcpSocket这样,我怎么能解决这个问题?
编辑:我在类的构造函数创建套接字,然后调用初始化函数prepareSocket:
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段)发送保持活动段。 其它对等然后用另一确认进行回复。 如果该确认是不是一个特定数量的探针段内接收到,则连接被自动删除。 小问题是,内核启动后2小时,因为当连接空闲发送保活段! 因此,您需要更改这个值(如果您的操作系统允许),或在您的协议,实现自己保持活动的机制(如许多协议来完成,如SSH)。 Linux允许你使用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));
我一直面临着一个QT客户端应用程序类似的问题。 基本上我与定时器,信号和槽处理它。 当应用程序启动时,它开始4秒checkConnectionTimer。 每4秒计时器到期时,如果客户端套接字状态!= AbstractSocket ::连接或连接,它尝试与clientSocket-> connectToHost连接
当插座信号“连接()”,它开始5秒的服务器心跳定时器。 服务器应该发送一个字节心跳消息每4秒它的客户。 当我心跳(或readyRead暗示任何类型的消息()),我重新启动心跳计时器。 所以,如果心跳计时器不断有超时,我认为连接将下降并呼吁clientSocket->disconnectFromHost ();
这是工作非常好各种不同类型的断开的服务器上,优雅或以其他方式(猛拉电缆)。 是的,它需要自定义心跳类型的东西,但在一天结束时它是最快捷,最便携的解决方案。
我并不热衷于在内核设置KEEPALIVE超时。 这样,其更便于携带。 在构造函数:
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readMessage()));
connect(clientSocket, SIGNAL(connected()), this, SLOT(socketConnected()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
connect(heartbeatTimer, SIGNAL(timeout()), this, SLOT(serverTimeout()));
...
// Other Methods
void NetworkClient::checkConnection(){
if (clientSocket->state() != QAbstractSocket::ConnectedState &&
clientSocket->state() != QAbstractSocket::ConnectingState){
connectSocketToHost(clientSocket, hostAddress, port);
}
}
void NetworkClient::readMessage()
{
// Restart the timer by calling start.
heartbeatTimer->start(5000);
//Read the data from the socket
...
}
void NetworkClient::socketConnected (){
heartbeatTimer->start(5000);
}
void NetworkClient::socketDisconnected (){
prioResponseTimer->stop();
}
void NetworkClient::serverTimeout () {
clientSocket->disconnectFromHost();
}
试试这个信号槽连接:
connect(this, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onStateChanged(QAbstractSocket::SocketState)));
在插槽实现:
void TCPWorker::onStateChanged(QAbstractSocket::SocketState socketState ){
qDebug()<< "|GSTCPWorkerThread::onStateChanged|"<<socketState;
...}
我有同样的问题,而是你的问题(总是连接),我有延时4-5秒接收断开信号,unplugget以太网线后。
仍然在寻找解决方案,后期的答案,如果找到。
尝试在Qt的我的客户的模板:
class Client: public QTcpSocket {
Q_OBJECT
public:
Client(const QHostAddress&, int port, QObject* parent= 0);
~Client();
void Client::sendMessage(const QString& );
private slots:
void readyRead();
void connected();
public slots:
void doConnect();
};
CPP的:
void Client::readyRead() {
// if you need to read the answer of server..
while (this->canReadLine()) {
}
}
void Client::doConnect() {
this->connectToHost(ip_, port_);
qDebug() << " INFO : " << QDateTime::currentDateTime()
<< " : CONNESSIONE...";
}
void Client::connected() {
qDebug() << " INFO : " << QDateTime::currentDateTime() << " : CONNESSO a "
<< ip_ << " e PORTA " << port_;
//do stuff if you need
}
void Client::sendMessage(const QString& message) {
this->write(message.toUtf8());
this->write("\n"); //every message ends with a new line
}
我省略了一些代码,构造和插槽连接..尝试与这一点,如果它不将不起作用,也许有不对的服务器端..