QT TCP 简单编程了解原理

这里的内容主要参考《Qt Creator 快速入门》的18章节的TCP部分~
刚开始不懂TCP传输的什么服务端客户端,以及监听等概念,自己敲完一遍代码后,了解的更加清楚了~

先说一下,要实现的功能很简单:
服务器一直监听一个端口,一旦有客户端连接请求,便建立连接,并向客户端发送一个字符串,然后客户端接受该字符串并显示出来。

实现效果界面如图:
刚开始先运行服务器端的程序,界面上有一个label显示“等待连接。。。”
这里写图片描述
之后运行客户端的程序,界面上要求输入你要连的主机和端口号(我在服务器端设置的监听端口号是6666,所以这里我会填主机是“localhost”,表示本主机,端口号填6666),然后点击连接按钮(我在这个按钮的槽函数下设置了一个连接服务器的槽函数)
这里写图片描述
运行结果图:
当点击客户端的连接后,立马与服务器端进行了连接,并且此时服务器端给客户端发送了字符串,服务器端也收到了,就是图片上的“hello TCP”
这里写图片描述

这里写图片描述
主要代码:
服务器端:
项目名称为tcpserver,类名为Server
头文件
server.h

#ifndef SERVER_H
#define SERVER_H
#include<QTcpServer>
#include <QDialog>

namespace Ui {
class Server;
}

class Server : public QDialog
{
    Q_OBJECT

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

private:
    Ui::Server *ui;
    QTcpServer *tcpServer;
private slots:
    void sendMessage();
};

#endif // SERVER_H

server.cpp

#include<QtNetwork>
#include "server.h"
#include "ui_server.h"
#include<QDebug>
#include<QByteArray>
#include<QDataStream>
#include<QTcpSocket>
Server::Server(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Server)
{
    ui->setupUi(this);
    tcpServer=new QTcpServer(this);
    if(!tcpServer->listen(QHostAddress::Any,6666))//开始监听任何连在6666端口的IP地址
    {
        qDebug()<<tcpServer->errorString();
        close();
    }
    connect(tcpServer,&QTcpServer::newConnection,this,&Server::sendMessage);//当有客户端连接过来时,发射sendMessage

}

Server::~Server()
{
    delete ui;
}
void Server::sendMessage()
{
    QByteArray block;
    QDataStream out(&block,QIODevice::WriteOnly);//用block来暂时存放要发送的数据
    out.setVersion(QDataStream::Qt_5_5);//设置数据流的版本,客户端和服务器端的版本要相同
    //在发送数据时,一定要在最开始写入实际数据的大小信息,该大小信息占用两个字节,可以使用(quint16)0来表示
    out<<(quint16)0;//但是在写入数据前可能不知道实际数据大小信息,所以要在数据块的最前面留两个自己的位置,以便以后填写数据大小的信息
    out<<tr("hello TCP!");//这里输入实际的数据
    out.device()->seek(0);//seek(0)跳转到数据块的开头
    out<<(quint16)(block.size()-sizeof(quint16));//数据块总大小-数据块开头两个字节的大小获得数据实际大小,写入开头空着的位置

    QTcpSocket *clientConnection=tcpServer->nextPendingConnection();//获取已经建立连接的套接字
    connect(clientConnection,&QTcpSocket::disconnected,clientConnection,&QTcpSocket::deleteLater);//当连接断开时删除该套接字
    clientConnection->write(block);//用write函数,将数据发送出去
    clientConnection->disconnectFromHost();//该函数表明会一直等待套接字将所有数据发送完毕,然后关闭该套接字
    ui->label->setText(tr("发送数据成功!"));

}

可以看到,编写TCP服务器端程序时可以使用QTcpServer类,然后调用它的listen()函数进行监听。要对连接过来的客户端进行操作时,可以通过关联newConnection()信号在槽中进行

客户端
项目名称为tcpclient,类名为Client
client.h

#ifndef CLIENT_H
#define CLIENT_H
#include<QTcpSocket>
#include <QDialog>

namespace Ui {
class Client;
}

class Client : public QDialog
{
    Q_OBJECT

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

private:
    Ui::Client *ui;
    QTcpSocket *tcpSocket;
    QString message;
    quint16 blocksize;
private slots:
    void newConnect();
    void readmessage();
    void displayError(QAbstractSocket::SocketError);
    void on_pushButton_connect_clicked();
};

#endif // CLIENT_H

client.cpp

#include "client.h"
#include "ui_client.h"
#include<QtNetwork>
#include<QDataStream>
Client::Client(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Client)
{
    ui->setupUi(this);
    tcpSocket=new QTcpSocket(this);
    connect(tcpSocket,&QTcpSocket::readyRead,this,&Client::readmessage);
    connect(tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));

}

Client::~Client()
{
    delete ui;
}
void Client::newConnect()
{
    blocksize=0;//初始化数据大小为0
    tcpSocket->abort();//取消了当前已经存在的连接,并且重置套接字
    //连接到指定主机的指定端口
    tcpSocket->connectToHost(ui->lineEdit_Host->text(),ui->lineEdit_Port->text().toInt());
}
void Client::readmessage()
{
    QDataStream in(tcpSocket);//数据流入套接字
    in.setVersion(QDataStream::Qt_5_5);
    //如果是刚开始接收数据,因为初始化大小为0
    if(blocksize==0)
    {
        //判断所接收的数据是否大于两个字节,也就是文件的大小信息的空间
        //如果是,则把文件大小信息保存到blocksize
        if(tcpSocket->bytesAvailable()<(int)sizeof(quint16))
            return;
        in>>blocksize;//发送和接收的数据流都是有自己的格式的,比如,自己定义的quint16 blocksize;

    }
    //如果没有得到全部的数据,则返回,继续接收数据
    if(tcpSocket->bytesAvailable()<blocksize)
        return;
    in>>message;
    ui->label_message->setText(message);

}
void Client::displayError(QAbstractSocket::SocketError)
{
    qDebug()<<"test";
    qDebug()<<tcpSocket->errorString();
}

void Client::on_pushButton_connect_clicked()
{
    newConnect();
}

整个过程是这样的:启动服务器端,开始监听端口,客户端单击“连接,调用newConnect()槽,然后客户端向服务器发送连接请求,这时服务器调用sendMessage()槽,发送字符串,客户端接收到字符串时,调用readMessage()槽将字符串显示出来。”

猜你喜欢

转载自blog.csdn.net/qiqi123i/article/details/80256834