Qt 网络聊天室项目
1. 需求分析
2. 概要设计
2.1 服务器概要设计
2.2 客户端概要设计
3. 详细设计
3.1 服务端的伪代码
- QTcpServer::listen()类似于TCP编程中的bind(将套接字和ip、端口号 绑定在一起)
- QHostAddress::Any 是 0.0.0.0 代表本机任意网卡的地址
3.1.0 创建TCP服务器
3.1.1 响应客户端请求
- newConnection()信号触发自定义槽函数onNewConnection(), 槽函数中会调用 nextPendingConnection() 获取和客户端通信的套接字
- 然后把套接字(连接?)保存到容器当中。 然后当客户端通过套接字发过来消息时,将触发readyRead()信号
3.1.2 接收客户端请求
- 当消息发来时,容器中可能会有多个套接字,需要遍历检查是哪个客户端发来的消息
- readyRead()信号触发槽函数onReadyRead(), 这个槽函数去遍历检查是哪个客户端发来的消息,然后完成消息的接收。
3.2 客户端的伪代码
3.2.0 创建TCP套接字和服务器建立连接
- connectToHost() 类似TCP编程中的connect(), 向指定的IP和端口发送连接请求,建立三次握手。
- 如果希望连接成功时有什么操作,可以通过onConnected()槽函数来完成。
- 通信套接字收到对方发来的消息时,都会产生readyRead()信号, onReadyRead()槽函数完成消息的接收。
3.2.1 发送聊天消息
- 发送消息控件的槽函数
3.2.2 接收聊天消息
- readyRead()消息的槽函数, 下面if的作用是如果有消息才去读取消息,不然如果没有消息时去读取会阻塞
4. 代码编写
github
4.1 服务器代码示例
- 在工程文件里加上network
- list Widget控件可以显示聊天过程,然后可以把聊天消息保存到本地,这里就不写保存的操作了
遍历容器如果有删除操作需要注意的点。
容器元素 : s1 s2 s3 s4 s5
下标 : 0 1 2 3 4
通过下标遍历检查容器中保存的客户端通信套接字是否已经断开连接,如果是则删除
如果当遍历到下标为2的元素s3对应的套接字已经断开连接,那么就删除s3, s4会自动向前移动到下标为2的位置
然后从下标3开始继续遍历,这样就会跳过s4.
所以,当遍历时发现需要删除元素时,下标要自减1,才能继续遍历。
sreverdialog.h
#ifndef SREVERDIALOG_H
#define SREVERDIALOG_H#include <QDialog>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QTimer>namespace Ui {class SreverDialog;
}class SreverDialog : public QDialog
{Q_OBJECTpublic:explicit SreverDialog(QWidget *parent = 0);~SreverDialog();private slots:// slot func of "create server" buttonvoid on_pushButton_clicked();// slot func of corresponding the client connection request (NewConnection())void onNewConnection();// slot func of receiving the client message (ReadyRead)void onReadyRead();// slot func of forwording the message to other clientvoid sendMessge(const QByteArray& buf);// slot func of timervoid onTimeout(void);private:Ui::SreverDialog *ui;QTcpServer tcpServer;quint16 port; // server portQList <QTcpSocket*> tcpClientList; //vector: save all sockets that communicate with clientQTimer timer; // timer (ji shi qi)};#endif // SREVERDIALOG_H
sreverdialog.cpp
#include "sreverdialog.h"
#include "ui_sreverdialog.h"SreverDialog::SreverDialog(QWidget *parent) :QDialog(parent),ui(new Ui::SreverDialog)
{ui->setupUi(this);// When a client sends a request to the server, newConnection() signal is generatedconnect(&tcpServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));// send timeout signal every three secondsconnect(&timer, SIGNAL(timeout()), SLOT(onTimeout()));
}SreverDialog::~SreverDialog()
{delete ui;
}// slot func of "create server" button
void SreverDialog::on_pushButton_clicked()
{// get server portport = ui->lineEdit->text().toShort();// set up server ip and portif (tcpServer.listen(QHostAddress::Any, port) == true){qDebug()<<"create server sucessfully!";// disiable pushButton and lineEditui->pushButton->setEnabled(false);ui->lineEdit->setEnabled(false);}else {qDebug()<< "faied to create server.";}
}// slot func of corresponding the client connection request
void SreverDialog::onNewConnection(){// get the socket of communicating with the clientQTcpSocket* tcpClient = tcpServer.nextPendingConnection();// save socket to vectortcpClientList.append(tcpClient);// when a client sent a message to server, soket send readyRead() signalconnect(tcpClient, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
}// slot func of receiving the client message
void SreverDialog::onReadyRead(){//for(int i=0; i<tcpClientList.size(); i++){// 遍历容器找到是哪个客户端发来的消息// bytesAvailable()获取当前套接字等待读取消息字节数// 返回0表示没有消息需要读,大于0说明有消息要来if(tcpClientList.at(i)->bytesAvailable()){// read message and save itQByteArray buf = tcpClientList.at(i)->readAll();// display messageui->listWidget->addItem(buf);ui->listWidget->scrollToBottom();// start timertimer.start(3000);// forward message to other clientsendMessge(buf);}}
}
// slot func of forwording the message to other client
void SreverDialog::sendMessge(const QByteArray& buf){for(int i =0; i<tcpClientList.size(); i++) {tcpClientList.at(i)->write(buf);}
}// slot func of timer
void SreverDialog::onTimeout(void){qDebug()<<"ni ma";// 遍历检查容器中保存的客户端通信套接字是否已经断开连接,如果是则删除for(int i=0; i<tcpClientList.size(); i++){if(tcpClientList.at(i)->state() ==QAbstractSocket::UnconnectedState){tcpClientList.removeAt(i);--i;}}
}
4.2 客户端代码示例
clientdialog.h
#ifndef CLIENTDIALOG_H
#define CLIENTDIALOG_H#include <QDialog>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
#include <QDebug>namespace Ui {class ClientDialog;
}class ClientDialog : public QDialog
{Q_OBJECTpublic:explicit ClientDialog(QWidget *parent = 0);~ClientDialog();private slots:// slot func of sendButtonvoid on_sendButton_clicked();// slot func of connectButtonvoid on_connectButton_clicked();// slot func for successful connection with server (connected())void onConnected();// slot func for disconnection with servervoid disConnected();// slot fucn of receive message from servervoid onReadyRead();// slot fucn of network exceptionvoid onError();private:Ui::ClientDialog *ui;bool status; // client status: online/outlineQTcpSocket tcpSocket; // socketQHostAddress serverIp; // server ipquint16 serverPort; // server portQString username; // username
};#endif // CLIENTDIALOG_H
clientdialog.cpp
#include "clientdialog.h"
#include "ui_clientdialog.h"ClientDialog::ClientDialog(QWidget *parent) :QDialog(parent),ui(new Ui::ClientDialog)
{status = false;ui->setupUi(this);connect(&tcpSocket, SIGNAL(connected()), this, SLOT(onConnected()));connect(&tcpSocket, SIGNAL(disconnected()), this, SLOT(disConnected()));connect(&tcpSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));connect(&tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError()));
}ClientDialog::~ClientDialog()
{delete ui;
}// slot func of sendButton
void ClientDialog::on_sendButton_clicked()
{// get user input messageQString msg = ui->messageEdit->text();if(msg == ""){return;}msg = username + ": " + msg;// send messagetcpSocket.write(msg.toUtf8());// clean messageEditui->messageEdit->clear();
}// slot func of connectButton
void ClientDialog::on_connectButton_clicked()
{// if outline, connect to serverif (status == false){// get server ipserverIp.setAddress(ui->serverIpEdit->text());// get server portserverPort = ui->serverPortEdit->text().toShort();// get usernameusername = ui->usernameEdit->text();// send connection request// if success, generate connected singal, esle generate error singaltcpSocket.connectToHost(serverIp, serverPort);}// if online, disconnect from serverelse {// send server with message that leaving chat roomQString msg = username + ": leaved!";tcpSocket.write(msg.toUtf8());// disconnect from server, and generate disconnected singaltcpSocket.disconnectFromHost();}
}// slot func for successful connection with server (connected())
void ClientDialog::onConnected()
{status = true;ui->sendButton->setEnabled(true);ui->serverIpEdit->setEnabled(false);ui->serverPortEdit->setEnabled(false);ui->usernameEdit->setEnabled(false);ui->connectButton->setText("leave chat room");// send message to serverQString msg = username + ": entered the chat room!";// toUtf8(): transform QString to QByteArraytcpSocket.write(msg.toUtf8());
}// slot func for disconnection with server
void ClientDialog::disConnected()
{status = false;ui->sendButton->setEnabled(true);ui->serverIpEdit->setEnabled(true);ui->serverPortEdit->setEnabled(true);ui->usernameEdit->setEnabled(true);ui->connectButton->setText("connect server");
}// slot fucn of receive message from server
void ClientDialog::onReadyRead()
{if(tcpSocket.bytesAvailable()){// receive messageQByteArray buf = tcpSocket.readAll();// display messageui->listWidget->addItem(buf);// dispaly bottom messageui->listWidget->scrollToBottom();}
}// slot fucn of network exception
void ClientDialog::onError()
{// errorString(): get reason of network exceptionQMessageBox::critical(this, "ERROR", tcpSocket.errorString());
}
Qt 网络聊天室项目相关推荐
- 仿微信的网络聊天室项目开发【完整源码讲解】
目录 总体开发思路 服务器端 服务器界面设计 建立TCP服务器端通信 建立服务器消息发送输出流 建立服务器消息接收输入流 建立服务器实时消息通信线程 设置服务器通信自由断开 客户端 客户端界面设计 建 ...
- QT 网络聊天室设计实验报告
一.实验目的与要求 (1)了解QT Network模块基本知识 (2)掌握网络访问接口的方法 (3)熟悉获取网络接口信息的方法 二.实验内容与安排方式 (1)了解QT Network模块基本知识 (2 ...
- qt linux 聊天室,Qt网络聊天室客户端
原创 DeRoy 2020-08-15 收录于话题 #QT项目实战 11个 点击蓝字关注我们 基于Qt网络编程客户端 QTcpSocketQTcpSocket 类提供一个TCP套接字TCP是一个面向连 ...
- 仿微信的网络聊天室项目开发【完整源码讲解,Java一年工作经验面试题
/*使滚动条置于文本框最下端*/ infoWindow.setSelectionStart(infoWindow.getText().length());JScrollBar jSBInfo = jS ...
- QQ版网络聊天室完整项目+MFC\C++\C(更改服务器IP可实现异机沟通)
QQ版网络聊天室完整项目+MFC\C++\C 资源地址1 资源地址2 项目简介 服务器端部分代码 客户端响应部分代码 数据库连接 理论~ 实例展示 资源地址1 https://github.com/M ...
- 网络编程项目(聊天室项目)
一.实现目标 一个在Linux下可以使用的聊天软件,要求至少实现如下功能: 1. 采用Client/Server架构 2. Client A 登陆聊天服务器前,需要注册自己的ID和密码 3. 注册成功 ...
- java_OA管理系统(一):Servlet总结案例仿网络聊天室
因为我们学校的软件联盟要为我们校区开发一个OA系统,为此我将其所需要的一些技术进行汇总,以便web组组员开发所用. 第一篇是关于Servlet的一个汇总案例,算是开个简单的小头. 一.总述 代码来源于 ...
- 网络聊天室的技术与发展
网络聊天室的技术与发展 摘要: 此文讲述了视频聊天网站相关的技术.发展过程.从客户那里了解到了很多的视频聊天相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模式.系统架构以及相关技术的研究,写下 ...
- Linux环境下——C语言聊天室项目
由于使用了多线程操作,客户端进入程序后请先随便注册一次用户后再进行使用. 本程序默认第一个用户即ID为1的用户为超级管理员. 由于线程阻塞,最后的踢人操作有阻塞,需要在被踢出在线链表后手动下线. 看了 ...
- java大作业网络聊天室
这个项目是我大一的java期末大作业,学习了一个学期的成果,编程能力不够,做的并不够好,写在这里记录一下自己的成长,也欢迎大家给出宝贵意见! 第一次写博客哟,请多多支持! 该篇博客写一个基于java的 ...
最新文章
- mailmessage html编码,C#MailMessage顯示HTML標記的AlternateViews
- jqgrid本地加载分页_jqgrid无需分页即可加载大数据集
- object-c中归档的用法
- 复练-软考高级-论文写作专题
- 西瓜书+实战+吴恩达机器学习(二十)随机算法(拉斯维加斯方法、蒙特卡罗方法)
- Visual Studio 2008 编译程序时的 mt.exe 返回错误
- cin.ignore()函数的使用
- Mac如何设置文本中的单双引号样式?
- SPOJ SUBST1 New Distinct Substrings(后缀数组 本质不同子串个数)题解
- java 解析umd文件_Webpack UMD:严重依赖...无法静态提取
- A4988与42步进电机
- 基金经理的13年期货感悟(一)
- Unity用Animation组件制作简单的动画
- 干货!5招搞定问卷调查差异化分析
- 前大灯是近光灯还是远光灯_前照灯和近光灯一样吗?前照灯就是近光灯吗
- 树莓派4B(ubuntu)无线网络配置
- 设计模式 模版方法模式 展现程序员的一天
- python根据掩模坐标提取数据
- 服务器esxi虚拟机升级,ESXi 服务器安装升级补丁
- 关于python使用playsound播放音频:指定的设备未打开,或不被 MCI 所识别。