【QT】TCP简易聊天框

时间:2024-03-15 13:13:42

在这里插入图片描述

我们首先复习一下TCP通信的流程

基于linuxTCP客户端和服务器

QT下的TCP处理流程

服务器先启动(处于监听状态)

在这里插入图片描述

各函数的意义和使用

  • QTcpServer Class

    *QTcpServer*类提供了一个基于TCP的服务器。这个类可以接受传入的TCP连接。您可以指定端口或让QTcpServer自动选择一个端口。您可以收听特定地址或所有机器的地址。调用listen()让服务器侦听传入的连接。每次客户端连接到服务器时,都会发出newConnection()信号。

  • QTcpSocket Class

    QTcpSocket类提供了一个TCP套接字。TCP(传输控制协议)是一种可靠的,面向流的,面向连接的传输协议。 它特别适合连续传输数据。QTcpSocketQAbstractSocket的一个方便的子类,它允许你建立一个TCP连接并传输数据流。

    • 服务器端以监听的方式监听listen()客户端是否有连接请求
    • 客户端以调用**connectToHost()**函数主动连接服务器端
  • listen():Qt中,服务端的监听套接字不再是socket,而是QTcpServerQTcpSocket。此外,它将绑定bind()和监听listen()合为一个函数,即监听listen(),在调用的同时指定主机地址和端口号。

  • connectToHost()【客户端】
    而客户端的通信套接字也不再是socket,而是QTcpSocket,连接也不是connect(),而是connectToHost(),意为主动向主机(服务端)发起连接。

  • newConnection()【服务端】
    如果客户端发起连接并且成功,服务端将会收到一个信号。在Qt中,服务端不再是由accept()来确定连接的建立,而是会触发一个newConnection信号。既然是信号,就要有与之对应的槽函数。槽函数中主要的工作是取出建立好的套接字QTcpSocket(它是真正的通信套接字)。

  • write()【服务端/客户端】
    客户端用write()发送数据,如果数据传送成功,对方的通信套接字会触发readyRead()信号(继承自QIODevice类的信号),说明可以开始读数据了,我们需要在对应的槽函数中做接收处理。反过来,服务端给客户端发信息也是一样的。

  • connected() & disconnected()【服务端/客户端】
    只要成功与对方建立连接,无论是服务端还是客户端,通信套接字都会自动触发

  • **connected()**信号,而如果对方主动断开连接,通信套接字会自动触发disconnected()信号,我们可以利用这两个信号作出一些提示,比如在客户端与服务器端成功连接后,在客户端窗口输出“已成功连接服务器!”或者“已与服务器断开连接!”。

添加TCP模块

在这里插入图片描述

#include <QTcpServer>
#include <QTcpSocket>

在这里插入图片描述

## client.ui

client.h/server.h


#include <QTcpSocket>
...
class Client : public QWidget
{
  ...
private:
    Ui::Client *ui;
  QTcpSocket *client_chat;
 
  -------------------------------------

#include <QTcpSocket>
#include <QTcpServer>
#include <QPushButton>
....
class Server : public QWidget
{
  ....
private:
    Ui::Server *ui;
     QTcpServer *watch;//监听
    QTcpSocket *chat;  //通信
};

#endif // SERVER_H

client.cpp

#include "client.h"
#include "ui_client.h"
#include <QTcpSocket>
#include <QHostAddress>
#include <QDebug>
Client::Client(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Client)
{
    ui->setupUi(this);

    ui->sIP->setText("127.0.0.1");
    ui->sPort->setText("8000");

    client_chat = new QTcpSocket(this);
    client_chat->connectToHost(QHostAddress(ui->sIP->text()),8000);
    connect(client_chat,&QTcpSocket::readyRead,this,[=](){

        qDebug()<<1;
        QByteArray qba2 = client_chat->readAll();
        ui->record->append("对方说"+qba2);

    });

    connect(ui->send,&QPushButton::clicked,this,[=](){
       client_chat->write(ui->input->toPlainText().toUtf8());

       ui->record->append("Me say:"+ui->input->toPlainText());
       ui->input->clear();
    });
}

server.cpp

#include "server.h"
#include "ui_server.h"
#include <QDebug>
Server::Server(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Server)
{
    ui->setupUi(this);
    ui->sIP->setText("127.0.0.1");
    ui->sPort->setText("8000");

    watch = new QTcpServer(this);
                                //这里类型转换有点问题,因此我直接写8000
    watch->listen(QHostAddress(ui->sIP->text()),8000);

    connect(watch,&QTcpServer::newConnection,this,[=](){
       chat = watch->nextPendingConnection();
       ui->record->append("有新的连接");

       QList<QTcpSocket*>socketList;
       socketList.append(chat);
       QString IP= chat->peerAddress().toString();
       quint16 PORT = chat->peerPort();

       qDebug()<<socketList;
       qDebug()<<IP<<PORT;

       connect(chat,&QTcpSocket::readyRead,this,[=](){
          QByteArray qba = chat->readAll();
          ui->record->append("对方说:"+qba);
       });
    });

    connect(ui->send,&QPushButton::clicked,this,[=](){
       chat->write(ui->input->toPlainText().toUtf8());
      ui->record->append("MeSay:"+ui->input->toPlainText());

      ui->input->clear();

    });
}

main.c

#include "server.h"
#include "client.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Server w;
    w.show();

    Client c;
    c.setWindowTitle("客户端");
    c.show();
    return a.exec();
}

在这里插入图片描述