Qt--基于TCP客户端与服务器的聊天程序(半双工通信)

目录

任务:实现一个基于TCP的聊天程序,需要使用的类有:

QTcpServer ​编辑

QTcpSocket ​编辑

QTextStream 

服务端:server(QTcpServer)

步骤:

代码:

dialog.h

dialog.cpp

客户端:client(QTcpSocket)

步骤:

代码:

dialog.h

dialog.cpp

dialog.ui

 运行效果:

客户端

服务器 


任务:实现一个基于TCP的聊天程序,需要使用的类有:

  • QTcpServer Qt--基于TCP客户端与服务器的聊天程序(半双工通信)_第1张图片

服务器管理类:管理服务器的多个连接,直接继承了QObject,因此不具备IO能力。

相关函数如下:

// 构造函数
QTcpServer::QTcpServer(QObject * parent = 0)// 服务器开启监听,等待客户主动发起连接
// 参数1:监听来自于哪个IP地址的请求,默认值为不限制IP地址,QHostAddress类是IP地址的封装类。
// 参数2:服务器端口号
// 返回值:监听开启结果
bool QTcpServer::listen(
                const QHostAddress & address = QHostAddress::Any, 
                quint16 port = 0)
// 有新连接建立的通知信号
void QTcpServer::newConnection() [signal]// 服务器是否还在监听
bool QTcpServer::isListening() const// 关闭服务器
void QTcpServer::close()
// 返回一个就绪的连接对象,此对象用于跟某个客户端进行IO操作
QTcpSocket * QTcpServer::nextPendingConnection() [virtual]
  • QTcpSocket Qt--基于TCP客户端与服务器的聊天程序(半双工通信)_第2张图片

TCP连接类:进行网络IO操作,间接继承QIODevice类。

相关函数如下:

// 构造函数
QTcpSocket::QTcpSocket(QObject * parent = 0)
// 连接到服务器
// 参数1:服务器的IP地址
// 参数2:服务器的端口号
// 参数3:读写模式,默认为可读可写
void QAbstractSocket::connectToHost(const QString & hostName,
                                    quint16 port, 
                                    OpenMode openMode = ReadWrite) [virtual]
// 连接是否处于打开状态
bool QIODevice::isOpen() const
// 关闭连接
void QIODevice::close() [virtual]
// 拿到对面的IP地址封装类对象,如果没有连接返回QHostAddress::Null
QHostAddress QAbstractSocket::peerAddress() const
// 连接断开发射的信号
void QAbstractSocket::disconnected() [signal]
  • QTextStream 

文本流类:是一种高效地文本数据IO的辅助类。

服务端:server(QTcpServer)

步骤:

①创建QTcpServer对象

②监听list需要的参数是地址和端口号

③当有新的客户端连接成功回发送newConnect信号

④在newConnection信号槽函数中,调用nextPendingConnection函数获取新连接QTcpSocket对象

⑤连接QTcpSocket对象的readRead信号

⑥在readRead信号的槽函数使用read接收数据

⑦调用write成员函数发送数据

代码:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include 
#include
//网络相关类
#include
#include
#include
#include

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    QTcpServer *server;//服务器对象
    QTcpSocket *socket=NULL;
private slots:
    void newConnSlot();//新连接的槽函数
    void disconnectedSlot(); //网络连接断开的槽函数
    void readReadSlot(); //读取客户端信息的槽函数
    void btnSendClickedSlot();//发送给客户端消息的槽函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    //设置窗口标记为顶层
    setWindowFlags(Qt::WindowStaysOnTopHint);

    //创建管理类对象
    server=new QTcpServer(this);

    //连接服务器通知的信号槽
    connect(server,SIGNAL(newConnection()),this,SLOT(newConnSlot()));
    //向客户端发送信息的信号槽
    connect(ui->pushButtonSend,SIGNAL(clicked()),this,SLOT(btnSendClickedSlot()));

    // 服务器开启监听,等待客户主动发起连接
    // 参数1:监听来自哪个IP地址的请求,默认值为不限制IP地址,QHostAddress类是IP地址的封装类。
    // 参数2:服务器端口号
    server->listen(QHostAddress::Any,8887);
}

Dialog::~Dialog()
{
    if(server->isListening())//如果在监听
          server->close();//关闭服务器
    delete ui;
}

void Dialog::newConnSlot()
{
    //踢掉之前的连接
    if(socket!=NULL)
    {
        socket->close();
    }
    //拿到与客户端进行连接的QTcpSocket对象
    socket=server->nextPendingConnection();
    //建立断链通知的信号槽
    connect(socket,SIGNAL(disconnected()), this,SLOT(disconnectedSlot()));
    //建立读取消息的信号槽
    connect(socket,SIGNAL(readyRead()),this,SLOT(readReadSlot()));
    //拿到客户端的ip和端口号
    QString ip=socket->peerAddress().toString();
    quint16 port=socket->peerPort();
    QString time=QDateTime::currentDateTime().toString("hh:mm:ss");
    ui->textBrowser->append(time);
    ui->textBrowser->append("新连接来了!");
    ui->textBrowser->append("");
    ui->textBrowser->append(ip.append(":").append(QString::number(port)));
    ui->textBrowser->append("");
}

void Dialog::disconnectedSlot()
{
    //拿到客户端的ip和端口号
    QString ip=socket->peerAddress().toString();
    quint16 port=socket->peerPort();
    QString time=QDateTime::currentDateTime().toString("hh:mm:ss");
    ui->textBrowser->append(time);
    ui->textBrowser->append("连接结束了!");
    ui->textBrowser->append("");

    ui->textBrowser->append(ip.append(":").append(QString::number(port)));
    ui->textBrowser->append("");
}


void Dialog::readReadSlot()  //读取客户端信息
{
  QTextStream input(socket);
  QString time=QDateTime::currentDateTime().toString("hh:mm:ss");
  //读取数据
  QString msg=input.readAll();
  //展示内容
  ui->textBrowser->append(time);
  ui->textBrowser->append(msg);
}

void Dialog::btnSendClickedSlot()  //向客户端发送消息
{
    //获取用户输入的内容
   QString info=ui->lineEdit->text();
   if(info=="")
   {
      QMessageBox::warning(this,"提示","请输入发送的内容");
      return;
   }
   //创建文本流对象
   QTextStream output(socket);
   //发送内容
   output<lineEdit->clear();
}

客户端:client(QTcpSocket)

步骤:


①创建QTcpSocket对象

②当对象与Server连接成功时会发送connected 信号

③调用成员函数connectToHost连接服务器,需要的参数是地址和端口号

④connected信号的槽函数开启发送数据

⑤使用write发送数据,read接收数据

代码:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include 
#include
#include
//连接类
#include
#include
namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    QTcpSocket *client;//连接对象
    QTcpSocket *socket=NULL;
private slots:
    void btnConnClickedSlot();//连接按钮的槽函数
    void btnSendClickedSlot();//发送按钮的槽函数
    void connectedSlot();  //连接的槽函数
    void disconnectedSlot(); //断开连接的槽函数
    void readInfoSlot();//接收信息的槽函数
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    connect(ui->pushButtonConn,SIGNAL(clicked()),this,SLOT(btnConnClickedSlot()));
    connect(ui->pushButtonSend,SIGNAL(clicked()), this,SLOT(btnSendClickedSlot()));
    //设置窗口标记为顶层
    setWindowFlags(Qt::WindowStaysOnTopHint);
    //创建连接对象
    client=new QTcpSocket(this);
    //连接状态检测的信号槽
    connect(client,SIGNAL(connected()),this,SLOT(connectedSlot()));
    connect(client,SIGNAL(disconnected()),this,SLOT(disconnectedSlot()));
    //读取服务器发来消息的信号槽
    connect(client,SIGNAL(readyRead()),this,SLOT(readInfoSlot()));
}

Dialog::~Dialog()
{
    if(client->isOpen())//如果连接处于打开状态
          client->close();//关闭连接
    delete ui;
}

void Dialog::btnConnClickedSlot()
{
    // 默认输入有效,连接到服务器
    // 参数1:服务器的IP地址
    // 参数2:服务器的端口号
    client->connectToHost(ui->lineEditIp->text(),8887);
}

void Dialog::btnSendClickedSlot()
{
   //获取用户输入的内容
    QString msg=ui->lineEditInfo->text();
    if(msg=="")
    {
        QMessageBox::warning(this,"提示","请输入要发送的内容!");
        return;
    }
    //创建文本流对象
    QTextStream output(client);
    //发送内容
    output<lineEditInfo->clear();
}

void Dialog::connectedSlot()
{
    //屏蔽连接按钮
    ui->pushButtonConn->setEnabled(false);
    ui->pushButtonConn->setText("已连接");
    //释放发送按钮
    ui->pushButtonSend->setEnabled(true);
}
void Dialog::disconnectedSlot()
{
    //恢复连接按钮
    ui->pushButtonConn->setEnabled(true);
    ui->pushButtonConn->setText("连接");
    //屏蔽发送按钮
    ui->pushButtonSend->setEnabled(false);
}
void Dialog::readInfoSlot()
{
    QTextStream input(client);
    QString time=QDateTime::currentDateTime().toString("hh:mm:ss");
    //读取数据
    QString info=input.readAll();
    ui->textBrowser->append(time);
    ui->textBrowser->append(info);
}

dialog.ui

Qt--基于TCP客户端与服务器的聊天程序(半双工通信)_第3张图片

 运行效果:

客户端

 Qt--基于TCP客户端与服务器的聊天程序(半双工通信)_第4张图片

服务器 

Qt--基于TCP客户端与服务器的聊天程序(半双工通信)_第5张图片

你可能感兴趣的:(qt,tcp/ip,服务器)