怎么用QT实现TCP网络聊天室
今天小编给大家分享一下怎么用QT实现TCP网络聊天室的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
服务器:
serverdialog.h
#ifndef SERVERDIALOG_H
#define SERVERDIALOG_H
#include <QDialog>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QTimer>
namespace Ui {
class ServerDialog;
}
class ServerDialog : public QDialog
{
Q_OBJECT
public:
explicit ServerDialog(QWidget *parent = 0);
~ServerDialog();
private slots:
//创建服务器按钮对应的槽函数
void on_pushButton_clicked();
//响应客户端连接请求的槽函数
void onNewConnection();
//接收客户端聊天消息的槽函数
void onReadyRead();
//转发聊天消息给其它客户端的槽函数
void sendMessage(const QByteArray&);
//定时器检查客户端套接字是否为正常连接状态的槽函数
void onTimeout(void);
private:
Ui::ServerDialog *ui;
QTcpServer tcpServer;//TCP服务器
quint16 port;//服务器端口,quint16-->unsigned short
QList<QTcpSocket*> tcpClientList;//容器:保存和客户端通信的套接字
QTimer timer;//定时器,定时检查容器中和客户端通信的套接字是否为正常连接状态
};
#endif // SERVERDIALOG_H
serverdialog.cpp
#include "serverdialog.h"
#include "ui_serverdialog.h"
ServerDialog::ServerDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ServerDialog)
{
ui->setupUi(this);
}
ServerDialog::~ServerDialog()
{
delete ui;
}
//创建服务器按钮对应的槽函数
void ServerDialog::on_pushButton_clicked()
{
//获取服务器端口
port = ui->lineEdit->text().toShort();
//设置监听服务器的IP和端口
//QHostAddress::Any ==> QHostAddress("0.0.0.0");
if(tcpServer.listen(QHostAddress::Any,port)==false){
qDebug() << "创建服务器失败";
return;
}
else{
qDebug() << "创建服务器成功";
//当有客户端向服务器发送连接请求时,发送信号newConnection
connect(&tcpServer,SIGNAL(newConnection()),
this,SLOT(onNewConnection()));
//禁用端口输入和创建服务器按钮
ui->lineEdit->setEnabled(false);
ui->pushButton->setEnabled(false);
//定时器到时发送信号:timeout
connect(&timer,SIGNAL(timeout()),this,SLOT(onTimeout()));
//开启定时器,每隔3秒检查一次
timer.start(3000);
}
}
//响应客户端连接请求的槽函数
void ServerDialog::onNewConnection()
{
//获取和客户端通信的套接字
QTcpSocket* tcpClient = tcpServer.nextPendingConnection();
//保存套接字到容器中
tcpClientList.append(tcpClient);
//当客户端给服务器发送消息时,tcpClient发送信号readyRead
connect(tcpClient,SIGNAL(readyRead()),
this,SLOT(onReadyRead()));
}
//接收客户端聊天消息的槽函数
void ServerDialog::onReadyRead()
{
//遍历检查哪个客户端有消息
for(int i=0;i<tcpClientList.size();i++){
//at(i):获取容器中第i套接字(QTcpSocket*)
//bytesAvailable:获取当前套接字等待读取消息的字节数,如果为0表示没有消息,如果
//大于0说明有消息.
if(tcpClientList.at(i)->bytesAvailable()){
//读取消息并保存
QByteArray buf = tcpClientList.at(i)->readAll();
//显示消息
ui->listWidget->addItem(buf);
//回滚到最底部(最新消息)
ui->listWidget->scrollToBottom();
//转发消息给其它客户端
sendMessage(buf);
}
}
}
//转发聊天消息给其它客户端的槽函数
void ServerDialog::sendMessage(const QByteArray& msg)
{
for(int i=0;i<tcpClientList.size();i++){
tcpClientList.at(i)->write(msg);
}
}
//定时器检查客户端套接字是否为正常连接状态的槽函数
void ServerDialog::onTimeout(void)
{
for(int i=0;i<tcpClientList.size();i++){
//state():获取第i个套接字的连接状态
//UnconnectedState:表示未连接(断开连接)
if(tcpClientList.at(i)->state() ==
QAbstractSocket::UnconnectedState){
//从容器中将断开连接的套接字移除
tcpClientList.removeAt(i);
--i;
}
}
}
main.cpp
#include "serverdialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ServerDialog w;
w.show();
return a.exec();
}
客户端:
clientdialog:
#ifndef CLIENTDIALOG_H
#define CLIENTDIALOG_H
#include <QDialog>
//QT += network
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
namespace Ui {
class ClientDialog;
}
class ClientDialog : public QDialog
{
Q_OBJECT
public:
explicit ClientDialog(QWidget *parent = 0);
~ClientDialog();
private slots:
//发送按钮对应的槽函数
void on_sendButton_clicked();
//连接服务器按钮对应的槽函数
void on_connectButton_clicked();
//和服务器连接成功时执行的槽函数
void onConnected(void);
//和服务器断开连接时执行的槽函数
void onDisconnected(void);
//接收服务器转发聊天消息的槽函数
void onReadyRead(void);
//网络通信异常时执行的槽函数
void onError(void);
private:
Ui::ClientDialog *ui;
bool status;//客户端状态标记,true:在线,false:离线状态
QTcpSocket tcpSocket;//和服务器通信的tcp套接字
QHostAddress serverIp;//服务器地址
quint16 serverPort;//服务器端口
QString username;//聊天室昵称
};
#endif // CLIENTDIALOG_H
clientdialog.cpp
#include "clientdialog.h"
#include "ui_clientdialog.h"
ClientDialog::ClientDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::ClientDialog)
{
ui->setupUi(this);
status = false;
//和服务器连接成功时,tcpSocket发送信号:connected
connect(&tcpSocket,SIGNAL(connected()),
this,SLOT(onConnected()));
//和服务器断开连接时,tcpSocket发送信号:disconnected
connect(&tcpSocket,SIGNAL(disconnected()),
this,SLOT(onDisconnected()));
//收到聊天消息时,tcpSocket发送信号:readyRead
connect(&tcpSocket,SIGNAL(readyRead()),
this,SLOT(onReadyRead()));
//网络通信异常时,tcpSocket发送信号:error
connect(&tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),
this,SLOT(onError()));
}
ClientDialog::~ClientDialog()
{
delete ui;
}
//发送按钮对应的槽函数
void ClientDialog::on_sendButton_clicked()
{
//获取用户输入的消息
QString msg = ui->messageEdit->text();
if(msg == ""){
return;
}
msg = username + ":" + msg;
//发送消息
tcpSocket.write(msg.toUtf8());
//清空已输入的消息
ui->messageEdit->clear();
}
//连接服务器按钮对应的槽函数
void ClientDialog::on_connectButton_clicked()
{
if(status == false){//如果当前是离线状态,则连接服务器
//获取服务器IP
if(serverIp.setAddress(ui->serverIpEdit->text())==false){
//critical():表示错误的消息提示框
QMessageBox::critical(this,"Error","IP地址错误");
return;
}
//获取服务器端口
serverPort = ui->serverportEdit->text().toShort();
if(serverPort < 1024){
QMessageBox::critical(this,"Error","端口格式错误");
return;
}
//获取聊天室昵称
username = ui->usernameEdit->text();
if(username == ""){
QMessageBox::critical(this,"Error","聊天室昵称不能为空");
return;
}
//向服务器发送连接请求:
//如果成功,发送信号:connected;
//如果失败,发送信号:error
tcpSocket.connectToHost(serverIp,serverPort);
}
else{//如果当前是在线状态,则断开和服务器连接
//向服务器发送离开聊天室的消息
QString msg = username + ":离开了聊天室";
//toUtf8():将QString(unicode)转换QByteArray(utf-8)
tcpSocket.write(msg.toUtf8());
//断开连接
//断开后发送信号:disconnected
tcpSocket.disconnectFromHost();
}
}
//和服务器连接成功时执行的槽函数
void ClientDialog::onConnected(void)
{
status = true;//设置状态标记:在线
ui->sendButton->setEnabled(true);//恢复"发送"按钮为正常可用状态
ui->serverIpEdit->setEnabled(false);//禁用ip输入
ui->serverportEdit->setEnabled(false);//禁用端口输入
ui->usernameEdit->setEnabled(false);//禁用昵称输入
ui->connectButton->setText("离开聊天室");//修改连接服务器按钮文本
//向服务器发送进入聊天室提示消息
QString msg = username + ":进入了聊天室";
//toUtf8():将QString(unicode)转换QByteArray(utf-8)
tcpSocket.write(msg.toUtf8());
}
//和服务器断开连接时执行的槽函数
void ClientDialog::onDisconnected(void)
{
status = false;//设置离线状态
ui->sendButton->setEnabled(false);//禁用"发送"按钮
ui->serverIpEdit->setEnabled(true);//恢复ip输入
ui->serverportEdit->setEnabled(true);//恢复端口输入
ui->usernameEdit->setEnabled(true);//恢复昵称输入
ui->connectButton->setText("连接服务器");//修改离开聊天室按钮文本
}
//接收服务器转发聊天消息的槽函数
void ClientDialog::onReadyRead(void)
{
//bytesAvailable():获取等待读取消息的字节数
if(tcpSocket.bytesAvailable()){
//读取消息
QByteArray buf = tcpSocket.readAll();
//显示消息到界面
ui->listWidget->addItem(buf);
ui->listWidget->scrollToBottom();
}
}
//网络通信异常时执行的槽函数
void ClientDialog::onError(void)
{
//errorString():获取网络通信异常原因的字符串
QMessageBox::critical(this,"Error",tcpSocket.errorString());
}
main.cpp
#include "clientdialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ClientDialog w;
w.show();
return a.exec();
}
最终实现效果:
相关文章