**
introduction
**
TCP/IP communication (i.e. SOCKET communication) is the communication established through TCP/IP protocol on the basis of following the four-tier architecture of ISO/OSI model by connecting the Server end of the Server and the Client end of the Client through the network cable. The controller can be set as Server or Client.
For details of TCP/IP protocol: TCP/IP protocol details - Zhihu (zhihu.com)
Generally speaking, TCP/IP communication has two parts:
Client and server
QTcpServer (listening socket) and QTcpSocket (communication socket)
Listening socket, as the name suggests, monitors the status of various communications. Once communication is carried out, the listening socket will start the communication socket for communication
After the client actively connects to the server using the connectToHost function, the server will trigger the slot function newConnectio, take out the QTcpServer (listening socket), take out the relevant contents and assign them to the QTcpSocket (communication socket).
The client sends data to the server and triggers readyRead() for processing. The principle is the same when transmitting data to each other.
What works for both parties:
Once a connection is established, it will trigger connected. In particular, the server triggers newConnectio
The same is true for mutual data transmission. Once received, readyread will be triggered
In the server, a listening socket and a communication socket are required. The listening socket is used to listen whether the client sends a request to the server
This blog has made a preliminary study and attempt, and written a small routine based on window communication and file transfer between client and server.
**
1, Client
**
The code of the client is slightly simpler than that of the server. Generally speaking, using the QTcpSocket class in QT to communicate with the server only requires the following five steps:
(1) Create QTcpSocket socket object
socket = new QTcpSocket(this);
(2) Use this object to connect to the server
QString ip = ui.lineEdit_ip->text();//Get ip int port = ui.lineEdit_2->text().toInt();//Get port data socket->connectToHost(ip, port);
(3) Use the write function to send data to the server
QByteArray data = ui.lineEdit_3->text().toUtf8();//Get the data in the lineEdit control and send it to the server socket->write(data);
(4) When new data arrives in the socket receiving buffer, a readRead() signal will be sent, so a slot function is added for the signal to read the data
connect(socket, &QTcpSocket::readyRead, this, &QTcpClinet::ReadData); void QTcpClinet::ReadData() { QByteArray buf = socket->readAll(); ui.textEdit->append(buf); }
(5) Disconnect from the server (press F1 for help on the difference between close() and disconnectFromHost())
socket->disconnectFromHost();
Clinet routine: (New qt cpt client project)
ui interface
Local loop ip: 127.0.0.1 can be connected to the local ip (ip circulating inside the computer)
If you want to connect to other ip addresses in the LAN - > run (win+R) + CMD + ipconfig - > IPv4 address to view the local ip address
QTcpClinet.h
#include <QtWidgets/QWidget> #include "ui_QTcpClinet.h" #include"QTcpSocket.h" #pragma execution_character_set("utf-8") class QTcpClinet : public QWidget { Q_OBJECT public: QTcpClinet(QWidget *parent = Q_NULLPTR); ~QTcpClinet(); public slots: void on_btn_connect_clicked(); void ReadData(); void on_btn_push_clicked(); private: Ui::QTcpClinetClass ui; QTcpSocket* socket;//Create socket pointer };
QTcpClinet.cpp
#include "QTcpClinet.h" QTcpClinet::QTcpClinet(QWidget *parent) : QWidget(parent) { ui.setupUi(this); socket = new QTcpSocket(this); } QTcpClinet::~QTcpClinet() { delete this->socket;//Reclaim memory } void QTcpClinet::on_btn_connect_clicked() { if (ui.btn_connect->text()==tr("Connect server")) { QString ip = ui.lineEdit_ip->text();//Get ip int port = ui.lineEdit_2->text().toInt();//Get port data //Cancel existing connection socket->abort(); //Connect server socket->connectToHost(ip, port); bool isconnect = socket->waitForConnected();//Wait until the connection is successful //If the connection is successful if (isconnect) { ui.textEdit->append("The connection was successful!!"); ui.btn_push->setEnabled(true);//Button enable //Modify key text ui.btn_connect->setText("Disconnect server"); //Receive buffer (server) information connect(socket, &QTcpSocket::readyRead, this, &QTcpClinet::ReadData); } else { ui.textEdit->append("The connection falied!!"); } } else { //Disconnect socket->disconnectFromHost(); ui.btn_connect->setText("Connect server"); ui.btn_push->setEnabled(false);//Turn off send button enable } } //Receive buffer information function void QTcpClinet::ReadData() { QByteArray buf = socket->readAll(); ui.textEdit->append(buf); } //Send button event void QTcpClinet::on_btn_push_clicked() { QByteArray data = ui.lineEdit_3->text().toUtf8();//Get the data in the lineEdit control and send it to the server socket->write(data); //Determine whether the write is successful bool iswrite = socket->waitForBytesWritten(); if (iswrite) { //Write successful } else { //No write succeeded } }
**
2, Server (need to be running all the time)
**
In addition to using the QTcpSocket class, the server also needs to use the qtcpserver class. Even so, it is only a little more complex than the client. It takes six steps:
(1) Create qtcpserver object
server = new QTcpServer(this);
(2) Listen on a port so that clients can use this port to access the server
server->listen(QHostAddress::Any, 6677);// Listen to all ip and 6677 ports
(3) When the server is accessed by the client, it will send a newConnection() signal, so a slot function is added for the signal, and a QTcpSocket object is used to accept client access
connect(server, &QTcpServer::newConnection, this, &TcpServer::ClientConnect); void TcpServer::ClientConnect() { //Resolve all customer connections while (server->hasPendingConnections()) { //After connecting, obtain the connection information through the socket (QTcpSocket object) socket = server->nextPendingConnection(); QString str = QString("[ip:%1,port:%2]").arg(socket->peerAddress().toString()).arg(socket->peerPort());//Monitor whether the client sends a message connect(socket, &QTcpSocket::readyRead, this, &TcpServer::ReadData1); } }
(4) Use the write function of socket to send data to the client
socket->write(data);
(5) When new data arrives in the socket receiving buffer, a readRead() signal will be sent, so a slot function is added for the signal to read the data
//Monitor whether the client sends a message connect(socket, &QTcpSocket::readyRead, this, &TcpServer::ReadData1); //Get the information sent by the client to the server void TcpServer::ReadData1() { QByteArray buf = socket->readAll();//readAll can receive up to 65532 data QString str = QString("[ip:%1,port:%2]").arg(socket->peerAddress().toString()).arg(socket->peerPort()); ui.textEdit_server->append(str +QString(buf)); //socket->write("ok");// The server returns an OK after receiving the information }
(6) Cancel listening
server->close();
Server routine: (add a new qt project TcpServer (server))
ui interface
TcpServer.h
#include <QtWidgets/QWidget> #include"ui_TcpServer.h" #include"qtcpserver.h" #include"qtcpsocket.h" class TcpServer : public QWidget { Q_OBJECT public: TcpServer(QWidget *parent = Q_NULLPTR); ~TcpServer(); public slots: void on_btn_server_clicked(); void on_btn_listen_clicked(); private: Ui::TcpServerClass ui; QTcpServer* server; QTcpSocket* socket;//A client corresponds to a socket void ClientConnect(); void ReadData1(); };
TcpServer.cpp
#include "TcpServer.h" #include"qstring.h" #include"qdebug.h" #pragma execution_character_set("utf-8") TcpServer::TcpServer(QWidget *parent) : QWidget(parent) { ui.setupUi(this); server = new QTcpServer(this); //Client connection signal slot connect(server, &QTcpServer::newConnection, this, &TcpServer::ClientConnect); } TcpServer::~TcpServer() { server->close(); server->deleteLater(); } void TcpServer::on_btn_listen_clicked() { if (ui.btn_listen->text()=="Listen") { //Get the port number from the input box int port = ui.lineEdit_port->text().toInt(); //Listen for all ip addresses on the specified port if (!server->listen(QHostAddress::Any, port)) { //If an error occurs, an error message is output qDebug() << server->errorString(); return; } //Modify key text ui.btn_listen->setText("Cancel listening"); } else { socket->abort(); //Cancel listening server->close(); //Modify key text ui.btn_listen->setText("Listen"); } } void TcpServer::ClientConnect() { //Resolve all customer connections while (server->hasPendingConnections()) { //After connecting, obtain the connection information through socket socket = server->nextPendingConnection(); QString str = QString("[ip:%1,port:%2]").arg(socket->peerAddress().toString()).arg(socket->peerPort()); //Prompt for successful connection ui.textEdit_server->append(str+"Connect to the server"); //The check box option is the ip address to which the server is connected ui.comboBox->addItem(str); //Put the socket address into the combobox attribute //ui.comboBox->setItemData(ui.comboBox->count()-1, QVariant((int)socket)); //Monitor whether the client sends a message connect(socket, &QTcpSocket::readyRead, this, &TcpServer::ReadData1); } } //Get the information sent by the client to the server void TcpServer::ReadData1() { QByteArray buf = socket->readAll();//readAll can receive up to 65532 data QString str = QString("[ip:%1,port:%2]").arg(socket->peerAddress().toString()).arg(socket->peerPort()); ui.textEdit_server->append(str +QString(buf)); } //The server sends information to the client void TcpServer::on_btn_server_clicked() { if(ui.comboBox->count()== 0)return; //QTcpSocket* skt= (QTcpSocket*)ui.comboBox->itemData(ui.comboBox->currentIndex()).value<int>(); socket->write(ui.lineEdit1->text().toUtf8()); }
Note: in write, you need to write an element of type char or an element of type QByteArray
Effect display:
**
3, TCP/IP file transfer
**
The message transmission is realized above, because socket - > readAll(); (readAll receives 65532 data at most), so it is not advisable to use this method for the transmission of large files.
Idea of TCP/IP file transmission:
Client and server connections
The client selects the file and sends the file to the server (the file header is sent, format: file name & size)
The server triggers readyRead, then parses the file frame header (obtains the file name and size), and returns an ok message to the client
The client triggers readyRead, then sends file data, and displays the progress through the progressBar
The server triggers readyRead again to receive the file data and save it (determine whether the file frame header or file data is received through ishead)
Code implementation:
New server project (TcpServer)
TcpServer.h
#pragma once #include <QtWidgets/QWidget> #include "ui_TcpServer.h" #include"qtcpserver.h" #include"qtcpsocket.h" #pragma execution_character_set("utf-8") class TcpServer : public QWidget { Q_OBJECT public: TcpServer(QWidget *parent = Q_NULLPTR); void hasConnect(); private: Ui::TcpServerClass ui; QTcpServer* server; QTcpSocket* socket; bool ishead; QString fileName; int fileSize;//Total size of received files int recvSize;//The size of the currently received file QByteArray filebuf;//Currently received file data };
TcpServer.cpp
#include "TcpServer.h" #include"qfile.h" TcpServer::TcpServer(QWidget *parent) : QWidget(parent) { ishead = true; ui.setupUi(this); server = new QTcpServer(this); //Listen to the ip address of port 1122 server->listen(QHostAddress::Any, 1122); //If there is a user connection, trigger the slot function connect(server, &QTcpServer::newConnection, this, &TcpServer::hasConnect); } void TcpServer::hasConnect() { while (server->hasPendingConnections()>0)//Determine how many people are currently connected { //Use socket to connect with our clients. One client corresponds to one socket socket = server->nextPendingConnection(); //Output client information on the server interface ui.textEdit->append(QString("%1: New user connection").arg(socket->peerPort())); //If the client sends a message, the anonymous function is triggered connect(socket, &QTcpSocket::readyRead, [=]() { QByteArray buf = socket->readAll(); //Use a flag bit ishead to determine whether it is a header or a data bit if (ishead) { //If it is a header, parse the header (file name, file size) QString str = QString(buf); ui.textEdit->append(str); QStringList strlist = str.split("&"); fileName = strlist.at(0);//Resolve frame header file name fileSize = strlist.at(1).toInt();//Parse frame header file size ishead = false;//The next file received is our data recvSize = 0; filebuf.clear(); socket->write("ok"); } else { //Receive and save files according to file name and file size filebuf.append(buf); recvSize += buf.size();//Current file size + 1 for each file received //When the received file size is equal to the total file size, the file data is received if (recvSize>=fileSize) { //Save file QFile file(ui.lineEdit->text() + fileName); file.open(QIODevice::WriteOnly); file.write(filebuf); file.close(); ishead = true; } } }); } }
New client project (QTcpClient)
QTcpClient.h
#include <QtWidgets/QWidget> #include"ui_QTcpClient.h" #include"qtcpsocket.h" #pragma execution_character_set("utf-8") class QTcpClient : public QWidget { Q_OBJECT public: QTcpClient(QWidget *parent = Q_NULLPTR); public slots: void on_btn_connect_clicked(); void on_btn_choose_clicked(); void on_btn_open_clicked(); private: Ui::QTcpClientClass ui; QTcpSocket* socket; };
QTcpClient.cpp
#include "QTcpClient.h" #include"qfiledialog.h" #include"qfileinfo.h" QTcpClient::QTcpClient(QWidget *parent) : QWidget(parent) { ui.setupUi(this); socket = new QTcpSocket(this); } void QTcpClient::on_btn_connect_clicked() { QString ip = ui.lineEdit_ip->text();//Get ip int port = ui.lineEdit_port->text().toInt();//Get port data socket->connectToHost(ip, port);//Connect server //Wait for the connection to succeed if (socket->waitForConnected()) { ui.textEdit->append("<font color='green'>Successfully connected to the server!</font>"); ui.btn_open->setEnabled(true); //If the server sends information to the client, the anonymous function is triggered connect(socket, &QTcpSocket::readyRead, [=]() { //Read the information sent by the server (i.e. buffer information) QByteArray buf = socket->readAll(); if (buf=="ok") { QFile file = (ui.label_path->text()); if (!file.open(QIODevice::ReadWrite)) { //fail to read file return; } qint64 currentlen = 0;//Currently sent size qint64 allLength = file.size();//Total file size do { char data[1024]; qint64 msize = file.read(data, 1024);//Put the read file into the other array and return the read size socket->write(data, msize);//Send the read data to the server currentlen += msize;//Get the file size currently sent in real time ui.progressBar->setValue(currentlen *100 / allLength);//Update interface progress bar } while (currentlen < allLength);//When the sending file is equal to the file size, the sending is completed and the cycle ends } }); } else { ui.textEdit->append("<font color='red'>Failed to connect to the server!</font>"); } } //Select file event void QTcpClient::on_btn_choose_clicked() { QString path = QFileDialog::getOpenFileName(this, "Open file", "", "(*.*)"); ui.label_path->setText(path); } //Send file event void QTcpClient::on_btn_open_clicked() { QFileInfo info(ui.label_path->text()); //Use QFileInfo:: fileName, size to obtain the file name and size format: file name & size //The server parses the file name and size in this format QString head = QString("%1&%2").arg(info.fileName()).arg(info.size()); //Send the format to the server toUtf8: QString to QByteArray or char type socket->write(head.toUtf8());
Effect display: