700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Qt TCP/IP(多客户端连接服务器)多个客户端同时登陆的聊天室示例

Qt TCP/IP(多客户端连接服务器)多个客户端同时登陆的聊天室示例

时间:2020-08-09 02:34:53

相关推荐

Qt TCP/IP(多客户端连接服务器)多个客户端同时登陆的聊天室示例

一、TCP和UDP的区别

这里我会用一个表格来显示这两者的区别

二、incomingConnection函数

这个函数和之前讲过的newConnection信号功能差不多,只要有新的连接出现,就会自动调用这个函数。

然后我们只需在这个函数中新建一个QTcpSocket对象,并且将这个套接字指定为这个函数的参数socketDescriptor,然后将这个套接字存放到套接字列表中就可以实现多个客户端同时登陆了。

这里我们简单看一下这个函数里的内容

1 void Server::incomingConnection(int socketDescriptor)2 {3TcpClientSocket *tcpclientsocket = new TcpClientSocket(this);//只要有新的连接就生成一个新的通信套接字4//将新创建的通信套接字描述符指定为参数socketdescriptor5tcpclientsocket->setSocketDescriptor(socketDescriptor);6 7//将这个套接字加入客户端套接字列表中8tcpclientsocketlist.append(tcpclientsocket);9 }

Server这个类是继承于QTcpServer类的,所以我们需要在Server类中重写incomingConnection函数。

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

三、多个客户端同时登陆的小聊天室示例。

首先说明一下这个小示例的功能,当有一个客户端进入聊天室的时候,会向服务器发送一个信息,告诉服务器这个账号进入了聊天室, 然后服务器会在界面中显示哪个账号进入了聊天室,并且服务器会向所有的客户端发送消息,告诉所有客户端有哪个账号进入了聊天室。某个账号发送信息的时候也是如此,服务器会将收到的信息发送给所有的客户端。

如果需要实现网络通信,就必须在pro文件中加入 QT += network

服务器端

在服务器端需要添加三个类,一个类用来创建界面,一个类用来监听,这个类的基类是QTcpServer,最后一个类用来通信,通信的类的基类是QTcpSocket类。

1、用来创建界面的Tcpserver类

1 #ifndef TCPSERVER_H2 #define TCPSERVER_H3 4 #include <QWidget>5 #include "server.h"6 7 namespace Ui {8 class TcpServer;9 }10 11 class TcpServer : public QWidget12 {13Q_OBJECT14 15 public:16explicit TcpServer(QWidget *parent = 0);17~TcpServer();18 19 private:20Ui::TcpServer *ui;21int port;22Server *server;23 24 protected slots:25void slotupdateserver(QString, int);//接收到server发过来的信号就更新界面的信息26 27 28 private slots:29void on_pushButtonCreateChattingRoom_clicked();30 };31 32 #endif // TCPSERVER_H

1 #include "tcpserver.h"2 #include "ui_tcpserver.h"3 4 5 TcpServer::TcpServer(QWidget *parent) :6QWidget(parent),7ui(new Ui::TcpServer)8 {9ui->setupUi(this);10port = 8888;11 12 }13 14 TcpServer::~TcpServer()15 {16delete ui;17 }18 19 void TcpServer::on_pushButtonCreateChattingRoom_clicked()20 {21server = new Server(this, port);22connect(server, &Server::updateserver, this, &TcpServer::slotupdateserver);23ui->pushButtonCreateChattingRoom->setEnabled(false);24 }25 26 void TcpServer::slotupdateserver(QString msg, int length)27 {28ui->textEdit->append(msg);29 }

2、用来监听的类Server

1 #ifndef SERVER_H2 #define SERVER_H3 4 #include <QTcpServer>5 #include <QObject>6 #include <QList>7 #include "tcpclientsocket.h"8 9 class Server : public QTcpServer10 {11Q_OBJECT //为了实现信号和槽的通信12 public:13Server(QObject *parent = 0, int port = 0);14QList<TcpClientSocket*> tcpclientsocketlist;15 protected:16void incomingConnection(int socketDescriptor);//只要出现一个新的连接,就会自动调用这个函数17 protected slots:18void sliotupdateserver(QString, int);//用来处理tcpclient发过来的信号19void slotclientdisconnect(int);20 21 signals:22void updateserver(QString, int);//发送信号给界面,让界面更新信息23 24 };25 26 #endif // SERVER_H

1 #include "server.h"2 #include <QHostAddress>3 4 Server::Server(QObject *parent, int port):QTcpServer(parent)5 {6listen(QHostAddress::Any, port); //监听7 }8 9 void Server::incomingConnection(int socketDescriptor)10 {11TcpClientSocket *tcpclientsocket = new TcpClientSocket(this);//只要有新的连接就生成一个新的通信套接字12//将新创建的通信套接字描述符指定为参数socketdescriptor13tcpclientsocket->setSocketDescriptor(socketDescriptor);14 15//将这个套接字加入客户端套接字列表中16tcpclientsocketlist.append(tcpclientsocket);17 18 19//接收到tcpclientsocket发送过来的更新界面的信号20connect(tcpclientsocket, &TcpClientSocket::updateserver, this, &Server::sliotupdateserver);21connect(tcpclientsocket, &TcpClientSocket::clientdisconnected, this, &Server::slotclientdisconnect);22 23 }24 25 void Server::sliotupdateserver(QString msg, int length)26 {27//将这个信号发送给界面28emit updateserver(msg, length);29 30//将收到的信息发送给每个客户端,从套接字列表中找到需要接收的套接字31for(int i = 0; i < tcpclientsocketlist.count(); i++)32{33 QTcpSocket *item = tcpclientsocketlist.at(i);34 // if(item->write((char*)msg.toUtf8().data(), length) != length)35 // {36 // continue;37 // }38 item->write(msg.toUtf8().data());39}40 41 }42 43 void Server::slotclientdisconnect(int descriptor)44 {45for(int i = 0; i < tcpclientsocketlist.count(); i++)46{47 QTcpSocket *item = tcpclientsocketlist.at(i);48 if(item->socketDescriptor() == descriptor)49 {50 tcpclientsocketlist.removeAt(i);//如果有客户端断开连接, 就将列表中的套接字删除51 return;52 }53}54return;55 }

3、用来通信的类TcpClientSocket

1 #ifndef TCPCLIENTSOCKET_H2 #define TCPCLIENTSOCKET_H3 4 #include <QTcpSocket>5 6 class TcpClientSocket : public QTcpSocket7 {8Q_OBJECT //添加这个宏是为了实现信号和槽的通信9 public:10TcpClientSocket(QObject *parent = 0);11 protected slots:12void receivedata();//处理readyRead信号读取数据13void slotclientdisconnected();//客户端断开连接触发disconnected信号,这个槽函数用来处理这个信号14 15 signals:16void updateserver(QString, int);//用来告诉tcpserver需要跟新界面的显示17void clientdisconnected(int); //告诉server有客户端断开连接18 };19 20 #endif // TCPCLIENTSOCKET_H

1 #include "tcpclientsocket.h"2 3 TcpClientSocket::TcpClientSocket(QObject *parent)4 {5//客户端发送数据过来就会触发readyRead信号6connect(this, &TcpClientSocket::readyRead, this, &TcpClientSocket::receivedata);7connect(this, &TcpClientSocket::disconnected, this, &TcpClientSocket::slotclientdisconnected);8 }9 10 void TcpClientSocket::receivedata()11 {12 // while(bytesAvailable() > 0)13 // {14 // int length = bytesAvailable();15 // char buf[1024]; //用来存放获取的数据16 // read(buf, length);17 // QString msg = buf;18 // //发信号给界面,让界面显示登录者的信息19 // emit updateserver(msg, length);20 // }21int length = 10;22QByteArray array = readAll();23QString msg = array;24emit updateserver(msg, length);25 }26 27 void TcpClientSocket::slotclientdisconnected()28 {29emit clientdisconnected(this->socketDescriptor());30 }

客户端

客户端只需要一个类就行了,这个类我们只需要创建一个通信套接字来和服务器进行通信就可以了。

1 #ifndef TCPCLIENT_H2 #define TCPCLIENT_H3 4 #include <QWidget>5 #include <QTcpSocket>6 7 namespace Ui {8 class TcpClient;9 }10 11 class TcpClient : public QWidget12 {13Q_OBJECT14 15 public:16explicit TcpClient(QWidget *parent = 0);17~TcpClient();18 19 private slots:20void on_pushButtonEnter_clicked();21void slotconnectedsuccess();//用来处理连接成功的信号22void slotreceive();//接收服务器传过来的信息23void on_pushButtonSend_clicked();24void slotdisconnected();//用来处理离开聊天室的信号25 26 27 private:28Ui::TcpClient *ui;29bool status;//用来判断是否进入了聊天室30int port;31QHostAddress *serverIP;32QString userName;33QTcpSocket *tcpsocket;34 };35 36 #endif // TCPCLIENT_H

1 #include "tcpclient.h"2 #include "ui_tcpclient.h"3 #include <QHostAddress>4 #include <QMessageBox>5 6 TcpClient::TcpClient(QWidget *parent) :7QWidget(parent),8ui(new Ui::TcpClient)9 {10ui->setupUi(this);11//将进入聊天室的标志位置为false12status = false;13//端口为888814port = 8888;15ui->lineEditServerPort->setText(QString::number(port));//界面中端口默认显示888816 17serverIP = new QHostAddress();18 19//未进入聊天室内不能发送信息20ui->pushButtonSend->setEnabled(false);21 }22 23 TcpClient::~TcpClient()24 {25delete ui;26 }27 28 //进入聊天室29 void TcpClient::on_pushButtonEnter_clicked()30 {31//首先判断这个用户是不是在聊天室中32if(status == false)33{34 //不在聊天室中就和服务器进行连接35 QString ip = ui->lineEditServerIp->text();//从界面获取ip地址36 if(!serverIP->setAddress(ip))//用这个函数判断IP地址是否可以被正确解析37 {38 //不能被正确解析就弹出一个警告窗口39 QMessageBox::warning(this, "错误", "IP地址不正确");40 return;41 }42 if(ui->lineEditUserName->text() == "")43 {44 //用户名不能为空45 QMessageBox::warning(this, "错误", "用户名不能为空");46 return;47 }48 49 //从界面获取用户名50 userName = ui->lineEditUserName->text();51 //创建一个通信套接字,用来和服务器进行通信52 tcpsocket = new QTcpSocket(this);53 54 //和服务器进行连接55 tcpsocket->connectToHost(*serverIP, port);56 57 //和服务器连接成功能会触发connected信号58 connect(tcpsocket, &QTcpSocket::connected, this, &TcpClient::slotconnectedsuccess);59 //接收到服务器的信息就会触发readyRead信号60 connect(tcpsocket, &QTcpSocket::readyRead, this, &TcpClient::slotreceive);61 62 63 64 //将进入聊天室的标志位置为true;65 status = true;66}67else//已经进入了聊天室68{69 int length = 0;70 QString msg = userName + ":Leave Chat Room";71 // if((length = tcpsocket->write((char*)msg.toUtf8().data(), msg.length())) != msg.length())72 // {73 // return;74 // }75 tcpsocket->write(msg.toUtf8().data());76 tcpsocket->disconnectFromHost();77 status = false;78 //离开聊天室就会触发disconnected信号79 connect(tcpsocket, &QTcpSocket::disconnected, this, &TcpClient::slotdisconnected);80}81 }82 83 //用来处理连接成功的信号84 void TcpClient::slotconnectedsuccess()85 {86//进入聊天室可以发送信息了87ui->pushButtonSend->setEnabled(true);88//将进入聊天的按钮改为离开聊天室89ui->pushButtonEnter->setText("离开聊天室");90 91int length = 0;92//将用户名发送给服务器93QString msg= userName + " :Enter Chat Room";94 95 // if((length = tcpsocket->write((char*)msg.toUtf8().data(), msg.length())) != msg.length())96 // {97 // return;98 // }99tcpsocket->write(msg.toUtf8().data());100 }101 102 103 void TcpClient::slotreceive()104 {105 // while(tcpsocket->bytesAvailable() > 0 )106 // {107 // QByteArray datagram;108 // datagram.resize(tcpsocket->bytesAvailable());109 // tcpsocket->read(datagram.data(), datagram.size());110 // QString msg = datagram.data();111 // ui->textEdit->append(msg.left(datagram.size()));112 // }113QByteArray array = tcpsocket->readAll();114ui->textEdit->append(array);115 }116 117 void TcpClient::on_pushButtonSend_clicked()118 {119if(ui->lineEditSend->text() == "")120{121 return;122}123QString msg = userName + ":" + ui->lineEditSend->text();124 // tcpsocket->write((char*)msg.toUtf8().data(), msg.length());125tcpsocket->write(msg.toUtf8().data());126ui->lineEditSend->clear();127 }128 129 void TcpClient::slotdisconnected()130 {131ui->pushButtonSend->setEnabled(false);132ui->pushButtonEnter->setText("进入聊天室");133 }

编译完之后运行的界面就是这样的

整个通信的步骤

首先我们点击服务器的创建聊天室,TcpServer类的中的相应的槽函数会创建一个Server类的对象,然后调用构造函数会进行监听。一旦有客户端点击进入聊天室的按钮,客户端的tcpsocket就会和服务器进行连接,只要服务器监听到新的连接,Server类对象就会自动调用incomingConnection(int socketDescripter)这个函数。

接着我们只需要在这个函数中创建一个通信套接字也就是TcpClientSocket对象,并且将这个套接字描述符设定为参数socketDescripter,然后将这个套接字加入套接字列表中。这个时候客户端和服务器连接成功了,客户端就会触发一个connected信号,需要我们写一个槽函数来处理这个信号,这里的处理就是将这个用户名和“Enter Chat Room”发送给服务器。

服务器一旦收到信息,就会触发readyRead信号,这个时候我们需要在写一个相应的槽函数来读取套接字中的信息。我们这里是用readall来读取套接字中的所有信息。

当收到数据的时候,我们需要发一个信号给Server,将读取的信息再发送给所有在聊天室里的用户,所以在Server类中要添加一个相应的槽函数来将数据发送给所有的用户。

因为同时需要在服务器界面中显示所有用户发过来的消息,所以需要在刚刚那个槽函数中将自己定义的一个信号发送给TcpServer类,让其将收到的消息显示在界面中。客户端收到消息之后也会触发readyRead信号,客户端只需要将从套接字中读取的消息显示在见面中就行了。

客户端发送消息的时候需要从QLineEdit对象中读取内容,然后通过tcpsocket->write()函数将消息发送给服务器就行了。服务器同样会将收到的信息发送给所有的用户,同时显示在自己的界面中。最后客户端退出聊天室,客户端点击离开聊天室按钮,进入相应的槽函数中调用disconnectFromHost()函数,就会和服务器断开连接,一旦有调用了这个函数,就会触发disconnected信号,然后我们需要写一个相应的槽函数来处理这个信号,我们所做的处理就是将这个用户名和“Leave Chat Roo”发送给服务器。服务器那一端检测到有客户端断开连接也会触发disconnected信号,这个时候我们需要将套接字列表中将对应的套接字删除就可以了。

本文福利,费领取Qt开发学习资料包、技术视频,内容包括(C++语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QT嵌入式开发,Quick模块等等)↓↓↓↓↓↓见下面↓↓文章底部点击费领取↓↓

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。