QT的Socket通信

您所在的位置:网站首页 socket底层调用过程 QT的Socket通信

QT的Socket通信

2023-09-11 16:25| 来源: 网络整理| 查看: 265

 

 

一、linux下的tcp通信过程

其中bind绑定,会固定一个端口,否则是随机的。

一个链接是由双方的ip和端口组成的,固定端口保证源的不变性,

这样另一端在任何时候访问的目的都是一致的,也可以说这个端口提供了什么服务。

 

同时绑定后直接操作socket id就可以操作对应的链接了。

 

二、QT下的TCP通信过程

Qt中提供的所有的Socket类都是非阻塞的。

Qt中常用的用于socket通信的套接字类:

         QTcpServer

用于TCP/IP通信, 作为服务器端套接字使用

         QTcpSocket

用于TCP/IP通信,作为客户端套接字使用。

         QUdpSocket

用于UDP通信,服务器,客户端均使用此套接字。

 

1.QT下的服务端 1).socket函数变为QTcpServer 2).bind ,listen 统一为listen

同时没有accept,当有一个链接过来的时候,会产生一个信号:newconnection,可以从对应的槽函数中取出建立好的套接字(对方的)QTcpSocket 如果成功和对方建立好链接,通信套接字会自动触发connected信号

3).read :

对方发送数据过来,链接的套接字(通信套接字)就会触发(本机的)readyRead信号,需要在对应的槽函数中接收数据

4).write,

发送数据,对方的(客户端的)套接字(通信套接字)就会触发readyRead信号,需要在对应的槽函数中接收数据 如果对方主动断开连接,对方的(客户端的)套接字(通信套接字)会自动触发disconnected信号

 

2.QT下的客户端: 1).socket函数变为 QTcpSocket 2).connect变为connetToHost()

如果成功和对方建立好链接,就会自动触发connected信号

3).read :

对方发送数据过来,链接的套接字(通信套接字)就会触发(本机的)readyRead信号,需要在对应的槽函数中接收数据

4).write,

发送数据,对方的(服务器的)套接字(通信套接字)就会触发readyRead信号,需要在对应的槽函数中接收数据,如果对方主动断开连接,就会自动触发disconnected信号

具体见图《QtTCP通信过程》

 

三、TCP服务器

Qwidget是基类,比较干净,QMainWindow相对比较多。

如果输入头文件没有提示,就需要在项目文件中加入对应模块,同时再编译不运行一下,让qt可以构建并加载对应的模块。

#include //监听套接字 #include //通信套接字//对方的(客户端的)套接字(通信套接字) //监听套接字,指定父对象,让其自动回收空间 tcpServer = new QTcpServer(this); tcpServer->listen(QHostAddress::Any, 8888); setWindowTitle("服务器: 8888"); connect(tcpServer, &QTcpServer::newConnection, [=]()//信号无参数,这里也没有参数 { //取出建立好连接的套接字 tcpSocket = tcpServer->nextPendingConnection(); //获取对方的IP和端口 QString ip = tcpSocket->peerAddress().toString(); qint16 port = tcpSocket->peerPort(); QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port); ui->textEditRead->setText(temp); //必须放在里面,因为建立好链接才能读,或者说tcpSocket有指向才能操作 connect(tcpSocket, &QTcpSocket::readyRead, [=]() { //从通信套接字中取出内容 QByteArray array = tcpSocket->readAll(); ui->textEditRead->append(array); } ); } ); void ServerWidget::on_buttonSend_clicked() { if(NULL == tcpSocket) { return; } //获取编辑区内容 QString str = ui->textEditWrite->toPlainText(); //给对方发送数据, 使用套接字是tcpSocket tcpSocket->write( str.toUtf8().data() ); } void ServerWidget::on_buttonClose_clicked() { if(NULL == tcpSocket) { return; } //主动和客户端断开连接 tcpSocket->disconnectFromHost(); tcpSocket->close(); tcpSocket = NULL; } 四、TCP客户端

可以在项目中添加新文件中选择Qt--->Qt设计师界面类(这个是带ui的),选择这个后项目会多出一个ui

 

ui->setupUi(this);//显示ui tcpSocket = NULL; //分配空间,指定父对象 tcpSocket = new QTcpSocket(this); setWindowTitle("客户端"); connect(tcpSocket, &QTcpSocket::connected, [=]() { ui->textEditRead->setText("成功和服务器建立好连接"); } ); //因为tcpSocket已经分配了空间,有指向,所以可以放在外面 connect(tcpSocket, &QTcpSocket::readyRead, [=]() { //获取对方发送的内容 QByteArray array = tcpSocket->readAll(); //追加到编辑区中 ui->textEditRead->append(array); } ); void ClientWidget::on_buttonConnect_clicked() { //获取服务器ip和端口 QString ip = ui->lineEditIP->text(); qint16 port = ui->lineEditPort->text().toInt(); //主动和服务器建立连接 tcpSocket->connectToHost(QHostAddress(ip), port); } void ClientWidget::on_buttonSend_clicked() { //获取编辑框内容 QString str = ui->textEditWrite->toPlainText(); //发送数据 tcpSocket->write( str.toUtf8().data() ); } void ClientWidget::on_buttonClose_clicked() { //主动和对方断开连接 tcpSocket->disconnectFromHost(); tcpSocket->close();//这里释放连接,前面connect的时候会建立连接 } int main(int argc, char *argv[]) { QApplication a(argc, argv); ServerWidget w; w.show(); ClientWidget w2; w2.show();//显示另外一个窗口 return a.exec(); }

上述代码具体见《TCP》

serverwidget.h

1 #ifndef SERVERWIDGET_H 2 #define SERVERWIDGET_H 3 4 #include 5 #include //监听套接字 6 #include //通信套接字 7 8 namespace Ui { 9 class ServerWidget; 10 } 11 12 class ServerWidget : public QWidget 13 { 14 Q_OBJECT 15 16 public: 17 explicit ServerWidget(QWidget *parent = 0); 18 ~ServerWidget(); 19 20 private slots: 21 void on_buttonSend_clicked(); 22 23 void on_buttonClose_clicked(); 24 25 private: 26 Ui::ServerWidget *ui; 27 28 QTcpServer *tcpServer; //监听套接字 29 QTcpSocket *tcpSocket; //通信套接字 30 31 }; 32 33 #endif // SERVERWIDGET_H

  serverwidget.cpp

1 #include "serverwidget.h" 2 #include "ui_serverwidget.h" 3 4 ServerWidget::ServerWidget(QWidget *parent) : 5 QWidget(parent), 6 ui(new Ui::ServerWidget) 7 { 8 ui->setupUi(this); 9 10 tcpServer = NULL; 11 tcpSocket = NULL; 12 13 //监听套接字,指定父对象,让其自动回收空间 14 tcpServer = new QTcpServer(this); 15 16 tcpServer->listen(QHostAddress::Any, 8888); 17 18 setWindowTitle("服务器: 8888"); 19 20 connect(tcpServer, &QTcpServer::newConnection, 21 [=]() 22 { 23 //取出建立好连接的套接字 24 tcpSocket = tcpServer->nextPendingConnection(); 25 26 //获取对方的IP和端口 27 QString ip = tcpSocket->peerAddress().toString(); 28 qint16 port = tcpSocket->peerPort(); 29 QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port); 30 31 ui->textEditRead->setText(temp); 32 33 connect(tcpSocket, &QTcpSocket::readyRead, 34 [=]() 35 { 36 //从通信套接字中取出内容 37 QByteArray array = tcpSocket->readAll(); 38 ui->textEditRead->append(array); 39 } 40 41 ); 42 43 44 } 45 46 ); 47 48 } 49 50 ServerWidget::~ServerWidget() 51 { 52 delete ui; 53 } 54 55 void ServerWidget::on_buttonSend_clicked() 56 { 57 if(NULL == tcpSocket) 58 { 59 return; 60 } 61 //获取编辑区内容 62 QString str = ui->textEditWrite->toPlainText(); 63 //给对方发送数据, 使用套接字是tcpSocket 64 tcpSocket->write( str.toUtf8().data() ); 65 66 } 67 68 void ServerWidget::on_buttonClose_clicked() 69 { 70 if(NULL == tcpSocket) 71 { 72 return; 73 } 74 75 //主动和客户端端口连接 76 tcpSocket->disconnectFromHost(); 77 tcpSocket->close(); 78 tcpSocket = NULL; 79 }

clientwidget.h

1 #ifndef CLIENTWIDGET_H 2 #define CLIENTWIDGET_H 3 4 #include 5 #include //通信套接字 6 7 namespace Ui { 8 class ClientWidget; 9 } 10 11 class ClientWidget : public QWidget 12 { 13 Q_OBJECT 14 15 public: 16 explicit ClientWidget(QWidget *parent = 0); 17 ~ClientWidget(); 18 19 private slots: 20 void on_buttonConnect_clicked(); 21 22 void on_buttonSend_clicked(); 23 24 void on_buttonClose_clicked(); 25 26 private: 27 Ui::ClientWidget *ui; 28 29 QTcpSocket *tcpSocket; //通信套接字 30 }; 31 32 #endif // CLIENTWIDGET_H

clientwidget.cpp

1 #include "clientwidget.h" 2 #include "ui_clientwidget.h" 3 #include 4 5 ClientWidget::ClientWidget(QWidget *parent) : 6 QWidget(parent), 7 ui(new Ui::ClientWidget) 8 { 9 ui->setupUi(this); 10 11 tcpSocket = NULL; 12 13 //分配空间,指定父对象 14 tcpSocket = new QTcpSocket(this); 15 16 setWindowTitle("客户端"); 17 18 19 connect(tcpSocket, &QTcpSocket::connected, 20 [=]() 21 { 22 ui->textEditRead->setText("成功和服务器建立好连接"); 23 } 24 ); 25 26 connect(tcpSocket, &QTcpSocket::readyRead, 27 [=]() 28 { 29 //获取对方发送的内容 30 QByteArray array = tcpSocket->readAll(); 31 //追加到编辑区中 32 ui->textEditRead->append(array); 33 } 34 35 ); 36 37 } 38 39 ClientWidget::~ClientWidget() 40 { 41 delete ui; 42 } 43 44 void ClientWidget::on_buttonConnect_clicked() 45 { 46 //获取服务器ip和端口 47 QString ip = ui->lineEditIP->text(); 48 qint16 port = ui->lineEditPort->text().toInt(); 49 50 //主动和服务器建立连接 51 tcpSocket->connectToHost(QHostAddress(ip), port); 52 53 } 54 55 void ClientWidget::on_buttonSend_clicked() 56 { 57 //获取编辑框内容 58 QString str = ui->textEditWrite->toPlainText(); 59 //发送数据 60 tcpSocket->write( str.toUtf8().data() ); 61 62 } 63 64 void ClientWidget::on_buttonClose_clicked() 65 { 66 //主动和对方断开连接 67 tcpSocket->disconnectFromHost(); 68 tcpSocket->close(); 69 }

 

五、UDP通信过程

使用Qt提供的QUdpSocket进行UDP通信。在UDP方式下,客户端并不与服务器建立连接,它只负责调用发送函数向服务器发送数据。

类似的服务器也不从客户端接收连接,只负责调用接收函数,等待来自客户端的数据的到达。

在UDP通信中,服务器端和客户端的概念已经显得有些淡化,两部分做的工作都大致相同

 

1.QT下的服务端

socket函数变为QUdpSocket

bind ,还是bind,(固定端口,让别人可以知道往哪里发,客户端也可以绑定)

 

readDatagram :

对方发送数据过来,套接字就会触发readyRead信号,需要在对应的槽函数中接收数据

writeDatagram,

发送数据,对方的(客户端的)套接字就会触发readyRead信号,需要在对应的槽函数中接收数据

close 还是close

 

2.QT下的客户端:

socket函数变为 QUdpSocket

readDatagram :对方发送数据过来,套接字就会触发readyRead信号,需要在对应的槽函数中接收数据writeDatagram,发送数据,对方的(客户端的)套接字就会触发readyRead信号,需要在对应的槽函数中接收数据

close 还是close

 

 

六、UDP文本发送

 

UDP中没有严格的区分服务端和客户端。

关闭按钮是用于关闭窗口的,这主要是由于udp不是面向连接的,没有断开连接的说法。

#include //UDP套接字 //分配空间,指定父对象,这是为了让父对象来回收,其实也可以不用指定,自己来回收资源也行 udpSocket = new QUdpSocket(this); //绑定 udpSocket->bind(8888); setWindowTitle("服务器端口为:8888"); //当对方成功发送数据过来 //自动触发 readyRead() connect(udpSocket, &QUdpSocket::readyRead, this, &Widget::dealMsg); void Widget::dealMsg() { //读取对方发送的内容 char buf[1024] = {0}; QHostAddress cliAddr; //对方地址 quint16 port; //对方端口 qint64 len = udpSocket->readDatagram(buf, sizeof(buf), &cliAddr, &port); if(len > 0) { //格式化 [192.68.2.2:8888]aaaa QString str = QString("[%1:%2] %3") .arg(cliAddr.toString()) .arg(port) .arg(buf); //给编辑区设置内容 ui->textEdit->setText(str); } } //发送按钮 void Widget::on_buttonSend_clicked() { //先获取对方的IP和端口 QString ip = ui->lineEditIP->text(); qint16 port = ui->lineEditPort->text().toInt(); //获取编辑区内容 QString str = ui->textEdit->toPlainText(); //给指定的IP发送数据 udpSocket->writeDatagram(str.toUtf8(), QHostAddress(ip), port); }

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3