zoukankan      html  css  js  c++  java
  • Ubuntu上Qt+Tcp网络编程之简单聊天对话框

    首先看一下实现结果:

      >>功能

         (1)服务器和客户端之间进行聊天通信;

         (2)一个服务器可同时给多个客户端发送消息;(全部连接时)

                 也可以只给特定的客户端发送消息;(连接特定IP)

         (3)可发送任意字符,包括中文;(原来参考的程序不能发中文)

      >>后续拓展

         (1)不同客户端之间能否进行通信?

         (2)发完消息之后如何清空发送区?

         (3)如何完善登录注册功能?

         (4)如何更换界面背景及颜色?

          …………

     程序:

    注意:首先需要在每个工程.pro文件里加上一句

    QT       += network

    1.mytcpclient.h

    #ifndef MYTCPCLIENT_H
    #define MYTCPCLIENT_H
    
    #include <QMainWindow>
    #include <QTcpSocket>
    #include <QHostAddress>
    #include <QMessageBox>
    
    namespace Ui {
    class MyTcpClient;
    }
    
    class MyTcpClient : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MyTcpClient(QWidget *parent = 0);
        ~MyTcpClient();
    
    private:
        Ui::MyTcpClient *ui;
        QTcpSocket *tcpClient;
    
    private slots:
        //客户端槽函数
        void ReadData();
        void ReadError(QAbstractSocket::SocketError);
    
        void on_btnConnect_clicked();
        void on_btnSend_clicked();
        void on_btnClear_clicked();
    };
    
    #endif // MYTCPCLIENT_H
    mytcpclient.h

    2.mytcpclient.cpp

    #include "mytcpclient.h"
    #include "ui_mytcpclient.h"
    
    MyTcpClient::MyTcpClient(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MyTcpClient)
    {
        ui->setupUi(this);
    
        //初始化TCP客户端
        tcpClient = new QTcpSocket(this);   //实例化tcpClient
        tcpClient->abort();                 //取消原有连接
        ui->btnConnect->setEnabled(true);
        ui->btnSend->setEnabled(false);
    
        connect(tcpClient, SIGNAL(readyRead()), this, SLOT(ReadData()));
        connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)), 
                this, SLOT(ReadError(QAbstractSocket::SocketError)));
    }
    
    MyTcpClient::~MyTcpClient()
    {
        delete ui;
    }
    
    void MyTcpClient::ReadData()
    {
        //QByteArray buffer = tcpClient->readAll();   //by me
        QByteArray buffer;  //add by me
        buffer.resize(tcpClient->bytesAvailable());//add by me
        tcpClient->read(buffer.data(),buffer.size());//add by me
        if(!buffer.isEmpty())
        {
            QString msg = QString::fromLocal8Bit(buffer.data());//add by me
            ui->edtRecv->append(msg);   //buffer  ->   msg  ;   by me
        }
    }
    
    void MyTcpClient::ReadError(QAbstractSocket::SocketError)
    {
        tcpClient->disconnectFromHost();
        ui->btnConnect->setText(tr("连接"));
        QMessageBox msgBox;
        msgBox.setText(tr("failed to connect server because %1").arg(tcpClient->errorString()));
        msgBox.exec();
    }
    
    void MyTcpClient::on_btnConnect_clicked()
    {
        if(ui->btnConnect->text()=="连接")
        {
            tcpClient->connectToHost(ui->edtIP->text(), ui->edtPort->text().toInt());
            if (tcpClient->waitForConnected(1000))  // 连接成功则进入if{}
            {
                ui->btnConnect->setText("断开");
                ui->btnSend->setEnabled(true);
            }
        }
        else
        {
            tcpClient->disconnectFromHost();
            if (tcpClient->state() == QAbstractSocket::UnconnectedState 
                    || tcpClient->waitForDisconnected(1000))  //已断开连接则进入if{}
            {
                ui->btnConnect->setText("连接");
                ui->btnSend->setEnabled(false);
            }
        }
    }
    
    void MyTcpClient::on_btnSend_clicked()
    {
        QString data = ui->edtSend->toPlainText();
        QByteArray text = data.toLocal8Bit();        //add by me
        if(data != "")
        {
            //tcpClient->write(data.toLatin1()); //qt5出去了.toAscii()     //by me
            tcpClient->write(text,text.length());         //add by me
        }
    }
    
    void MyTcpClient::on_btnClear_clicked()
    {
        ui->edtRecv->clear();
    }
    mytcpclient.cpp

    3.mytcpserver.h

    #ifndef MYTCPSERVER_H
    #define MYTCPSERVER_H
    
    #include <QMainWindow>
    #include <QTcpServer>
    #include <QTcpSocket>
    #include <QNetworkInterface>
    #include <QMessageBox>
    namespace Ui {
    class MyTcpServer;
    }
    
    class MyTcpServer : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MyTcpServer(QWidget *parent = 0);
        ~MyTcpServer();
    
    private:
        Ui::MyTcpServer *ui;
        QTcpServer *tcpServer;
        QList<QTcpSocket*> tcpClient;
        QTcpSocket *currentClient;
    
    private slots:
        void NewConnectionSlot();
        void disconnectedSlot();
        void ReadData();
    
        void on_btnConnect_clicked();
        void on_btnSend_clicked();
        void on_btnClear_clicked();
    };
    
    #endif // MYTCPSERVER_H
    mytcpserver.h

    4.mytcpserver.cpp

    #include "mytcpserver.h"
    #include "ui_mytcpserver.h"
    
    MyTcpServer::MyTcpServer(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MyTcpServer)
    {
        ui->setupUi(this);
    
        tcpServer = new QTcpServer(this);
        ui->edtIP->setText(QNetworkInterface().allAddresses().at(1).toString());   //获取本地IP
        ui->btnConnect->setEnabled(true);
        ui->btnSend->setEnabled(false);
    
        connect(tcpServer, SIGNAL(newConnection()), this, SLOT(NewConnectionSlot()));
    }
    
    MyTcpServer::~MyTcpServer()
    {
        delete ui;
    }
    // newConnection -> newConnectionSlot 新连接建立的槽函数
    void MyTcpServer::NewConnectionSlot()
    {
        currentClient = tcpServer->nextPendingConnection();
        tcpClient.append(currentClient);
        ui->cbxConnection->addItem(tr("%1:%2").arg(currentClient->peerAddress().toString().split("::ffff:")[1])
                                              .arg(currentClient->peerPort()));
        connect(currentClient, SIGNAL(readyRead()), this, SLOT(ReadData()));
        connect(currentClient, SIGNAL(disconnected()), this, SLOT(disconnectedSlot()));
    }
    
    // 客户端数据可读信号,对应的读数据槽函数
    void MyTcpServer::ReadData()
    {
        // 由于readyRead信号并未提供SocketDecriptor,所以需要遍历所有客户端
        for(int i=0; i<tcpClient.length(); i++)
        {
            QByteArray buffer;  //add by me
            buffer.resize(tcpClient[i]->bytesAvailable());//add by me
            tcpClient[i]->read(buffer.data(),buffer.size());//add by me
            //QByteArray buffer = tcpClient[i]->readAll();  //by me
            if(buffer.isEmpty())    continue;
    
            static QString IP_Port, IP_Port_Pre;
            IP_Port = tr("[%1:%2]:").arg(tcpClient[i]->peerAddress().toString().split("::ffff:")[1])
                                         .arg(tcpClient[i]->peerPort());
    
            // 若此次消息的地址与上次不同,则需显示此次消息的客户端地址
            if(IP_Port != IP_Port_Pre)
                ui->edtRecv->append(IP_Port);
    
            QString msg = QString::fromLocal8Bit(buffer.data());//add by me
            ui->edtRecv->append(msg);  //buffer ->  msg ; by me
    
            //更新ip_port
            IP_Port_Pre = IP_Port;
        }
    }
    // disconnected -> disconnectedSlot 客户端断开连接的槽函数
    void MyTcpServer::disconnectedSlot()
    {
        //由于disconnected信号并未提供SocketDescriptor,所以需要遍历寻找
        for(int i=0; i<tcpClient.length(); i++)
        {
            if(tcpClient[i]->state() == QAbstractSocket::UnconnectedState)
            {
                // 删除存储在combox中的客户端信息
                ui->cbxConnection->removeItem(ui->cbxConnection->findText(tr("%1:%2")
                                      .arg(tcpClient[i]->peerAddress().toString().split("::ffff:")[1])
                                      .arg(tcpClient[i]->peerPort())));
                // 删除存储在tcpClient列表中的客户端信息
                 tcpClient[i]->destroyed();
                 tcpClient.removeAt(i);
            }
        }
    }
    // 监听--断开
    void MyTcpServer::on_btnConnect_clicked()
    {
        if(ui->btnConnect->text()=="监听")
        {
            bool ok = tcpServer->listen(QHostAddress::Any, ui->edtPort->text().toInt());
            if(ok)
            {
                ui->btnConnect->setText("断开");
                ui->btnSend->setEnabled(true);
            }
        }
        else
        {
            for(int i=0; i<tcpClient.length(); i++)//断开所有连接
            {
                tcpClient[i]->disconnectFromHost();
                bool ok = tcpClient[i]->waitForDisconnected(1000);
                if(!ok)
                {
                    // 处理异常
                }
                tcpClient.removeAt(i);  //从保存的客户端列表中取去除
            }
            tcpServer->close();     //不再监听端口
            ui->btnConnect->setText("监听");
            ui->btnSend->setEnabled(false);
        }
    }
    // 发送数据
    void MyTcpServer::on_btnSend_clicked()
    {
        QString data = ui->edtSend->toPlainText();
        QByteArray text = data.toLocal8Bit();    //add by me
        if(data == "")  return;    // 文本输入框为空时
        //全部连接
        if(ui->cbxConnection->currentIndex() == 0)
        {
            for(int i=0; i<tcpClient.length(); i++)
                //tcpClient[i]->write(data.toLatin1()); //qt5除去了.toAscii()    //by me
                tcpClient[i]->write(text,text.length());         //add by me
        }
        //指定连接
        else
        {
            QString clientIP = ui->cbxConnection->currentText().split(":")[0];
            int clientPort = ui->cbxConnection->currentText().split(":")[1].toInt();
    //        qDebug() << clientIP;
    //        qDebug() << clientPort;
            for(int i=0; i<tcpClient.length(); i++)
            {
                if(tcpClient[i]->peerAddress().toString().split("::ffff:")[1]==clientIP
                                && tcpClient[i]->peerPort()==clientPort)
                {
                    //tcpClient[i]->write(data.toLatin1());    //by me
                    tcpClient[i]->write(text,text.length());   //add by me
                    return; //ip:port唯一,无需继续检索
                }
            }
        }
    }
    
    void MyTcpServer::on_btnClear_clicked()
    {
        ui->edtRecv->clear();
    }
    mytcpserver.cpp

    5.mytcpclient.ui

    6.mytcpserver.ui

  • 相关阅读:
    Gradle gitignore Gradle 模式 上传SVN 要忽略的文件
    加速Android Studio/Gradle构建
    JAVA unicode转换成中文
    进程与线程
    Flask快速入门
    tensorflow入门指南
    BP神经网络与Python实现
    文档数据库MongoDB
    Python虚拟环境virtualenv
    Python爬虫框架Scrapy
  • 原文地址:https://www.cnblogs.com/ylsm-kb/p/9092527.html
Copyright © 2011-2022 走看看