Qt下应用QTcpServer与QTcpSocket实现Tcp控制


   很多情形下,我们在应用程序的最外层都使用TCP作为可靠控制,下面,我就总结一下我在项目中使用QTcpServer与QTcpSocket的一些心得和体会。

    服务端TCP程序可以利用QTcpServer,首先我们声名QTcpServer *对象(注意:QTcpServer占用的网络资源需要我们手动释放,任何我们程序可能异常退出或正常结束的地方QTcpServer *最后都要close())
    注意我们的服务端要一直监听客户端
  tcpPort=8888;
    tcpServer=new QTcpServer();
    if(!tcpServer->listen(QHostAddress::Any,tcpPort))
    {
        tcpServer->close();
        emit MSG(QString("listen erro"));
    }
    connect(tcpServer,&QTcpServer::newConnection,this,&TcpServer::onNewConnection);
    在新连接对应的槽里我们把
  QTcpSocket *newpeer=tcpServer->nextPendingConnection();
  这个新连接的socket指针取下来,进行操作,当执行newpeer->write(QByterArray &MSG)即服务器向此peer发送数据;当执行QByterArray MSG=newpeer->write()即服务器读此peer的数据,所有信息的传递均是对QTcpSocket的操作,并要要对每一个socket的disconnected连接deleteLater槽防止内存泄漏。
  说到此处,就牵涉到了QString 与QByterArray的转换,因为我们平时处理消息大多是对QSring进行处理:
  QString->QByterArray(只有英文(Latin)时):
newpeer->write(QString("Server").toLatin1());
  QByterArray-> QString:
QTextCodec *tc= QTextCodec::codecForName("UTF-8");
QString str=tc->toUnicode((QByteArray)
rawreply)
下面的代码抽取自 我的服务端程序
#ifndef TCPSERVER_H
#define TCPSERVER_H

#include <QObject>
#include<QTcpServer>
#include<QAbstractSocket>
class TcpServer : public QObject
{
    Q_OBJECT
public:
    explicit TcpServer(QObject *parent = 0);
    ~TcpServer();
private:
    int nb_peer;//总共的小伙伴数目,用于确定client->index的取值
    QTcpServer *tcpServer;
public slots:
    void ReadDataFromSocket();
    void onNewConnection();
    void onDisConnection();
    void processMSG(QString &MSG);
  // void processAddedClient(QTcpSocket *client);
};
#include "tcpserver.h"

TcpServer::TcpServer(QObject *parent) :
    QObject(parent),nb_peer(0)
{
    tcpPort=8888;
    tcpServer=new QTcpServer();
    if(!tcpServer->listen(QHostAddress::Any,tcpPort))
    {
        tcpServer->close();
        emit MSG(QString("listen erro"));
    }
    peerList = QList<client>();
    connect(tcpServer,&QTcpServer::newConnection,this,&TcpServer::onNewConnection);
}
void TcpServer::onNewConnection()
{

    QTcpSocket *newpeer=tcpServer->nextPendingConnection();
    //写入验证


    connect(newpeer,SIGNAL(readyRead()),this,SLOT(ReadDataFromSocket()));
    connect(newpeer,SIGNAL(disconnected()),newpeer,SLOT(deleteLater()));
    connect(newpeer,SIGNAL(disconnected()),this,SLOT(onDisConnection()));
    newpeer->write(QString("Server").toLatin1());
    newpeer->flush();
}
#include<QTextCodec>
#include<iterator>
void TcpServer::ReadDataFromSocket()
{
    QByteArray rawreply= static_cast<QTcpSocket*>(sender())->readAll();
    QTextCodec *tc= QTextCodec::codecForName("UTF-8");
    client beingCheckedClient;
    beingCheckedClient.index=nb_peer;
    beingCheckedClient.socket=static_cast<QTcpSocket*>(sender());
    if(tc->toUnicode(rawreply)!=QString("Client")&& !peerList.contains(beingCheckedClient
                ))
    {
        //写入信息
        //emit ChangeLabel(QString(rawreply));
        static_cast<QTcpSocket*>(sender())->write(
                    QString("connect time out! disconnecting...").toLatin1());
        static_cast<QTcpSocket*>(sender())->flush();
        static_cast<QTcpSocket*>(sender())->disconnectFromHost();
        return ;
    }
}
TcpServer::~TcpServer()
{
    tcpServer->close();

}

客户端就没什么好说的了,也是对QTcpSocket的一些操作,但是注意要在程序开始时对服务器发起连接:
    tcpsocket=new QTcpSocket();
    tcpsocket->abort();
    tcpsocket->connectToHost(("127.0.0.1"),8888);
一些问题:很多大牛可能会说,我直接使用write read接受字符串命令可能并不安全,在实际应用中我发现,低频率的收发数据这种方法非常可靠,但是在很多客户端同时连接时,进行回调消息验证时,会出现信息残缺,我的解决方案是使用延时策略,但是这并不是长久之计。
按照官方给的例子:
服务端发送数据:
void Server::sendFortune()
{
    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_0);
  out << (quint16)0;
    out << fortunes.at(qrand() % fortunes.size());
    out.device()->seek(0);
    out << (quint16)(block.size() - sizeof(quint16));
 QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
    connect(clientConnection, SIGNAL(disconnected()),
            clientConnection, SLOT(deleteLater()));
  clientConnection->write(block);
    clientConnection->disconnectFromHost();
}

客户端接受数据:
void Client::readFortune()
{
    QDataStream in(tcpSocket);
    in.setVersion(QDataStream::Qt_4_0);

    if (blockSize == 0) {
        if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
            return;

        in >> blockSize;
    }

    if (tcpSocket->bytesAvailable() < blockSize)
        return;
QString nextFortune;
    in >> nextFortune;

    if (nextFortune == currentFortune) {
        QTimer::singleShot(0, this, SLOT(requestNewFortune()));
        return;
    }

    currentFortune = nextFortune;
    statusLabel->setText(currentFortune);
    getFortuneButton->setEnabled(true);
}

缺点是每收发一回合信息,都要重连一次。

Ubuntu 环境下Gtk与QT编译环境安装与配置

Linux系统下QT环境搭建

Ubuntu下QT控制台程序无法运行的解决方案以及XTerm的配置方法

Ubuntu 10.04下QT4.7.4移植详解

Ubuntu 14.04下安装部署Qt5开发环境

Qt 的详细介绍:请点这里
Qt 的下载地址:请点这里

本文永久更新链接地址

相关内容

    暂无相关文章