使用QT TCP 相关网络库的时候,需要在工程文件内添加network

  1. QT += network

1. TCP 服务端

使用tcp服务端的主要相关步骤如下:


1.1 声明QTcpServer与QTcpSocket

QTcpServer是QT中对Tcp服务端的封装,主要有以下功能:

  • 绑定IP和端口
  • 处理客户端连接/断开

QTcpSocket是QT中用来对socket进行操作的api,主要有以下功能:

  • 读取数据
  • 写入数据

在.h文件中声明指针

  1. // .h 文件
  2. #include <QTcpServer>
  3. #include <QTcpSocket>
  4. #include <QMap>
  5. // ....
  6. private:
  7. QTcpServer *tcpServer;
  8. QMap<QString, QTcpSocket*> tcpClient;
  9. QTcpSocket *currentClient;
  10. int cnt;
  11. // ....

声明中:

  • tcpServer:用来保存QTcpServer对象的指针。
  • tcpClient:是一个map表,保存了所有与客户端连接后新建的socket对象。为了在多连接的时候能够区分不同的对象,将每个QTcpSocket的ip和socket指针一起保存在QMap中。
  • currentClient:是当前使用的QTcpSocket对象指针。

多连接的处理逻辑是:

  • 有新连接来后,将ip和对应QTcpSocket指针存到Map里。
  • 读取到数据的时候,遍历map,根据QTcpSocket指针(value)可以找到ip值(key)。
  • 发送数据时候,根据界面上的ip(key),可以直接取出对应的value。

1.2 初始化QTcpServer

1.2.1 初始化服务端

  1. tcpServer = new QTcpServer(this);

1.2.2 实现处理新连接连接信号

tcpServer 提供了多个触发信号(新连接,连接断开等),我们必须要处理的信号是有新连接到来信号newConnection。

  1. void newConnection()

这个信号通知我们有新的客户端请求连接服务端,我们需要为这个客户端新建一个QTcpSocket;因此我们编写了一个槽函数,与newConnection()信号连接,用来处理新连接。
在处理连接的槽函数中需要需要完成以下工作:

  • 使用nextPendingConnection(),获得为新的客户端连接创建的QTcpSocket
  • 获取当前连接的客户端的ip
  • 将ip字符串 和 新建的QTcpSocket保存到map中
  • 为新建的QTcpSocket,连接数据可读取信号槽

具体代码:
首先在头文件中定义槽函数

  1. slots:
  2. void :NewConnectionSlot();
  1. void MainWindows::NewConnectionSlot()
  2. {
  3. currentClient = tcpServer->nextPendingConnection(); // 获取新建的socket
  4. int current_port = currentClient->peerPort(); //获取当前连接的客户端的端口
  5. QString ip = currentClient->peerAddress().toString().split("::ffff:")[1] + QString::number(current_port);
  6. tcpClient.insert(ip, currentClient);
  7. // 可以将这个ip 字符串,更新在ui的客户端ip选择框里
  8. connect(currentClient, SIGNAL(readyRead()), this, SLOT(ReadData()));
  9. }

在新建QTcpServer对象后,将我们上面定义的槽函数NewConnectionSlot和newConnection信号进行连接

tcpServer = new QTcpServer(this);
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(NewConnectionSlot()));

完整初始化函数为:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    tcpServer = new QTcpServer(this);
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(NewConnectionSlot()));        
}

void MainWindows::NewConnectionSlot()
{
    currentClient = tcpServer->nextPendingConnection(); // 获取新建的socket
    int current_port = currentClient->peerPort(); //获取当前连接的客户端的端口
    QString ip = currentClient->peerAddress().toString().split("::ffff:")[1] + QString::number(current_port);
    tcpClient.insert(ip, currentClient);
    // 可以将这个ip 字符串,更新在ui的客户端ip选择框里
    ui->cbxConnection->append(ip);
    connect(currentClient, SIGNAL(readyRead()), this, SLOT(ReadData()));
}

到这里tcpServer的初始化部分已经完成。


1.3 实现数据读取槽函数

QTcpSocket拥有readyRead信号, 接下来需要实现在NewConnectionSlot中,用来和readyRead信号连接的数据处理函数

void MainWindows::ReadData()
{
    QTcpSocket *socket = qobject_cast<QMessageBox *>(sender()); // 获取是哪个socket发送的信号
    QByteArray buffer = socket->readAll();
    // buffer是读取到的数据, 接下来可以打印在ui上
}

1.4 实现数据发送函数

从ui上获取要发送的数据和目标客户端后,可以通过QTcpsocket的write()将数据发送出去

void MainWindows::on_sendButton_clicked(){
    QString clientIP = ui->cbxConnection->currentText();
    QString data = ui->textEdit->toPlainText();
    tcpClient[clientIP]->write(data.toLatin1());
}

1.5 监听端口和ip

调用tcpServer的listen()函数对端口进行监听,第一个参数QHostAddress::Any代表本机上所有网卡,第二个参数是要监听的端口。

tcpServer->listen(QHostAddress::Any, ui->portEdit->text().toInt());

2. 客户端

客户端大体上和服务端相似,但不需要管理多连接

2.1 初始化QTcpSocket

2.1.1 新建对象并连接信号槽

新建对象,并连接有数据可读信号槽

tcpClient = new QTcpSocket(this);   //实例化tcpClient
connect(tcpClient, SIGNAL(readyRead()), this, SLOT(ReadData()));

2.1.2 实现有数据可读槽函数

实现上一步中connect的ReadData槽函数

void MainWindows::ReadData()
{
    QByteArray buffer = tcpClient->readAll();
    if(!buffer.isEmpty())
    {
        ui->edtRecv->append(buffer);
    }
}

2.2 实现数据发送函数

获取文本框上的数据文字,通过tcpClient->write来发送, 发送的时候需要转成二进制格式。

void MainWindows::on_sendButton_clicked(){
    QString data = ui->edtSend->toPlainText();
    if(data != "")
    {
        tcpClient->write(data.toLatin1()); 
    }
}

2.3 连接到目标服务器

在按下连接按钮后,连接到目标服务器。

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    tcpClient = new QTcpSocket(this);   //实例化tcpClient
    connect(tcpClient, SIGNAL(readyRead()), this, SLOT(ReadData()));        
}

void MainWindows::on_connectButton_clicked(){
    tcpClient->connectToHost(ui->edtIP->text(), ui->edtPort->text().toInt());
}