这段时间用到了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的设计:
三、运行结果