专业的网站建设公司哪家好,学建设网站去哪里学,网站登录界面模板,用什么软件做网站最快一、基本原理及流程
1#xff09;知识回顾#xff08;C语言中的TCP流程#xff09; 2#xff09;QT中的服务器端/客户端的操作流程 二、代码实现
1#xff09;服务器
.ui .pro 在pro文件中添加network库 .h
#ifndef WIDGET_H
#define WIDGET_H#include QWidget知识回顾C语言中的TCP流程 2QT中的服务器端/客户端的操作流程 二、代码实现
1服务器
.ui .pro 在pro文件中添加network库 .h
#ifndef WIDGET_H
#define WIDGET_H#include QWidget
#include QTcpServer //服务器头文件
#include QTcpSocket //客户端头文件
#include QList //链表头文件用于存放客户端容器
#include QMessageBox //消息对话框类
#include QDebugQT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent nullptr);~Widget();private slots:void on_startBtn_clicked(); //自定义启动按钮的槽函数void newConnection_slot(); //自定义处理newConnection信号的槽函数void readyRead_slot(); //自定义处理reayRead信号的槽函数private:Ui::Widget *ui;//定义服务器指针QTcpServer *server;//定义客户端指针链表容器QListQTcpSocket * clientList;};
#endif // WIDGET_H.main
#include widget.h#include QApplicationint main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}.cpp
#include widget.h
#include ui_widget.hWidget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui-setupUi(this);//在构造函数中给服务器指针实例化对象server new QTcpServer(this); //此时就创建一个服务器了
}Widget::~Widget()
{delete ui;
}//启动服务器按钮对应的槽函数
void Widget::on_startBtn_clicked()
{//1、获取ui界面上的端口号quint16 port ui-portEdit-text().toUInt();//2、将服务器设置成监听状态//bool QTcpServer::listen(const QHostAddress address QHostAddress::Any, quint16 port 0)//参数1要监听的主机地址如果是any表示监听所有主机地址也可以给特定的主机地址进行监听//参数2通过指定的端口号进行访问服务器如果是0表示由服务器自动分配如果非0则表示指定端口号 (quint16 unsignal int)//返回值成功返回真失败返回假if(!server-listen(QHostAddress::Any,port)){QMessageBox::critical(this,失败,服务器启动失败); //默认按钮为okreturn;}else{QMessageBox::information(this,成功,服务器启动成功);}//此时表明服务器启动成功并对客户端连接进行监听//如果有客户端向服务器发来连接请求那么该服务器就会自动发射一个newConnection//我们可以将该信号连接到对应的槽函数中处理相关逻辑connect(server,QTcpServer::newConnection,this,Widget::newConnection_slot);
}//处理newConnection信号的槽函数实现
void Widget::newConnection_slot()
{qDebug()有新的客户端发来连接请求了;//获取最新连接的客户端套接字//函数原型[virtual] QTcpSocket *QTcpServer::nextPendingConnection()//参数无//返回值最新连接客户端套接字的指针QTcpSocket *s server-nextPendingConnection();//将获取的套接字存放到客户端容器中clientList.push_back(s);//此时客户端就和服务器建立起联系了//如果该套接字有数据向服务器发送过来那么该套接字就会自动发射一个ready read信号//我们可以将该信号连接到自定义的槽函数中然后处理相关逻辑connect(s, QTcpSocket::readyRead, this, Widget::readyRead_slot);
}//关于readyRead信号对应槽函数的实现
void Widget::readyRead_slot()
{//删除客户端链表中的无效客户端套接字for(int i0;iclientList.count();i){//判断套接字的状态//函数原型SocketState state() const;//功能返回客户端套接字的状态//参数无//返回值客户端的状态如果结果为0表示未连接if(clientList[i]-state() 0){clientList.removeAt(i); //将下标为i的客户端的套接字从链表中移除}}//遍历所有客户端查看是哪个客户端发来数据for(int i0 ; iclientList.count() ; i){//函数原型qint64 bytesAvailable() const override;//功能返回当前客户端套接字中的可读数据字节个数//参数无//返回值当前客户端待读的字节数如果该数据为0表示无待读数据if(clientList[i]-bytesAvailable() ! 0){//读取当前客户端的相关数据并返回一个字节数组//参数无//返回值数据的字节数组QByteArray msg clientList[i]-readAll();//将数据展示到ui界面上ui-msgList-addItem(QString::fromLocal8Bit(msg));//将接收到的该消息发送给所有客户端for(int j 0 ; jclientList.count() ; j){clientList[j]-write(msg);}}}
} 2客户端
.ui .pro 在pro文件中添加network库 .h
#ifndef WIDGET_H
#define WIDGET_H#include QWidget
#include QTcpSocket //客户端头文件
#include QMessageBox //QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent nullptr);~Widget();private slots:void on_connectBtn_clicked();void connected_slot(); //自定义处理connected信号的槽函数void readyRead_slot(); //自定义处理readyRead信号的槽函数void on_sendBtn_clicked(); //自定义处理发送按钮的槽函数void disconnect_slot(); //自定义处理disconnectFromHost信号的函数void on_disConnectBtn_clicked();private:Ui::Widget *ui;//定义一个客户端指针QTcpSocket *socket;//用户名QString userName; //由于多个槽函数需要用到该用户名所以将用户名设置为类的私有成员};
#endif // WIDGET_H.main
#include widget.h#include QApplicationint main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}.cpp
#include widget.h
#include ui_widget.hWidget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui-setupUi(this);//将发送区域的组件设置为不可用状态ui-sendBtn-setEnabled(false);ui-msgEdit-setEnabled(false);ui-disConnectBtn-setEnabled(false);//给客户端指针实例化空间socket new QTcpSocket(this);//如果连接服务器成功该客户端就会发射一个connected的信号//我们可以将该信号连接到自定义的槽函数中处理相关逻辑//由于该连接只需要连接一次所以写在构造函数中即可connect(socket,QTcpSocket::connected,this,Widget::connected_slot);//客户端与服务器连接成功后如果服务器向客户端发来数据那么该客户端就会自动发送一个readyRead信号//我们只需要connect(socket,QTcpSocket::readyRead,this,Widget::readyRead_slot);//当客户端与服务器断开连接后该客户端就会发射一个disconnected的信号//我们可以将该信号与自定义的槽函数连接//由于只需要连接一次所以将该连接写到构造函数中即可//点击断开连接按钮connect(socket,QTcpSocket::disconnected,this,Widget::disconnect_slot);
}Widget::~Widget()
{delete ui;
}//连接服务器按钮对应的槽函数
void Widget::on_connectBtn_clicked()
{//获取ui界面的信息userName ui-userNameEdit-text(); //获取用户名QString hostName ui-ipEdit-text(); //获取主机地址quint16 port ui-portEidt-text().toUInt(); //获取端口号//调用函数连接到主机//[virtual] void QAbstractSocket::connectToHost(const QString hostName, quint16 port)//参数1服务器的主机地址//参数2端口号//返回值无socket-connectToHost(hostName,port);//如果连接服务器成功该客户端就会发射一个connected的信号//我们可以将该信号连接到自定义的槽函数中处理相关逻辑//由于该连接只需要连接一次所以写在构造函数中即可
}//关于处理connected信号的槽函数的定义
void Widget::connected_slot()
{QMessageBox::information(this,成功,连接服务器成功);//设置组件的可用状态ui-msgEdit-setEnabled(true);ui-sendBtn-setEnabled(true);ui-disConnectBtn-setEnabled(true);ui-userNameEdit-setEnabled(false);ui-ipEdit-setEnabled(false);ui-portEidt-setEnabled(false);ui-connectBtn-setEnabled(false);//顺便向服务器发送一条消息说***进入聊天室QString msg userName 进入聊天室;socket-write(msg.toLocal8Bit());
}//关于readyRead信号对应槽函数的实现
void Widget::readyRead_slot()
{//读取该客户端中的数据QByteArray msg socket-readAll();//将数据展示在ui界面ui-msgList-addItem(QString::fromLocal8Bit(msg));}//发送按钮对应的槽函数
void Widget::on_sendBtn_clicked()
{//获取ui界面中的编辑的文本内容QString m ui-msgEdit-text();//整合要发送的消息QString msg userName m;socket-write(msg.toLocal8Bit());//将消息编辑器中的内容清空ui-msgEdit-clear();
}//断开服务器按钮对应的槽函数
void Widget::on_disConnectBtn_clicked()
{//准备要发送的信息QString msg userName 离开聊天室;socket-write(msg.toLocal8Bit());//调用成员函数disconnectFromHost//函数原型virtual void disconnectFromHost();//功能断开客户端与服务器的连接//参数无socket-disconnectFromHost();//当客户端与服务器断开连接后该客户端就会发射一个disconnected的信号//我们可以将该信号与自定义的槽函数连接//由于只需要连接一次所以将该连接写到构造函数中即可}//关于disconnectFromHost信号对应槽函数的实现
void Widget::disconnect_slot()
{QMessageBox::information(this,退出,断开成功);//设置组件的可用状态ui-msgEdit-setEnabled(false);ui-sendBtn-setEnabled(false);ui-disConnectBtn-setEnabled(false);ui-userNameEdit-setEnabled(true);ui-ipEdit-setEnabled(true);ui-portEidt-setEnabled(true);ui-connectBtn-setEnabled(true);
}三、效果展示