标签:聊天室 void ServiceWidget 网络 ClientWidget ui 服务器 客户端
● 需求分析:
1.服务器:基于TCP协议创建服务器
相应客户端连接
事实接受说有客户端发送的消息
保存显示信息并转发给其他客户端
2.客户端:创建TCP套接字
配置服务器的IP端口和聊天室昵称
向服务器发送链接请求
获取用户输入的聊天信息并发送到1服务器
事实接受服务器转发的消息并显示
项目展示
服务器界面:
服务器头文件源码:
在pro文件中添加网络模块
QT += core gui network
#ifndef SERVICEWIDGET_H
#define SERVICEWIDGET_H
#include <QWidget>
#include<QTcpServer>//tcp服务器
#include<QTcpSocket>//tcp套接字
#include<QDebug>
#include<QTimer>//计时器
namespace Ui {
class ServiceWidget;
}
class ServiceWidget : public QWidget
{
Q_OBJECT
public:
explicit ServiceWidget(QWidget *parent = 0);
~ServiceWidget();
private slots:
//创建服务器按钮对应的槽函数
void on_creatButton_clicked();
//相应客户端连接的槽函数
void onNewconnect();
//接受客户端信息的槽函数
void onReadyRead();
//转发聊天信息给其他客户端的槽函数
void sendMessage(const QByteArray& buf);
//计时器槽函数
void onTimeout(void);
private:
Ui::ServiceWidget *ui;
QTcpServer tcpServer;//服务器对象
quint16 port;//保存端口号对象
QList<QTcpSocket*> tcpClientList;//保存通讯套接字的容器
QTimer timer;//计时器对象
};
#endif // SERVICEWIDGET_H
服务器源文件代码展示:
#include "servicewidget.h"
#include "ui_servicewidget.h"
ServiceWidget::ServiceWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ServiceWidget)
{
ui->setupUi(this);
//当客户端发送连接请求时服务端会收到newConnection信号
connect(&tcpServer,SIGNAL(newConnection()),this,SLOT(onNewconnect()));
//当计时器时间到发出timer信号执行计时器槽函数
connect(&timer,SIGNAL(timeout()),SLOT(onTimeout()));
}
ServiceWidget::~ServiceWidget()
{
delete ui;
}
//创建服务器按钮的槽函数
void ServiceWidget::on_creatButton_clicked()
{
//取portEdit文本框内输入的端口号
port=ui->portEdit->text().toShort();
//设置监听任意IP的port端口号并进行判断
if(tcpServer.listen(QHostAddress::Any,port)==true)
{
qDebug()<<"ok";
ui->creatButton->setEnabled(false);
ui->portEdit->setEnabled(false);
timer.start(3000);
}
else
{
qDebug()<<"faile";
}
}
//相应客户端连接的槽函数
void ServiceWidget::onNewconnect()
{
//获得服务端通信套接字
QTcpSocket* tcpClient= tcpServer.nextPendingConnection();
//将其套接字放入套接字容器中
tcpClientList.append(tcpClient);
//当客户端发送信息时会发送readRead信号,执行onReadRead槽函数
connect(tcpClient,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
}
//接送客户端信息的的槽函数
void ServiceWidget::onReadyRead()
{
//循环进行判断是哪一个客户端给服务器发送了消息
for(int i=0;i<tcpClientList.size();i++)
{
//bytesAvailable获取套接字读取信息字节数
if(tcpClientList.at(i)->bytesAvailable())
{
//获取套接字里的所有信息存在到QByteArry的缓存区中
QByteArray buf=tcpClientList.at(i)->readAll();
//在listWidget中显示
ui->listWidget->addItem(buf);
//添加消息的回滚
ui->listWidget->scrollToBottom();
//调用转发信息函数
sendMessage(buf);
}
}
}
//转发聊天信息给其他客户端的槽函数
void ServiceWidget::sendMessage(const QByteArray& buf)
{
//循环遍历将缓存区的信息发送给所有客户端
for(int i=0;i<tcpClientList.size();i++)
{
tcpClientList.at(i)->write(buf);
}
}
//计时器槽函数断开已经失效的套接字
void ServiceWidget::onTimeout(void)
{
//循环遍历容器中所有的套接字判断其状态是否离线离线就删除
for(int i=0;i<tcpClientList.size();i++)
{
if(tcpClientList.at(i)->state()==QAbstractSocket::UnconnectedState)
{
tcpClientList.removeAt(i);
i--;
}
}
}
客户端界面:
在pro文件中添加网络模块
QT += core gui network
客户端头文件代码展示:
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include <QWidget>
#include<QTcpSocket>//套接字
#include<QHostAddress>// 服务器地址
#include<QMessageBox>//提示框
#include<QDebug>
namespace Ui {
class ClientWidget;
}
class ClientWidget : public QWidget
{
Q_OBJECT
public:
explicit ClientWidget(QWidget *parent = 0);
~ClientWidget();
private slots:
//发送信息键的槽函数
void on_sendButton_clicked();
//连接服务器键的槽函数
void on_connectButton_clicked();
//连接服务器槽函数
void onConnected();
//断开连接服务器的槽函数
void onDisconnected();
//接受到信息的槽函数
void onreadyRead();
//出错的槽函数
void one rror();
private:
Ui::ClientWidget *ui;
//判断客户端与服务器连接与否的bool值
bool status;
//套接字的对象
QTcpSocket tcpSocket;
//服务器IPD地址对象
QHostAddress serverIP;
//端口对象
quint16 serverPort;
//聊天室昵称对象
QString username;
};
#endif // CLIENTWIDGET_H
客户端源文件展示:
#include "clientwidget.h"
#include "ui_clientwidget.h"
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
//客户端与服务器状态默认设置为断开
status=false;
//客户端连接服务器
connect(&tcpSocket,SIGNAL(connected()),this,SLOT(onConnected()));
//客户端断开于服务器连接
connect(&tcpSocket,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
//客户端接受消息
connect(&tcpSocket,SIGNAL(readyRead()),this,SLOT(onreadyRead()));
//服务器连接失败,数据收发失败触发出错槽函数
connect(&tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(onError()));
}
ClientWidget::~ClientWidget()
{
delete ui;
}
//信息发送按钮槽函数
void ClientWidget::on_sendButton_clicked()
{
QString msg=ui->messageEdit->text();
if(msg=="")
{
return;
}
msg=username+":"+msg;
tcpSocket.write(msg.toUtf8());
ui->messageEdit->clear();
}
//服务器连接按钮槽函数
void ClientWidget::on_connectButton_clicked()
{
//判断客户端与服务器连接状态
if(status==false)
{
//获得serverIP文本框输入的ip地址
serverIP.setAddress(ui->serveripEdit->text());
//获得serverPort文本框输入的端口
serverPort=ui->serverPortEdit->text().toShort();
//获得username文本框输入聊天室内名称
username=ui->usernameEdit->text();
//向服务器发送请求成功发送信号connected失败发送信号error
tcpSocket.connectToHost(serverIP,serverPort);
}
else
{
QString msg=username+" leave room!";
//发出信号给服务器
tcpSocket.write(msg.toUtf8());
//断开连接
tcpSocket.disconnectFromHost();
}
}
//与服务器连接槽函数
void ClientWidget:: onConnected()
{
//连接成功设置状态为true
status=true;
ui->sendButton->setEnabled(true);
ui->serveripEdit->setEnabled(false);
ui->serverPortEdit->setEnabled(false);
ui->usernameEdit->setEnabled(false);
ui->connectButton->setText("leave room");
QString msg=username+" go in room";
tcpSocket.write(msg.toUtf8());
}
//与服务器断开的槽函数
void ClientWidget::onDisconnected()
{
status=false;
ui->sendButton->setEnabled(true);
ui->serveripEdit->setEnabled(false);
ui->serverPortEdit->setEnabled(false);
ui->usernameEdit->setEnabled(false);
ui->connectButton->setText("connect service");
}
//接收到服务器信息槽函数
void ClientWidget::onreadyRead()
{
//接受消息输出
if(tcpSocket.bytesAvailable())
{
QByteArray buf=tcpSocket.readAll();
ui->listWidget->addItem(buf);
//设置消息的滚动
ui->listWidget->scrollToBottom();
}
}
//出错糙汉苏
void ClientWidget::onError()
{
//提示框提示网络连接错误原因
QMessageBox::critical(this,"ERROR",tcpSocket.errorString());
}
标签:聊天室,void,ServiceWidget,网络,ClientWidget,ui,服务器,客户端 来源: https://blog.csdn.net/weixin_45461214/article/details/119408502
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。