QTchatRoomDemo

QT chatroom First Demo

成品演示

在这里插入图片描述

整体项目结构:

在这里插入图片描述

1.开启电脑telnet,当作一个客户端

客户端还没开始写,先暂时用

在这里插入图片描述

2.编写服务端server

下面可不看:自己的理解

socket套接字=lp地址+端口号
目标:实现一个简单的服务器,可以接受客户端发来的信息今天的客户端采用telnet客户端服务端: 一个客户端
类库
QTcpServer实现服务器端的端口监听,可以提供一种服务

QTcpSocket 实现套接字类,这里有消息的封装,可以读取和写入
自定义类Server类,用户消息服务。

工程文件引入network类库才能使用tcp服务

如何开启端口服务?
使用QTcpServer中的listen方法就可以开启指定的端口listen(QHostAddress::Any,8888);
并在mianwindow.h里面实例化 server server;

通过重写void incomingConnection(qintptr handle);来将新连接用户加入进来

将当前的连接对象存入到socket对象中sock=new QTcpSocket(this);sock->setSocketDescriptor(handle);监听sock对象的readyread信号来处理最后的消息读取消息
sock->read(buffer,sock->bytesAvailable()):通过if语句来排除无用字符if(sock->bytesAvailable()>0)

2.1创建widget项目

新的c++文件server,server继承QObject,然后工程文件引入network类库,QObject改为QTcpServer

在这里插入图片描述
.

在这里插入图片描述

2.2开启端口服务

  • 使用QTcpServer中的listen方法就可以开启指定的端口listen(QHostAddress::Any,8888);
  • 并在widget.h里面实例化 server server;
Server::Server(QObject *parent) : QTcpServer(parent)
{
    //开启监听
    listen(QHostAddress::Any,8888);
}
class Widget : public QWidget
{
private:
    Ui::Widget *ui;
    Server server;//实例化
};

打开cmd,检查是否开启端口成功

在这里插入图片描述

2.3监听链接的用户

QTCPserver
void newConnection(); 单线程的的信号,不推荐使用

重写void incomingConnection(qintptr handle);来监听链接的用户,推荐使用  后台线程的方式  
virtual void incomingConnection(qintptr handle);
This virtual function is called by QTcpServer when a new connection is available. The socketDescriptor argument is the native socket descriptor for the accepted connection.
    就是说当有人连接你的服务端时,就会把连接者的socket信息都保存在socketDescriptor(即handle)当中

server.h当中

private slots:
    void incomingConnection(qintptr handle);

server.cpp

//只要有一个人链接,就会调用这个方法
void Server::incomingConnection(qintptr handle)
{
    qDebug() <<"有人链接了";
}

打开cmd 输入telnet 127.0.0.1 8888,链接成功显示

在这里插入图片描述

2.4接受连接用户的信息

void Server::incomingConnection(qintptr handle)
{
//    qDebug() <<"有人链接了";

    sock = new QTcpSocket(this);
    sock->setSocketDescriptor(handle);//将连接的用户加入进来,就可以接受用户输入的内容
   
    connect(sock,&QTcpSocket::readyRead,[=](){
        char buffer[1024]; //暂存
        sock->read(buffer,sock->bytesAvailable()); //读取的有效内容存到buffer
        qDebug() << buffer;
    });
}

cmd 输入 telnet 127.0.0.1 8888,连接成功后,在cmd黑窗口输入内容,会显示在QT控制窗口当中

在这里插入图片描述

3.编写客户端

下面可不看:自己的理解

textEdit 富文本框 html也行,消息窗口
plain textedit 只有文本功能
lineEdit单行文本框
listWidget列表界面做好后要先编译,然后才可以正常使用控件编译快捷键ctrl+b,显示日志
客户端接收数据信号readyRead()
信息读取socket->readAll():
将bytearray转为字符串arr.data();
发送消息socket->write(str.toUtf80);采用字节流发送

3.1UI

创建一个client UI

在这里插入图片描述

client.h

#include <QWidget>
#include <QTcpSocket>

namespace Ui {
class Client;
}

class Client : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_connetBtn_clicked();

    void receiveMessage();

    void on_sendBtn_clicked();

private:
    Ui::Client *ui;

    QTcpSocket * socket; //必须new才能实例化
};

client.cpp

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

    setWindowTitle("TCP客户端");
}

Client::~Client()
{
    delete ui;
}

void Client::on_connetBtn_clicked()
{
    socket = new QTcpSocket(this);

    //连接服务器 IP+端口
    socket->connectToHost(ui->IPlineEdit->text(),ui->portlineEdit->text().toInt());

    //接收服务端发来的消息
    connect(socket,&QTcpSocket::readyRead,this,[=](){
        this->receiveMessage();
    });
}

//接收服务端来的信息
void Client::receiveMessage()
{
    QByteArray receivedata = socket->readAll(); //接受的是字符流
    QString str = receivedata.data(); //字符流转换为普通文本
    ui->receivetextEdit->setText(str);
}

//客户端发送信息出去
void Client::on_sendBtn_clicked()
{
    QString sendMessage = ui->sendtextEdit->toPlainText();//普通文本

    socket->write(sendMessage.toUtf8()); //toUtf8()中文不乱码
}

3.2在主窗口写一个跳转页面按钮

方便测试客户端功能

widget.ui拉一个按钮上去,然后,提升槽为clicked

widget.h 创建client指针

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;

    Server server;//实例化,相当于new了

    Client *client;
};

widget.cpp

//显示客户端界面
void Widget::on_pushButton_clicked()
{
    client = new Client(this);

    client->show();
}

在这里插入图片描述

3.3测试客户端发送功能

打开服务端端口后,连接服务端后,点击发送消息

在这里插入图片描述

4.服务端

4.1增加UI

在这里插入图片描述

4.2接收客户端的信息,显示用户上线日志

  • 为了与UI连接,server.h新增加一个server (int port)构造函数,当点击开始监听这个控件时,才开启端口

    server.cpp

    Server::Server(QObject *parent) : QTcpServer(parent)
    {
    
    //    //开启监听
    //    listen(QHostAddress::Any,8888);
    }
    
    Server::Server(int port)
    {
        //开启监听
        listen(QHostAddress::Any,port);
    }
    

    widget.cpp

    void Widget::on_listenPortBtn_clicked()
    {
        int port = ui->portlineEdit->text().toInt();
    
        server = new Server(port);
    
        //开启监听之后,就可以处理客户端发来的信息
        connect(server,&Server::translateClientMessage,this,&Widget::getClientMessage);
    }
    
  • 处理来自客户端的消息

    server.h增加一个translateClientMessage(QString,int)的自定义信号

    class Server : public QTcpServer
    {
        Q_OBJECT
    public:
        explicit Server(QObject *parent = nullptr);
        Server(int port);
    
    private:
        QTcpSocket *sock; //套接字,当别人连上你这个服务端时后,对方的ip地址等的一些信息就存在这里面
    
    signals:
        //自定义接受信号,服务器接收到了客户端的自身socket信息和传过来的文本数据
        void translateClientMessage(QString,int); //1表示文本信息,2表示显示client IP信息
    
    private slots:
        void incomingConnection(qintptr handle);
        void receiveMessage();
    };
    

    server.cpp

    //只要有一个人链接,就会调用这个方法
     void Server::incomingConnection(qintptr handle)
     {
         qDebug() <<"有人链接了";
    
         sock = new QTcpSocket(this);
         sock->setSocketDescriptor(handle);//将连接的用户加入进来,就可以接受用户输入的内容
    
         connect(sock,&QTcpSocket::readyRead,[=](){
             this->receiveMessage();
         });
    
         //获取对方的ip地址
         QString clientIP = sock->peerAddress().toString();
         emit translateClientMessage(clientIP + "上线了",2);
     }
    
    void Server::receiveMessage()
    {
    //    if(sock->bytesAvailable() >0)
    //    {
    //        char buffer[1024]; //暂存
    //        sock->read(buffer,sock->bytesAvailable()); //读取的有效内容存到buffer
    //        qDebug() << buffer;
    //    }
    
        QByteArray byteArrData = sock->readAll();
        QString str = byteArrData.data();
    
        //接收到客户端的发送文本后,触发转发的信号,将这些文本来显示到窗口上
        //有了信号,就要有相应的槽函数,我们要把这些接收的信息显示在窗口UI上,所以槽函数应该写在widget上
        emit translateClientMessage(str,1); //1用来表示接受的是客户端发来的消息
    }
    

    widget.cpp 定义了一个槽函数getClientMessage(QString s,int type)来实现client socket的接收,显示到UI上

    void Widget::getClientMessage(QString s,int type)
    {
        if(type == 1)
        {
            ui->receivetextEdit->setText(s); //显示接收的客户端的信息文本
        }
        else if(type == 2)
        {
            ui->conneterLoglistWidget->addItem(s);//显示连接日志,客户端的IP
        }
    
    }
    

    这里写完,自己试一下,能否运行

    在这里插入图片描述

4.3服务端发送消息给客户端

由于在server.h当中定义的是private:QTcpSocket *sock;,服务端的发送是在widget主窗口上的,所以是无法使用到这个sock,

不可以在widget.cpp当中访问到server.h这个私有属性

server.h增加一个公共接口:public:QTcpSocket * getSock();

server.cpp直接返回这个sock就行

QTcpSocket *Server::getSock()
{
    return this->sock;
}

widget.cpp 提升发送 这个按钮的点击函数

void Widget::on_sendBtn_clicked()
{
    //先获取控件的内容,在发送
   QByteArray serverSendMessage =  ui->sendtextEdit->toPlainText().toUtf8();
   sock = server->getSock();
   sock->write(serverSendMessage);
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值