目录
前言:
在Qt的服务端上,不单单会用到服务端本身的API,对连接上来的客户端,也需要进行数据交互,也要用到一些收发包相关的API操作;
1、相关的库和类
Qt下使用tcp协议,需要在工程的pro文件中添加:
QT += network
需要添加network网络库之后,才可以使用对应的类
客户端的类头文件:
#include <QTcpSocket>
服务端的类头文件:
#include <QTcpServer>
2、服务端常用API
qt的服务端套接字把常见的bind和listen合并成一个listen函数了:
bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
监听完成之后,就得考虑接受客户端连接了
会有如下这几个API:
// 等待客户端连接 bool waitForNewConnection(int msec = 0, bool *timedOut = Q_NULLPTR); // 判断是否有客户端连接过来 virtual bool hasPendingConnections() const; // 用得最多还是这个nextPendingConnection函数,可以直接拿到客户端套接字 virtual QTcpSocket *nextPendingConnection();
当前,Qt是基于信号槽的,而且默认socket是异步的,所以也会有一个客户端连接触发的信号
void newConnection(); // 当有客户连接之后,会自动触发该信号
当有客户端连接过来之后,就会自动触发该信号,此时只需要写一个槽函数来和该信号关联即可
拿到新的客户端连接,拿到该连接套接字之后,就可以和客户端进行数据交互了
如以下代码:
// connectSlot 为自定义槽函数 connect(m_server,SIGNAL(newConnection()),this,SLOT(connectSlot()));
自定义槽函数:
void ServerMainWindow::connectSlot() { QTcpSocket *client = m_server->nextPendingConnection(); qDebug()<<client; QByteArray buffer = "欢迎来到码蚁软件服务器。"; qDebug()<<client->write(buffer); }
当然,还可以专门写一个槽来和已连接的客户端进行交互
void ServerMainWindow::clientSlot() { QTcpSocket * client = static_cast<QTcpSocket *>(sender()); QByteArray buffer = client->readAll(); qDebug()<<buffer.data(); }
当然,加了槽之后,前面的connectSlot代码可以稍微改动一下:
void ServerMainWindow::connectSlot() { QTcpSocket *client = m_server->nextPendingConnection(); qDebug()<<client; if(!client->isValid()) return; m_clients[client] = HEART_CHECK_TIMES; // 用于心跳检测的map // 关联与客户端通信的自定义收包槽 connect(client,SIGNAL(readyRead()),this,SLOT(clientSlot())); QByteArray buffer = "欢迎来到码蚁软件服务器。"; qDebug()<<client->write(buffer); }
OK,这样写了之后,就可以和前面那一篇的客户端代码进行交互测试了,
找不到前一篇的话,可以点传送门过去看看哈:
Qt TCP相关的一些整理:客户端常见操作 socket 通信 network-CSDN博客
好了,下一篇将进行心跳检测的处理,敬请期待。【已更】
C++ Qt TCP的心跳检测机制,断线重连技术,应用层代码重新实现-CSDN博客
核心代码呈上:
完整代码下载地址:点我下载
头文件:
#ifndef SERVERMAINWINDOW_H
#define SERVERMAINWINDOW_H
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
namespace Ui {
class ServerMainWindow;
}
class ServerMainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit ServerMainWindow(QWidget *parent = 0);
~ServerMainWindow();
private slots:
void connectSlot(); // 处理连接的槽
void clientSlot(); // 与客户端交互的槽
private:
Ui::ServerMainWindow *ui;
QTcpServer *m_server;
QMap<QTcpSocket*,int> m_clients;
};
#endif // SERVERMAINWINDOW_H
源文件:
#include "servermainwindow.h"
#include "ui_servermainwindow.h"
#include <QDebug>
#define HEART_CHECK_TIMES 6
ServerMainWindow::ServerMainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::ServerMainWindow)
{
ui->setupUi(this);
m_server = new QTcpServer(this);
if(m_server->listen(QHostAddress::Any,8898)){
qDebug()<<"listen ok";
connect(m_server,SIGNAL(newConnection()),this,SLOT(connectSlot()));
}else{
qDebug()<<"listen fail"<<m_server->errorString();
}
}
ServerMainWindow::~ServerMainWindow()
{
delete ui;
}
void ServerMainWindow::connectSlot()
{
QTcpSocket *client = m_server->nextPendingConnection();
qDebug()<<client;
if(!client->isValid()) return;
m_clients[client] = HEART_CHECK_TIMES; // 用于心跳检测的map
// 关联与客户端通信的自定义收包槽
connect(client,SIGNAL(readyRead()),this,SLOT(clientSlot()));
QByteArray buffer = "欢迎来到码蚁软件服务器。";
qDebug()<<client->write(buffer);
}
void ServerMainWindow::clientSlot()
{
QTcpSocket * client = static_cast<QTcpSocket *>(sender());
QByteArray buffer = client->readAll();
qDebug()<<buffer.data();
}
最后,顺便把最终的效果呈现以下。