QT TCP服务器/客户端【多线程】

服务器

文件结构
首先要在.pro文件中添加network,否则将不能使用QTcpserver

QT       += core gui network
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#define PORT 8000

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void newClientHandler();
    void clientInfoSlot();

    void on_sendButton_clicked();

private:
    Ui::Widget *ui;
    QTcpServer *server;
    QTcpSocket *socket;
};
#endif // WIDGET_H

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    server = new QTcpServer;
    //开启端口监视(服务)
    server->listen(QHostAddress::AnyIPv4,PORT);
    //将Server的新连接信号,绑定newClientHandler槽函数
    connect(server,&QTcpServer::newConnection,this,&Widget::newClientHandler);
}

Widget::~Widget()
{
    delete ui;
}
void Widget::newClientHandler()
{
    //建立TCP连接,sever
    socket = server->nextPendingConnection();
    ui->addresslineEdit->setText(socket->peerAddress().toString());
    ui->portlineEdit->setText(QString::number(socket->peerPort()));
    //将Socket的数据就绪信号,绑定clientInfoSlot槽函数
    connect(socket,&QTcpSocket::readyRead,this,&Widget::clientInfoSlot);

}
void Widget::clientInfoSlot()
{
    //获取信号的发出者
    QTcpSocket *socket=(QTcpSocket *)sender();
    ui->revlineEdit->setText(QString(socket->readAll()));
}

void Widget::on_sendButton_clicked()
{
    QByteArray ba;
    ba.append(ui->sendlineEdit->text().toLatin1());
    socket->write(ba);
}


在这里插入图片描述

客户端

在这里插入图片描述
同样的,别忘了在.pro文件中修改

QT       += core gui network

客户端建立连接之后开启新窗口chat

#ifndef CHAT_H
#define CHAT_H

#include <QWidget>
#include<QTcpSocket>
namespace Ui {
class chat;
}

class chat : public QWidget
{
    Q_OBJECT

public:
    explicit chat(QTcpSocket *socket,QWidget *parent = nullptr);
    ~chat();

private slots:
    void on_sendButton_clicked();

    void on_clearButton_clicked();

    void clientReadHandler();

private:
    Ui::chat *ui;
    QTcpSocket *socket;
};

#endif // CHAT_H

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<QTcpsocket>
#include<QHostAddress>
#include<QMessageBox>
#include "chat.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_cancelButton_clicked();

    void on_connectButton_clicked();

private:
    Ui::Widget *ui;
    QTcpSocket *socket;
    chat *ch;
};
#endif // WIDGET_H

#include "chat.h"
#include "ui_chat.h"

chat::chat(QTcpSocket *s,QWidget *parent) :
    QWidget(parent),
    ui(new Ui::chat)
{
    ui->setupUi(this);
    socket = s;
    connect(socket,&QTcpSocket::readyRead,this,&chat::clientReadHandler);
}

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

void chat::on_sendButton_clicked()
{
    QByteArray ba;
    ba.append(ui->lineEdit->text().toLatin1());
    socket->write(ba);
}


void chat::on_clearButton_clicked()
{
    ui->lineEdit->clear();
}

void chat::clientReadHandler()
{
    ui->revlineEdit->setText(QString(socket->readAll()));
}

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    socket = new QTcpSocket;
}

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

void Widget::on_connectButton_clicked()
{
    QString ip = ui->iplineEdit->text();
    QString port = ui->portlineEdit->text();
    qDebug() << ip;
    qDebug() << port;

    socket->connectToHost(QHostAddress(ip),port.toShort());
    //绑定QTcpSocket::connected信号
    connect(socket,&QTcpSocket::connected,[this]{
        QMessageBox::information(this,"Tip","连接成功");
        this->hide();
        //开启新窗口,将socket作为参数。
        ch = new chat(socket);
        ch->show();
    });
    connect(socket,&QTcpSocket::disconnected,[this]{
        QMessageBox::information(this,"Tip","连接失败!");
    });
}

void Widget::on_cancelButton_clicked()
{
    this->close();
}

在这里插入图片描述
在这里插入图片描述

多线程版本【针对服务端】

当存在多个客户端连接服务端的时候,如果只用一个线程,会造成先启动的客户端无法读写。此时,需要服务端开启多线程服务。
在这里插入图片描述
在这里插入图片描述

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QThread>
#include<QTcpSocket>
#include<QDebug>

class myThread : public QThread
{
    Q_OBJECT
public:
    explicit myThread(QTcpSocket *socket);
    void run();
signals:
    void sentToWidget(QByteArray *b);
private slots:
    void clientinfoSolt();
private:
    QTcpSocket *socket;
    QByteArray *ba;
};

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include"mythread.h"

#define PORT 8000

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void newClientHandler();
    void clientInfoSlot();

    void on_sendButton_clicked();
    void threadSlot(QByteArray *b);
private:
    Ui::Widget *ui;
    QTcpServer *server;
    QTcpSocket *socket;
};
#endif // WIDGET_H

#include "mythread.h"

myThread::myThread(QTcpSocket *s)
    :socket{s}
{
    ba = new QByteArray;
}
void myThread::run()
{
    Qt::HANDLE hd = QThread::currentThreadId();
    QString hdstr = QString::number(reinterpret_cast<quintptr>(hd));
    qDebug()<<"线程:";
    qDebug()<<hdstr;
    ba->append("th ID:");
    ba->append(hdstr.toUtf8());
    connect(socket,&QTcpSocket::readyRead,this,&myThread::clientinfoSolt);
}
void myThread::clientinfoSolt()
{
    //qDebug()<<socket->readAll();
    ba->append(socket->readAll());
    emit sentToWidget(ba);//发送信号
}

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    server = new QTcpServer;
    server->listen(QHostAddress::AnyIPv4,PORT);
    connect(server,&QTcpServer::newConnection,this,&Widget::newClientHandler);
}

Widget::~Widget()
{
    delete ui;
}
void Widget::newClientHandler()
{
    //建立TCP连接
    socket = server->nextPendingConnection();
    ui->addresslineEdit->setText(socket->peerAddress().toString());
    ui->portlineEdit->setText(QString::number(socket->peerPort()));
    connect(socket,&QTcpSocket::readyRead,this,&Widget::clientInfoSlot);
    //启动线程
    myThread *t = new myThread(socket);//创建线程对象
    t->start();

    connect(t,&myThread::sentToWidget,this,&Widget::threadSlot);
}
void Widget::threadSlot(QByteArray *b)
{
    ui->revlineEdit->append(QString(*b));
}

void Widget::clientInfoSlot()
{
    //获取信号的发出者
    QTcpSocket *socket=(QTcpSocket *)sender();
    //ui->revlineEdit->setText(QString(socket->readAll()));
    ui->revlineEdit->append(QString(socket->readAll()));
}

void Widget::on_sendButton_clicked()
{
    QByteArray ba;
    ba.append(ui->sendlineEdit->text().toLatin1());
    socket->write(ba);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿波茨的鹅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值