Qt 实现简单的TCP通信


这段时间用到了QT的TCP通信,做了初步的学习与尝试,编写了一个客户端和服务器基于窗口通信的小例程。

使用QT的网络套接字需要.pro文件中加入一句:

QT += network

一、客户端

1、客户端的代码比服务器稍简单,总的来说,使用QT中的QTcpSocket类与服务器进行通信只需要以下5步:

(1)创建QTcpSocket套接字对象

socket = new QTcpSocket();

(2)使用这个对象连接服务器

socket->connectToHost(IP, port);

(3)使用write函数向服务器发送数据

socket->write(data);

(4)当socket接收缓冲区有新数据到来时,会发出readRead()信号,因此为该信号添加槽函数以读取数据

1 QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data); 2  
3 void MainWindow::socket_Read_Data() 4 { 5  QByteArray buffer; 6     //读取缓冲区数据
7     buffer = socket->readAll(); 8 }

(5)断开与服务器的连接(关于close()和disconnectFromHost()的区别,可以按F1看帮助)

socket->disconnectFromHost();

2、以下是客户端的例程

首先是mainwindow.h文件:

 1 //mainwindow.h
 2 #ifndef MAINWINDOW_H  3 #define MAINWINDOW_H
 4  
 5 #include <QMainWindow>
 6 #include <QTcpSocket>
 7  
 8 namespace Ui {  9 class MainWindow; 10 } 11  
12 class MainWindow : public QMainWindow 13 { 14  Q_OBJECT 15  
16 public: 17     explicit MainWindow(QWidget *parent = 0); 18     ~MainWindow(); 19  
20 private slots: 21  
22     void on_pushButton_Connect_clicked(); 23  
24     void on_pushButton_Send_clicked(); 25  
26     void socket_Read_Data(); 27  
28     void socket_Disconnected(); 29  
30 private: 31     Ui::MainWindow *ui; 32     QTcpSocket *socket; 33 }; 34  
35 #endif // MAINWINDOW_H

然后是mainwindow.cpp文件:

 1 //mainwindow.cpp
 2 #include "mainwindow.h"
 3 #include "ui_mainwindow.h"
 4  
 5 MainWindow::MainWindow(QWidget *parent) :  6  QMainWindow(parent),  7     ui(new Ui::MainWindow)  8 {  9     ui->setupUi(this); 10  
11     socket = new QTcpSocket(); 12  
13     //连接信号槽
14     QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data); 15     QObject::connect(socket, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected); 16  
17     ui->pushButton_Send->setEnabled(false); 18     ui->lineEdit_IP->setText("127.0.0.1"); 19     ui->lineEdit_Port->setText("8765"); 20  
21 } 22  
23 MainWindow::~MainWindow() 24 { 25     delete this->socket; 26     delete ui; 27 } 28  
29 void MainWindow::on_pushButton_Connect_clicked() 30 { 31     if(ui->pushButton_Connect->text() == tr("连接")) 32  { 33  QString IP; 34         int port; 35  
36         //获取IP地址
37         IP = ui->lineEdit_IP->text(); 38         //获取端口号
39         port = ui->lineEdit_Port->text().toInt(); 40  
41         //取消已有的连接
42         socket->abort(); 43         //连接服务器
44         socket->connectToHost(IP, port); 45  
46         //等待连接成功
47         if(!socket->waitForConnected(30000)) 48  { 49             qDebug() << "Connection failed!"; 50             return; 51  } 52         qDebug() << "Connect successfully!"; 53  
54         //发送按键使能
55         ui->pushButton_Send->setEnabled(true); 56         //修改按键文字
57         ui->pushButton_Connect->setText("断开连接"); 58  } 59     else
60  { 61         //断开连接
62         socket->disconnectFromHost(); 63         //修改按键文字
64         ui->pushButton_Connect->setText("连接"); 65         ui->pushButton_Send->setEnabled(false); 66  } 67 } 68  
69 void MainWindow::on_pushButton_Send_clicked() 70 { 71     qDebug() << "Send: " << ui->textEdit_Send->toPlainText(); 72      //获取文本框内容并以ASCII码形式发送
73     socket->write(ui->textEdit_Send->toPlainText().toLatin1()); 74     socket->flush(); 75 } 76  
77 void MainWindow::socket_Read_Data() 78 { 79  QByteArray buffer; 80     //读取缓冲区数据
81     buffer = socket->readAll(); 82     if(!buffer.isEmpty()) 83  { 84         QString str = ui->textEdit_Recv->toPlainText(); 85         str+=tr(buffer); 86         //刷新显示
87         ui->textEdit_Recv->setText(str); 88  } 89 } 90  
91 void MainWindow::socket_Disconnected() 92 { 93     //发送按键失能
94     ui->pushButton_Send->setEnabled(false); 95     //修改按键文字
96     ui->pushButton_Connect->setText("连接"); 97     qDebug() << "Disconnected!"; 98 }

最后是ui的设计:

二、服务器

1、服务器除了使用到了QTcpSocket类,还需要用到QTcpSever类。即便如此,也只是比客户端复杂一点点,用到了6个步骤:

(1)创建QTcpSever对象

server = new QTcpServer();

(2)侦听一个端口,使得客户端可以使用这个端口访问服务器

server->listen(QHostAddress::Any, port);

(3)当服务器被客户端访问时,会发出newConnection()信号,因此为该信号添加槽函数,并用一个QTcpSocket对象接受客户端访问

1 connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect); 2  
3 void MainWindow::server_New_Connect() 4 { 5     //获取客户端连接
6     socket = server->nextPendingConnection(); 7 }

(4)使用socket的write函数向客户端发送数据

socket->write(data);

(5)当socket接收缓冲区有新数据到来时,会发出readRead()信号,因此为该信号添加槽函数以读取数据

1 QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data); 2  
3 void MainWindow::socket_Read_Data() 4 { 5  QByteArray buffer; 6     //读取缓冲区数据
7     buffer = socket->readAll(); 8 }

(6)取消侦听

server->close();

2、以下是服务器的例程

首先是mainwindow.h文件:

 1 //mainwindow.h
 2 #ifndef MAINWINDOW_H  3 #define MAINWINDOW_H
 4  
 5 #include <QMainWindow>
 6 #include <QTcpServer>
 7 #include <QTcpSocket>
 8  
 9 namespace Ui { 10 class MainWindow; 11 } 12  
13 class MainWindow : public QMainWindow 14 { 15  Q_OBJECT 16  
17 public: 18     explicit MainWindow(QWidget *parent = 0); 19     ~MainWindow(); 20  
21 private slots: 22     void on_pushButton_Listen_clicked(); 23  
24     void on_pushButton_Send_clicked(); 25  
26     void server_New_Connect(); 27  
28     void socket_Read_Data(); 29  
30     void socket_Disconnected(); 31  
32 private: 33     Ui::MainWindow *ui; 34     QTcpServer* server; 35     QTcpSocket* socket; 36 }; 37  
38 #endif // MAINWINDOW_H

然后是mainwindow.cpp文件:

 1 #include "mainwindow.h"
 2 #include "ui_mainwindow.h"
 3  
 4 MainWindow::MainWindow(QWidget *parent) :  5  QMainWindow(parent),  6     ui(new Ui::MainWindow)  7 {  8     ui->setupUi(this);  9  
 10     ui->lineEdit_Port->setText("8765");  11     ui->pushButton_Send->setEnabled(false);  12  
 13     server = new QTcpServer();  14  
 15     //连接信号槽
 16     connect(server,&QTcpServer::newConnection,this,&MainWindow::server_New_Connect);  17 }  18  
 19 MainWindow::~MainWindow()  20 {  21     server->close();  22     server->deleteLater();  23     delete ui;  24 }  25  
 26 void MainWindow::on_pushButton_Listen_clicked()  27 {  28     if(ui->pushButton_Listen->text() == tr("侦听"))  29  {  30         //从输入框获取端口号
 31         int port = ui->lineEdit_Port->text().toInt();  32  
 33         //监听指定的端口
 34         if(!server->listen(QHostAddress::Any, port))  35  {  36             //若出错,则输出错误信息
 37             qDebug()<<server->errorString();  38             return;  39  }  40         //修改按键文字
 41         ui->pushButton_Listen->setText("取消侦听");  42         qDebug()<< "Listen succeessfully!";  43  }  44     else
 45  {  46 /*
 47  //如果正在连接(点击侦听后立即取消侦听,若socket没有指定对象会有异常,应修正——2017.9.30)  48  if(socket->state() == QAbstractSocket::ConnectedState)  49  {  50  //关闭连接  51  socket->disconnectFromHost();  52  }  53 */
 54         socket->abort();  55         //取消侦听
 56         server->close();  57         //修改按键文字
 58         ui->pushButton_Listen->setText("侦听");  59         //发送按键失能
 60         ui->pushButton_Send->setEnabled(false);  61  }  62  
 63 }  64  
 65 void MainWindow::on_pushButton_Send_clicked()  66 {  67     qDebug() << "Send: " << ui->textEdit_Send->toPlainText();  68     //获取文本框内容并以ASCII码形式发送
 69     socket->write(ui->textEdit_Send->toPlainText().toLatin1());  70     socket->flush();  71 }  72  
 73 void MainWindow::server_New_Connect()  74 {  75     //获取客户端连接
 76     socket = server->nextPendingConnection();  77     //连接QTcpSocket的信号槽,以读取新数据
 78     QObject::connect(socket, &QTcpSocket::readyRead, this, &MainWindow::socket_Read_Data);  79     QObject::connect(socket, &QTcpSocket::disconnected, this, &MainWindow::socket_Disconnected);  80     //发送按键使能
 81     ui->pushButton_Send->setEnabled(true);  82  
 83     qDebug() << "A Client connect!";  84 }  85  
 86 void MainWindow::socket_Read_Data()  87 {  88  QByteArray buffer;  89     //读取缓冲区数据
 90     buffer = socket->readAll();  91     if(!buffer.isEmpty())  92  {  93         QString str = ui->textEdit_Recv->toPlainText();  94         str+=tr(buffer);  95         //刷新显示
 96         ui->textEdit_Recv->setText(str);  97  }  98 }  99  
100 void MainWindow::socket_Disconnected() 101 { 102     //发送按键失能
103     ui->pushButton_Send->setEnabled(false); 104     qDebug() << "Disconnected!"; 105 }

最后是ui的设计:

 三、运行结果


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM