Server服务器端
QT版本5.6.1
- 界面设计
- 工程文件:
添加 network 模块
- 头文件引入TcpServer类和TcpSocket :QTcpServer和QTcpSocket
cpp
#include <QTcpServer>
#include <QTcpSocket>
- 创建server对象并实例化:
cpp
/*h文件中*/
QTcpServer *tcpServer;
/*cpp文件中*/
tcpServer = new QTcpServer(this);
使用This作为父对象,方便结束进程生命周期时,释放内存空间
- 构建槽函数:
cpp
private slots:
void newConnection_Slot();
void readyRead_Slot();
void stateChanged_Slot(QAbstractSocket::SocketState);
注 : 在C++的类中声明函数时可以不写参数名只写参数类型,但是,在实现时必须写出参数名。例如 : void stateChanged_Slot(QAbstractSocket::SocketState);形参是枚举类型,但是没有具体的形参名
newConnection_Slot: 当有客户端的socket建立连接时,tcpserver会发送newConnection()信号,触发连接槽函数,用于创建一个新的socket与客户端对接
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConnection_Slot()));
cpp
void Widget::newConnection_Slot()
{
ui->recvEdit->append("Have a clinet connection");
QTcpSocket *temptcpSocket = tcpServer->nextPendingConnection();
connect(temptcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Slot()));
connect(temptcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(stateChanged_Slot(QAbstractSocket::SocketState)));
// 客户端的ip地址
QString ipaddr = temptcpSocket->peerAddress().toString();
quint16 port = temptcpSocket->peerPort();
// 打印客户端连接的端口信息
ui->recvEdit->append("服务端:客户端的ip地址:" + ipaddr);
ui->recvEdit->append("服务端:客户端的端口:" + QString::number(port));
}
readyRead_Slot : 当有客户端的socket发送数据过来,服务端用来与客户端对接的socket发送数据可读信号readyRead(),触发槽函数,读数据
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Slot()));
cpp
void Widget::readyRead_Slot()
{
//sender()返回触发该函数的信号所属者的指针
QTcpSocket *tcpSocket = (QTcpSocket *)sender();
QString buf;
buf = tcpSocket->readAll();
ui->recvEdit->append(buf);
}
stateChanged_Slot(QAbstractSocket::SocketState) : 当服务端的socket与客户端断开连接时,会发送连接状态改变信号,触发槽函数
cpp
void Widget::stateChanged_Slot(QAbstractSocket::SocketState socketState)
{
QTcpSocket *tcpSocket = (QTcpSocket *)sender();
switch(socketState){
case QAbstractSocket::UnconnectedState:
ui->recvEdit->append("connection end");
tcpSocket->deleteLater();
break;
default:
break;
}
}
- ui按键槽函数:
cpp
void on_openBt_clicked();
void on_colseBt_clicked();
void on_sendBt_clicked();
void on_openBt_clicked() : 打开服务端
cpp
void Widget::on_openBt_clicked()
{
//判断输入的端口号是否为空,为空则直接返回
if(ui->portEdit->text().isEmpty()){
ui->recvEdit->append("port is empty!!");
return;
}
//启动监听,QHostAddress::Any表示所有IP地址
tcpServer->listen(QHostAddress::Any, ui->portEdit->text().toUInt());
ui->recvEdit->append("open successful");
ui->openBt->setEnabled(false);
ui->colseBt->setEnabled(true);
}
on_colseBt_clicked : 关闭客户端
cpp
void Widget::on_colseBt_clicked()
{
//关闭tcpserver知识关闭的监听功能,不会有新的客户端建立连接,但是已经建立连接的socket仍然可以通信
tcpServer->close();
ui->recvEdit->append("close successful");
ui->openBt->setEnabled(true);
ui->colseBt->setEnabled(false);
}
on_sendBt_clicked : 发送数据
cpp
void Widget::on_sendBt_clicked()
{
//返回server端与客户端建立连接的所有socket
QList <QTcpSocket *> socketList = tcpServer->findChildren<QTcpSocket *>();
qDebug() << "tcpSocket 数量:" << socketList.count() << endl;
if (socketList.count() == 0) {
ui->recvEdit->append("当前没有客户端连接,请先与客户端连接!");
return;
}
foreach (QTcpSocket *tmpTcpSocket, socketList) {
// 服务端向每个客户端发送消息
tmpTcpSocket->write(ui->sendEdit->text().toUtf8());
}
ui->recvEdit->append("服务端:" + ui->sendEdit->text());
}
工程源码:
widget.h:
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void state_Slot(QAbstractSocket::SocketState);
private:
Ui::Widget *ui;
QTcpServer *tcpServer;
private slots:
void newConnection_Slot();
void readyRead_Slot();
void stateChanged_Slot(QAbstractSocket::SocketState);
void on_openBt_clicked();
void on_colseBt_clicked();
void on_sendBt_clicked();
};
#endif // WIDGET_H
widget.cpp
cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
tcpServer = new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConnection_Slot()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::newConnection_Slot()
{
ui->recvEdit->append("Have a clinet connection");
QTcpSocket *temptcpSocket = tcpServer->nextPendingConnection();
connect(temptcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_Slot()));
connect(temptcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(stateChanged_Slot(QAbstractSocket::SocketState)));
// 客户端的ip地址
QString ipaddr = temptcpSocket->peerAddress().toString();
quint16 port = temptcpSocket->peerPort();
// 打印客户端连接的端口信息
ui->recvEdit->append("服务端:客户端的ip地址:" + ipaddr);
ui->recvEdit->append("服务端:客户端的端口:" + QString::number(port));
}
void Widget::readyRead_Slot()
{
//sender()返回触发该函数的信号所属者的指针
QTcpSocket *tcpSocket = (QTcpSocket *)sender();
QString buf;
buf = tcpSocket->readAll();
ui->recvEdit->append(buf);
}
void Widget::stateChanged_Slot(QAbstractSocket::SocketState socketState)
{
QTcpSocket *tcpSocket = (QTcpSocket *)sender();
switch(socketState){
case QAbstractSocket::UnconnectedState:
ui->recvEdit->append("connection end");
tcpSocket->deleteLater();
break;
default:
break;
}
}
void Widget::on_openBt_clicked()
{
if(ui->portEdit->text().isEmpty()){
ui->recvEdit->append("port is empty!!");
return;
}
tcpServer->listen(QHostAddress::Any, ui->portEdit->text().toUInt());
ui->recvEdit->append("open successful");
ui->openBt->setEnabled(false);
ui->colseBt->setEnabled(true);
}
void Widget::on_colseBt_clicked()
{
tcpServer->close();
ui->recvEdit->append("close successful");
ui->openBt->setEnabled(true);
ui->colseBt->setEnabled(false);
}
void Widget::on_sendBt_clicked()
{
//返回server端与客户端建立连接的所有socket
QList <QTcpSocket *> socketList = tcpServer->findChildren<QTcpSocket *>();
qDebug() << "tcpSocket 数量:" << socketList.count() << endl;
if (socketList.count() == 0) {
ui->recvEdit->append("当前没有客户端连接,请先与客户端连接!");
return;
}
foreach (QTcpSocket *tmpTcpSocket, socketList) {
// 服务端向每个客户端发送消息
tmpTcpSocket->write(ui->sendEdit->text().toUtf8());
}
ui->recvEdit->append("服务端:" + ui->sendEdit->text());
}