QT学习 网络tcp+udp

准备工作

  • PRO
QT       += network

  • 头文件
#include  

#include  

#include  

tcp客户端只需要QTcpSocket。

tcp服务端,需要QTcpServer 来监听,QTcpSocket来管理客户端连接

udp需要QUdpSocket

TCP 客户端

打开 

   QTcpSocket m_handle;

   //连接信号槽,接收消息

   QObject::connect(&m_handle, &QTcpSocket::readyRead, this, &XXX::slotReadyRead);
   // 连接断开响应

   QObject::connect(&m_handle, &QTcpSocket::disconnected, this, &XXX::slotDisconnected);

   //套接字错误响应
    QObject::connect(&m_handle, SIGNAL(error(QAbstractSocket::SocketError)),

                     this, SLOT(slotError(QAbstractSocket::SocketError)));


   //连接服务器

    m_handle.connectToHost(IP, PORT);


   //等待连接成功

   if(!m_handle.waitForConnected(1000))

   {

       qDebug() << "Connection failed!";

   }

   qDebug() << "Connect successfully!";

关闭

m_handle.disconnectFromHost();

QObject::disconnect(&m_handle, 0, 0, 0);

发送

    QByteArray sendData;

    qint64 written = m_handle.write(sendData);

    m_handle.flush();

接收槽函数

void XXX::slotReadyRead()

{

    QByteArray buffer = m_handle.readAll();
    qDebug() << buffer;

   // ……

}

断开槽函数
 

void XXX::slotDisconnected()

{

   //取消已有的连接

    m_handle.abort();

   qDebug() << "Disconnected!";

}

出错槽函数

void XXX::slotError(QAbstractSocket::SocketError)

{

   //取消已有的连接

    m_handle.abort();

}

tcp服务端

比客户端多了  客户端监听 以及  已连接客户端的维护

一般的实现形式

启动监听


 

   QTcpServer m_server;


   if (m_server.listen(QHostAddress::Any, port)) {

       // 连接信号槽,当有新的客户端连接时响应

       QObject::connect(&m_server, &QTcpServer::signal_incomingConnection, this, &XXX::slot_incomingConnection);

       qDebug() << "Server listenning!";

   }

   else {

       qDebug() << m_server.errorString();

   }
   

客户端连接槽函数

QList m_list;

void XXX::slot_incomingConnection() //响应客户端连接请求的函数

{

   //获取连接的客户端

    QTcpSocket *client = tcpServer.nextPendingConnection();

    m_list.append(client );

   //连接信号槽,用于接收客户端消息

   connect(client , SIGNAL(readyRead()), this, SLOT(slot_readyRead()));

}

客户端接收槽函数,可以发现无法直接知道是哪个客户端发来的消息

void xxx::slot_readyRead()

{
// 遍历所有客户端,检查谁有待读取的消息

   for (int i = 0; i < m_list.size(); i++)

   {


       if (m_list.at(i)->bytesAvailable())

       {

           //读取消息并保存

            QByteArray buffer = m_list.at(i)->readAll();

           qDebug() << buffer;

       }

   }

}

发送

void XXX::send(int i, const QByteArray &buf)

{

        m_list.at(i)->write(buf);

}

维护客户端连接情况

       // 当前连接数
       unsigned int size = m_list.size();

       //删除断开的客户端

       for (unsigned int i = 0; i < size ; i++)

       {

           // 判断当前客户端是否未连接

           if (m_list.at(i)->state() == QAbstractSocket::UnconnectedState)

           {

                m_list.removeAt(i);

               --i;

               --size ;

           }

       }

派生类形式

由于正常的使用qtcpsocket,当接收到消息或者当断开连接时无法知道是哪个客户端发起的。为了解决这个问题,可以自QTcpSocket派生子类。

qtcpserver类的正常使用,需nextPendingConnection获取新连接的客户端,这个在多个客户端同时发起时可能存在问题。也可以自QTcpServer派生子类来解决。

具体操作是

1、在qtcpserver派生类中增加一个信号(包含描述符和套接字),并在incomingConnection重载函数中emit。

2、在qtcpsocket派生类中改写信号(增加描述符和套接字),绑定原始信号(readyRead、disconnected等),在槽函数中emit改写的信号。

由于信号都带上了描述符和socket,绑定的槽函数直接就能知道发起的客户端描述符和套接字。

UDP

udp比较简单,绑定端口,就可以收发了。

打开

QUdpSocket m_handle;


    m_handle.bind(port,QUdpSocket::ShareAddress);
    // 绑定槽函数,接收消息

   connect(&m_handle,&QUdpSocket::readyRead,this,&XXX::slot_readyRead);

   qDebug() << "Bind successfully!";

发送

QByteArray sendData;


   

    qint64 written = m_handle.writeDatagram(sendData.data(),

                                            sendData.size(),

                                           QHostAddress(ip),

                                            port);


    m_handle.flush();

接收槽函数

void XXX::slot_readyRead()

{

    QByteArray buffer;


   //有未处理的消息

   if(m_handle.hasPendingDatagrams()){

        buffer.resize(m_handle.pendingDatagramSize());

        m_handle.readDatagram(buffer.data(),buffer.size());
        qDebug() << buffer;
        //……

   }

}

你可能感兴趣的:(qt,qt,学习,网络)