Qt——基于 TCP的网络聊天程序

一、TCP编程模型

在这里插入图片描述
Qt 中是通过 QTcpSocket类 和 QTcpServer类 实现TCP协议的编程。下面编写一个基于 TCP 协议的网络聊天室应用,它同样也是由 客户端 和 服务器两部分组成的。

二、效果展示

在这里插入图片描述

三、代码实现

1.服务器端

server.h:

#ifndef SERVER_H
#define SERVER_H

#include <QObject>
#include <QTcpServer>

#include "tcpclientsocket.h"

class Server : public QTcpServer
{
    Q_OBJECT
public:
    Server(QObject * parent = 0,int port = 0);
    QList<TcpClientSocket*> tcpClientSocketList;

signals:
    void updateServer(QByteArray);

public slots:
    void updateClients(QByteArray);
    void slotDisconnected(int);

protected:
    void incomingConnection(int socketDescriptor);

};

#endif // SERVER_H


tcpclientsocket.h:

#ifndef TCPCLIENTSOCKET_H
#define TCPCLIENTSOCKET_H

#include <QObject>
#include <QTcpSocket>

class TcpClientSocket : public QTcpSocket
{
    Q_OBJECT
public:
    TcpClientSocket(QObject *parent = nullptr);

signals:
    void updateClients(QByteArray);
    void disconnected(int);

protected slots:
    void dataReceived();
    void slotDisconnected();
};

#endif // TCPCLIENTSOCKET_H


tcpserver.h:

#ifndef TCPSERVER_H
#define TCPSERVER_H

#include <QDialog>
#include <QListWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QGridLayout>

#include "server.h"


class TcpServer : public QDialog
{
    Q_OBJECT

public:
    TcpServer(QWidget *parent = nullptr,Qt::WindowFlags f = 0);
    ~TcpServer();

public slots:
    void slotCreateServer();
    void updateServer(QByteArray);

private:
    QListWidget * contentListWidget;
    QLabel * portLabel;
    QLineEdit * portLineEdit;
    QPushButton * createBtn;
    QGridLayout * mainLayout;

    int port;
    Server * server;
};
#endif // TCPSERVER_H


main.cpp:

#include "tcpserver.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TcpServer w;
    w.show();
    return a.exec();
}


server.cpp:

#include "server.h"

Server::Server(QObject * parent,int port)
    :QTcpServer(parent)
{
    listen(QHostAddress::Any,port);
}


void Server::incomingConnection(int socketDescriptor){
    TcpClientSocket * tcpClientSocket = new TcpClientSocket(this);

    connect(tcpClientSocket,SIGNAL(updateClients(QByteArray)),
            this,SLOT(updateClients(QByteArray)));

    connect(tcpClientSocket,SIGNAL(disconnected(int)),
            this,SLOT(slotDisconnected(int)));

    tcpClientSocket->setSocketDescriptor(socketDescriptor);

    tcpClientSocketList.append(tcpClientSocket);
}

void Server::updateClients(QByteArray msg){

    emit updateServer(msg);

    for(int i = 0;i < tcpClientSocketList.count();i++){
        QTcpSocket * item = tcpClientSocketList.at(i);
        if(item->write(msg) != -1){
            continue;
        }
    }

}

void Server::slotDisconnected(int descriptor){
    for(int i = 0;i < tcpClientSocketList.count();i++){
        QTcpSocket * item = tcpClientSocketList.at(i);
        if(item->socketDescriptor() == descriptor){
            tcpClientSocketList.removeAt(i);
            return;
        }
    }
}


tcpclientsocket.cpp:

#include "tcpclientsocket.h"

TcpClientSocket::TcpClientSocket(QObject *parent) : QTcpSocket(parent)
{
    connect(this,SIGNAL(readyRead()),this,SLOT(dataReceived()));

    connect(this,SIGNAL(disconnected()),this,SLOT(slotDisconnected()));


}

void TcpClientSocket::dataReceived(){
    while(bytesAvailable() > 0){
        QByteArray datagram = readAll();
        emit updateClients(datagram);
    }
}

void TcpClientSocket::slotDisconnected(){
    emit disconnected(this->socketDescriptor());
}





tcpserver.cpp:

#include "tcpserver.h"

TcpServer::TcpServer(QWidget *parent,Qt::WindowFlags f)
    : QDialog(parent,f)
{
    setWindowTitle(tr("TCP Server"));

    contentListWidget = new QListWidget;
    portLabel = new QLabel(tr("端口:"));
    portLineEdit = new QLineEdit;
    createBtn = new QPushButton(tr("创建聊天室"));


    port = 8010;
    portLineEdit->setText(QString::number(port));


    mainLayout = new QGridLayout(this);

    mainLayout->addWidget(contentListWidget,0,0,1,2);
    mainLayout->addWidget(portLabel,1,0);
    mainLayout->addWidget(portLineEdit,1,1);
    mainLayout->addWidget(createBtn,2,0,1,2);


    connect(createBtn,SIGNAL(clicked()),this,SLOT(slotCreateServer()));

}

void TcpServer::slotCreateServer(){
    server = new Server(this,port);

    connect(server,SIGNAL(updateServer(QByteArray)),
            this,SLOT(updateServer(QByteArray)));

    createBtn->setEnabled(false);
}

void TcpServer::updateServer(QByteArray msg){
    contentListWidget->addItem(QString::fromUtf8(msg));
}

TcpServer::~TcpServer()
{
}



2.客户端

tcpclient.h:

#ifndef TCPCLIENT_H
#define TCPCLIENT_H

#include <QDialog>
#include <QListWidget>
#include <QLineEdit>
#include <QPushButton>
#include <QLabel>
#include <QGridLayout>

#include <QHostAddress>
#include <QTcpSocket>


class TcpClient : public QDialog
{
    Q_OBJECT

public:
    TcpClient(QWidget *parent = nullptr);
    ~TcpClient();

public slots:
    void slotEnter();
    void slotConnected();
    void dataReceived();
    void slotSend();

private:
    QListWidget * contentListWidget;
    QLineEdit * sendLineEdit;
    QPushButton * sendBtn;
    QLabel * usernameLabel;
    QLineEdit * usernameLineEdit;
    QLabel * serverIPLabel;
    QLineEdit * serverIPLineEdit;
    QLabel * portLabel;
    QLineEdit * portLineEdit;
    QPushButton * enterBtn;
    QGridLayout * mainLayout;

    bool status;
    int port;
    QHostAddress * serverIP;
    QString username;
    QTcpSocket * tcpSocket;

};
#endif // TCPCLIENT_H


main.cpp:

#include "tcpclient.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TcpClient w;
    w.show();
    return a.exec();
}


tcpclient.cpp:

#include "tcpclient.h"

#include <QMessageBox>
#include <QHostInfo>
#include <QDebug>

TcpClient::TcpClient(QWidget *parent)
    : QDialog(parent)
{
    setWindowTitle(tr("TCP Client"));

    contentListWidget = new QListWidget;
    sendLineEdit = new QLineEdit;
    sendBtn = new QPushButton(tr("发送"));

    usernameLabel = new QLabel(tr("用户名:"));
    usernameLineEdit = new QLineEdit;

    serverIPLabel = new QLabel(tr("服务器地址:"));
    serverIPLineEdit = new QLineEdit;

    portLabel = new QLabel(tr("端口:"));
    portLineEdit = new QLineEdit;

    enterBtn = new QPushButton(tr("进入聊天室"));

    status = false;
    port = 8010;
    portLineEdit->setText(QString::number(port));
    serverIP = new QHostAddress();

    mainLayout = new QGridLayout(this);

    mainLayout->addWidget(contentListWidget,0,0,1,2);
    mainLayout->addWidget(sendLineEdit,1,0);
    mainLayout->addWidget(sendBtn,1,1);
    mainLayout->addWidget(usernameLabel,2,0);
    mainLayout->addWidget(usernameLineEdit,2,1);
    mainLayout->addWidget(serverIPLabel,3,0);
    mainLayout->addWidget(serverIPLineEdit,3,1);
    mainLayout->addWidget(portLabel,4,0);
    mainLayout->addWidget(portLineEdit,4,1);
    mainLayout->addWidget(enterBtn,5,0,1,2);

    connect(enterBtn,SIGNAL(clicked()),this,SLOT(slotEnter()));

    connect(sendBtn,SIGNAL(clicked()),this,SLOT(slotSend()));

    sendBtn->setEnabled(false);
}

void TcpClient::slotEnter(){
    if(!status){
        QString ip = serverIPLineEdit->text();
        if(!serverIP->setAddress(ip)){
            QMessageBox::information(this,tr("error"),tr("server ip address error!"));
            return;
        }

        if(usernameLineEdit->text() == ""){
            QMessageBox::information(this,tr("error"),tr("username error!"));
            return;
        }

        username = usernameLineEdit->text();
        tcpSocket = new QTcpSocket(this);

        connect(tcpSocket,SIGNAL(connected()),this,SLOT(slotConnected()));

        connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));

        tcpSocket->connectToHost(*serverIP,port);
        status = true;

        if(status) qDebug() << "进入了聊天室"<<endl;
    }
    else{

        sendBtn->setEnabled(false);
        enterBtn->setText(tr("进入聊天室"));

        //清空
        usernameLineEdit->setText("");
        sendLineEdit->setText("");
        portLineEdit->setText("");
        serverIPLineEdit->setText("");

        status = false;
        if(!status) qDebug() << "离开了聊天室"<<endl;

        QString msg = username + tr(":Leave chat room");
        if(tcpSocket->write(msg.toUtf8()) != -1){
            return;
        }

        //tcp 断开连接
        tcpSocket->disconnectFromHost();

    }
}

void TcpClient::slotConnected(){
    sendBtn->setEnabled(true);
    enterBtn->setText(tr("离开"));

    QString msg = username + tr(":Enter Chat Room");
    if(tcpSocket->write(msg.toUtf8()) != -1){
        return;
    }
}

void TcpClient::slotSend(){
    if(sendLineEdit->text() == ""){
        return;
    }

    QString msg = username + ":" + sendLineEdit->text();
    tcpSocket->write(msg.toUtf8());
    sendLineEdit->clear();
}


void TcpClient::dataReceived(){
    while(tcpSocket->bytesAvailable() > 0){
        QByteArray datagram = tcpSocket->readAll();
        contentListWidget->addItem(QString::fromUtf8(datagram));
    }
}

TcpClient::~TcpClient()
{
}

3.注意

为了实现中文不出现乱码,我将则很难哥哥过程中的通信数据格式全部转成了 utf8格式。

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值