(9) Qt — network programming (half-duplex communication)

Directory

1. review

1.1 UDP and TCP

1.2 IP address and port number

2. Preparation

3. Programming content


1. Review

1.1 UDP and TCP

The same point of UDP and TCP protocols: both exist in the transport layer

  • TCP (Transmission Control Protocol):

It is a connection-oriented transport layer protocol, which can provide high-reliability communication (that is, data is correct, data is not lost,

Data without out-of-sequence, data without duplicate arrival communication)

Applicable situation:

1. It is suitable for communication that requires high transmission quality and transmits a large amount of data.

2. When reliable data transmission is required, the TCP protocol is usually used

3. Functions related to user login account management of MSN/QQ and other instant messaging software usually use TCP protocol

  • UDP : User Datagram Protocol

UDP (User Datagram Protocol) is an unreliable connectionless protocol. Since no connection is required before data is sent, efficient data transmission is possible.

Applicable situation:

1. Send small size data (such as when querying the IP address of the DNS server)

2. UDP is used in networks where it is difficult to receive data and give a response.

3. Suitable for broadcast/multicast communication.

4. The point-to-point text communication and audio and video communication of instant messaging software such as MSN/QQ/Skype usually use UDP protocol

5. Streaming media, VOD, VoIP, IPTV and other network multimedia services usually use UDP for real-time data transmission

1.2 IP address and port number

  • IP address

basic concept:

The IP address is the identification of the host in the Internet, and the host in the Internet must have an IP address to communicate with other machines.

  • Port number

basic concept:

In order to distinguish which process a data packet received by a host should be forwarded to for processing, the port number is used to distinguish.

Well-known ports: 1~1023 (1~255 are well-known ports, 256~1023 ports are usually occupied by UNIX systems)

Registered ports: 1024~49151

Dynamic or private port: 49152~65535

Suggestion for the port number of the custom program: 2000-65535, remove the serial number, such as 8888

2. Preparation

Like the database, the network function also needs to add the network module in the .pro file.

Qt’s TCP communication structure diagram is shown below (the principle is roughly shown in the figure below, but the specific API is different).

3. Programming Content

To implement a TCP-based chat program this time, the classes that need to be used are:

  • QTcpServer

Server management class: manages multiple connections to the server, directly inheriting QObject, so it does not have IO capabilities.

The relevant functions are as follows:

// Constructor
QTcpServer::QTcpServer(QObject * parent = 0)
// The server starts monitoring and waits for the client to initiate a connection
// Parameter 1: Which IP address to monitor the request from, the default value is not limited to the IP address, and the QHostAddress class is the encapsulation class of the IP address.
// Parameter 2: server port number
// Return value: monitor the opening result
bool QTcpServer::listen(
                const QHostAddress & address = QHostAddress::Any,
                quint16 port = 0)
// Notification signal for new connection establishment
void QTcpServer::newConnection() [signal]
// Is the server still listening
bool QTcpServer::isListening() const
// close the server
void QTcpServer::close()
// Return a ready connection object, which is used to perform IO operations with a client
QTcpSocket * QTcpServer::nextPendingConnection() [virtual]
  • QTcpSocket

TCP connection class: perform network IO operations, and indirectly inherit the QIODevice class.

The relevant functions are as follows:

// Constructor
QTcpSocket::QTcpSocket(QObject * parent = 0)
// connect to the server
// Parameter 1: IP address of the server
// Parameter 2: The port number of the server
// Parameter 3: Read and write mode, the default is readable and writable
void QAbstractSocket::connectToHost(const QString & amp; hostName,
                                    quint16 port,
                                    OpenMode openMode = ReadWrite) [virtual]
// Whether the connection is open
bool QIODevice::isOpen() const
// close the connection
void QIODevice::close() [virtual]
// Get the opposite IP address encapsulation class object, if there is no connection, return QHostAddress::Null
QHostAddress QAbstractSocket::peerAddress() const
// The signal emitted by disconnection
void QAbstractSocket::disconnected() [signal]
// The signal emitted when there is data to read
void QIODevice::readyRead() [signal]
  • QTextStream

Text stream class: It is an auxiliary class for efficient text data IO.

// Constructor
// The parameter is the derived class object of QIODevice
QTextStream::QTextStream(QIODevice * device)
// send string
// The parameter must be of type QString, be careful not to use const char*
// The return value is a reference of the current type, indicating that chain calls are supported, so the sent content is appended continuously
QTextStream & amp; QTextStream::operator<<(const QString & amp; string)
// Read the content with a maximum value of maxlen characters to the return value
QString QTextStream::read(qint64 maxlen)
// Read a line of characters with the maximum number of characters maxlen to the return value
QString QTextStream::readLine(qint64 maxlen = 0)
// read all characters to the return value
//
QString QTextStream::readAll()

Client: (QTcpSocket)
① Create a QTcpSocket object

②When the object is successfully connected to the server, a connected signal will be sent

③Call the member function connectToHost to connect to the server, the required parameters are address and port number

④The slot function of the connected signal starts sending data

⑤Use write to send data, read to receive data

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QtWidgets>
//connection class
#include <QTcpSocket>
//file stream class
#include <QTextStream>
#include <QTcpServer>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

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

private:
    Ui::Dialog *ui;
    QTcpSocket *client; //Connection object

private slots:
    void btnConnClickedSlot();
    void btnSendClickedSlot();
    //Connection and disconnection detection slot function
    void connectedSlot();
    void diaconnectedSlot();
    void readReadSlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

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

    connect(ui->pushButtonConn,SIGNAL(clicked()),this,SLOT(btnConnClickedSlot()));
    connect(ui->pushButtonSend,SIGNAL(clicked()),this,SLOT(btnSendClickedSlot()));

    //set window as top level
    setWindowFlags(Qt::WindowStaysOnTopHint);

    // create connection object
    client = new QTcpSocket(this);
    //client = new QTcpServer(this);
    //Signal slot for connection status detection
    connect(client,SIGNAL(connected()),this,SLOT(connectedSlot()));
    connect(client,SIGNAL(disconnected()),this,SLOT(diaconnectedSlot()));
    connect(client,SIGNAL(readyRead()),this,SLOT(readReadSlot()));

}

Dialog::~Dialog()
{
    // If the client is still connected, close it
    if(client->isOpen()){
        client->close();
    }
    delete ui;
}
void Dialog::btnConnClickedSlot(){
    //The default input is valid, connect to the server
    //Parameter 1: IP address of the server
    //Parameter 2: The port number of the server
    client->connectToHost(ui->lineEditIp->text(),8887);

}

void Dialog::btnSendClickedSlot(){
    // Get the content entered by the user
     QString msg = ui->lineEditMsg->text();
     if(msg == ""){
         QMessageBox::warning(this,"Prompt","Please enter the content to be sent!");
         return;
     }
     //Create a text stream object
     QTextStream output(client);
     //Send Content
     output << msg;
     //clear the input box
     ui->lineEditMsg->clear();
     QString time = QDateTime::currentDateTime().toString("hh:mm:ss");
     ui->textBrowser->append(time);
     ui->textBrowser->append("Client:");
     ui->textBrowser->append(msg);
     ui->textBrowser->append("");
}

void Dialog::connectedSlot()
{
    //shield connect button
    ui->pushButtonConn->setEnabled(false);
    ui->pushButtonConn->setText("connected");
    //Release the send button
    ui->pushButtonSend->setEnabled(true);
}

void Dialog::diaconnectedSlot()
{
    //Resume connection button
    ui->pushButtonConn->setEnabled(true);
    ui->pushButtonConn->setText("Connect!");
    //block the send button
    ui->pushButtonSend->setEnabled(false);
}
void Dialog::readReadSlot(){
    QString time = QDateTime::currentDateTime().toString("hh:mm:ss");
    ui->textBrowser->append(time);
    QTextStream input(client);
    QString msg = input. readAll();
    ui->textBrowser->append("Server:");
    ui->textBrowser->append(msg);
    ui->textBrowser->append("");
}

ui interface

Server: (QTcpServer)
① Create a QTcpServer object

②The parameters required to monitor the list are address and port number

③When a new client connects successfully, send a newConnect signal

④In the newConnection signal slot function, call the nextPendingConnection function to obtain the new connection QTcpSocket object

⑤Connect to the readRead signal of the QTcpSocket object

⑥Use read to receive data in the slot function of the readRead signal

⑦Call the write member function to send data

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QtWidgets>
//Network related classes
#include <QTcpServer>
#include <QTcpSocket>
#include <QDateTime>
#include <QTextStream>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

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

private:
    Ui::Dialog *ui;
    // management class server object
    QTcpServer *server;
    QTcpSocket*socket = NULL; // During the simple period, only one client connection is reserved

private slots:
    //Slot function for new connection establishment
    void newConnSlot();
    //Slot function for network connection disconnection
    void disconnectedSlot();
    //Slot function to read information
    void readReadSlot();
    void btnSendClickSlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    // Set the window flag, always displayed in the foreground
    setWindowFlags(Qt::WindowStaysOnTopHint);
    // Create management class object
    server = new QTcpServer(this);
    //server = new QTcpSocket(this);
    //Connect to the signal slot notified by the server
    connect(server,SIGNAL(newConnection()),this,SLOT(newConnSlot()));
    // Turn on monitoring and wait for the client to initiate a connection
    //Parameter 1: Listen to the request from which IP address, the default value is not limited to the IP address
    //QHostAddress class is the encapsulation class of ip address
    //parameter 2: server port number
    server->listen(QHostAddress::Any,8887);

}

Dialog::~Dialog()
{
    if(server->isListening()) // if listening
            // close the server
            server->close();
    delete ui;
}


void Dialog::newConnSlot()
{
    //If it is not the first connection, kick off the previous connection first
    if(socket!=NULL){
        socket->close();
    }
    //Get the QTcpSocket object connected to the client (green egg)
    socket = server->nextPendingConnection();
    / / Create a signal slot for disconnection notification
    connect(socket,SIGNAL(disconnected()),this,SLOT(disconnectedSlot()));
    //Create a signal slot for reading messages
    connect(socket,SIGNAL(readyRead()),this,SLOT(readReadSlot()));

    connect(ui->pushButtonSend,SIGNAL(clicked()),this,SLOT(btnSendClickSlot()));

    //Get the IP and port number of the opposite client
    QString ip = socket->peerAddress().toString();
    quint16 port = socket->peerPort();
    // output information
    QString time = QDateTime::currentDateTime().toString("hh:mm:ss");
    ui->textBrowser->append(time);
    ui->textBrowser->append("A new connection is coming!");
    ui->textBrowser->append(ip.append(":").append(QString::number(port)));
    ui->textBrowser->append("");


}

void Dialog::disconnectedSlot()
{
    //Get the IP and port number of the opposite client
    QString ip = socket->peerAddress().toString();
    quint16 port = socket->peerPort();
    // output information
    QString time = QDateTime::currentDateTime().toString("hh:mm:ss");
    ui->textBrowser->append(time);
    ui->textBrowser->append("The old connection is gone!");
    ui->textBrowser->append(ip.append(":").append(QString::number(port)));
    ui->textBrowser->append("");
}

void Dialog::readReadSlot()
{
    QString time = QDateTime::currentDateTime().toString("hh:mm:ss");
    ui->textBrowser->append(time);
    QTextStream input(socket);
    // read data
    QString msg = input. readAll();
    //exhibit
    ui->textBrowser->append("Client:");
    ui->textBrowser->append(msg);
    ui->textBrowser->append("");
}

void Dialog::btnSendClickSlot()
{
    QString msg2 = ui->lineEditMsg->text();
    if(msg2 == ""){
        QMessageBox::warning(this,"Prompt","Please enter the content to be sent!");
        return;
    }
    QTextStream output(socket);
    output << msg2;
    ui->lineEditMsg->clear();
    QString time = QDateTime::currentDateTime().toString("hh:mm:ss");
    ui->textBrowser->append(time);
    ui->textBrowser->append("Server:");
    ui->textBrowser->append(msg2);
    ui->textBrowser->append("");

}

ui interface

operation result: