首页 > 编程知识 正文

qt的socket通信,qtcpsocket客户端

时间:2023-05-03 16:05:35 阅读:25529 作者:2543

QT创建TCP Socket通信

最近在学习QT,知道QT可以进行套接字的网络通信,进行学习,制作简单的聊天DEMO。 为了测试是否可以与VS2012下的程序进行通信,在VS2012下编写了客户端程序,进行了通信测试,发现可以进行通信。 这也证明,采用同一通信协议[TCP]的两个程序,无论采用哪个编译器,采用的语法不同都可以进行通信。 简要介绍QT的TCP通信机制,然后介绍基于QT的聊天DEMO的具体实现过程; 最后说明与VS2012中的程序的通信。

1、QT的TCP套接字通信机制QT的TCP套接字通信仍然有服务端、客户端之分。 服务端监听端口并监听客户端连接是否到来,连接到来时建立新套接字连接的客户端通过IP和PORT连接到服务端,连接成功后可以发送和接收数据。 应该注意的是,在QT中,QT必须将套接字视为输入/输出流,数据的发送/接收是在read ()和write () )中进行的,并且必须与我们常见的send ()和recv () )进行区分。

要在QT上进行套接字通信,必须在工程名称. pro文件中输入QT =network。 如下所示。

a ) )服务端通信机制位于服务端,建立套接字通信需要两种QTcpServer和QTcpSocket。 其中,QTcpServer是用于建立QT的Server侧对象,QTcpSocket是用于建立套接字通信的套接字对象。 通信建立的流程如下。

1 )为QTcpServer类创建对象QTcpServer* mp_TCPServer; MP_TCP服务器=newq TCP服务器(; 2 )在监听QT中,通过listen ) )建立端口的监听。 MP_TCP服务器-listen (地址类型、端口号);

int port=ui-m_portLineEdit-text ().toInt ); //获取端口号if ()! MP _ TCP server-listen (qhostaddress 33603360 any,port ) ) qmessagebox 33603360信息(this,' QT网络通信),'服务器端返回; }其中,QHostAddress定义了一个特殊的集中IP地址。 例如

qhostaddress :3360空值表示空地址;

QHostAddress:LocalHost是IPv4的本地地址127.0.0.1;

qostaddress :3360 localhost ipv 6表示ipv6的本机地址;

QHostAddress:Broadcast是广播地址255.255.255.255;

QHostAddress:Any表示IPv4的任意地址;

QHostAddress:AnyIPv6表示IPv6的任意地址。

3 )将接收到的连接信号与时隙函数关联的服务端判断是否在信号SIGNAL:newConnection )中接收到新连接,当服务端接收到来自客户端的连接时,信号newConnection ) ) 此时,必须调用相应的插槽函数(例如,自定义函数(ServerNewConnection ) ),以便在服务端监听端口后建立信号与插槽函数的连接。 用connect函数联系:

连接(MP _ TCP服务器、信号(新连接)、this、slot (服务器连接) ); 在ServerNewConnection ()函数中,nextPendingConnection ) )函数获取连接到客户端的套接字。

MP_TCP套接字=MP_TCP服务器-nextpendingconnection (; 4 )在接收数据QT中,QT以信号SIGNAL:readyRead ) )判断是否接收到数据,如果客户端向服务端成功发送数据,则在服务端生成readyRead ) )信号要通过调用相应的自定义插槽函数(ServerReadData ) )来建立连接(connect函数中的信号readyRead ()和插槽函数ServerReadData ) ),请执行以下操作:

连接(MP _ TCP套接字,信号) readyread ()、this,slot ) serverreaddata ) ); 要从接收函数ServerReadData (用函数读取)函数获取数据:

MP _ TCP套接字-读取(buffer,1024 ); 请注意,read*函数具有多个重载函数,用于存储传入数据的数据类型可以是QByteArray或char*,并根据个人习惯和任务需要选择适当的read*函数。 但是,为了保持一致性,建议选择char*类型。

一是因为数据类型容易识别;二是因为熟悉CC++语言开发的对char*应该比较熟悉,防止使用上的错误。

5):发送数据

       在QT中,通过write函数向外部发送数据:

int sendRe = mp_TCPSocket->write(sendMsgChar, strlen(sendMsgChar));if( -1 == sendRe){ QMessageBox::information(this, "QT网络通信", "服务端发送数据失败!");}    b):客户端通信机制

        客户端的通信机制与服务端相比要相对简单,只用到了QTcpSocket一个类。

1):建立QTcpSocket类的对象

建立Socket的套接字:

QTcpSocket* mp_clientSocket;mp_clientSocket = new QTcpSocket(); 2):连接服务端

客户端通过connectToHost(IP, Port)函数连接服务端

mp_clientSocket->connectToHost(ip, port); 3):接收数据

       客户端接收数据与服务端接收数据的机制是相同的。通过readyRead()信号是否被触发来判断是否有数据传入,如果该信号被触发,则调用自定义函数(如:ClientRecvData())来保存接收到的数据。通过connect()函数,将信号readyRead()与槽函数ClientRecvData()建立映射关系。

在槽函数ClientRecvData()中通过read()函数接收数据,具体使用方法请参考服务端接收数据。

4):发送数据

客户端发送数据也是通过write()函数来实现,具体使用方法请参考服务端发送数据

2、QT基于TCP Socket的通信实例

该部分主要是DEMO的具体实现。

   a):服务端示例 1):在sockettcpserver.h中添加具体如下代码: private: Ui::SocketTCPServer *ui; QTcpServer *mp_TCPServer; QTcpSocket *mp_TCPSocket;private slots: void OnBtnInitSocket(); void OnBtnSendData(); void ServerReadData(); void ServerNewConnection(); void sServerDisConnection(); 2):在构造函数中添加如下代码: ui->m_portLineEdit->setText("5550"); connect(ui->m_initSocketBtn, SIGNAL(clicked()), this, SLOT(OnBtnInitSocket())); connect(ui->m_sendData, SIGNAL(clicked()), this, SLOT(OnBtnSendData())); 3):ServerNewConnection()具体实现: //获取客户端连接 mp_TCPSocket = mp_TCPServer->nextPendingConnection(); if(!mp_TCPSocket) { QMessageBox::information(this, "QT网络通信", "未正确获取客户端连接!"); return; } else { QMessageBox::information(this, "QT网络通信", "成功接受客户端的连接"); connect(mp_TCPSocket, SIGNAL(readyRead()), this, SLOT(ServerReadData())); connect(mp_TCPSocket, SIGNAL(disconnected()), this, SLOT(sServerDisConnection())); } 4):ServerReadData()具体实现: char buffer[1024] = {0}; mp_TCPSocket->read(buffer, 1024); if( strlen(buffer) > 0) { QString showNsg = buffer; ui->m_recvDataTextEdit->append(showNsg); } else { QMessageBox::information(this, "QT网络通信", "未正确接收数据"); return; } 5):OnBtnInitSocket()具体实现: mp_TCPServer = new QTcpServer(); int port = ui->m_portLineEdit->text().toInt(); if(!mp_TCPServer->listen(QHostAddress::Any, port)) { QMessageBox::information(this, "QT网络通信", "服务器端监听失败!"); return; } else { QMessageBox::information(this, "QT网络通信", "服务器监听成功!"); } connect(mp_TCPServer, SIGNAL(newConnection()), this, SLOT(ServerNewConnection())); 6):OnBtnSendData()具体实现: char sendMsgChar[1024] = {0}; QString sendMsg = ui->m_inputTextEdit->toPlainText(); if(sendMsg.isEmpty()) { QMessageBox::information(this, "QT网络通信", "发送数据为空,请输入数据"); return; } strcpy_s(sendMsgChar, sendMsg.toStdString().c_str()); if(mp_TCPSocket->isValid()) { int sendRe = mp_TCPSocket->write(sendMsgChar, strlen(sendMsgChar)); if( -1 == sendRe) { QMessageBox::information(this, "QT网络通信", "服务端发送数据失败!"); } } else { QMessageBox::information(this, "QT网络通信", "套接字无效!"); } 7):sServerDisConnection()具体实现: QMessageBox::information(this, "QT网络通信", "与客户端的连接断开"); return; 8):ui界面设计具体如下:

   b):客户端示例 1):在sockettcpclient.h中添加如下代码: private slots: void on_m_connectServerBtn_clicked(); void on_pushButton_2_clicked(); void ClientRecvData();private: Ui::SocketTCPClient *ui; QTcpSocket *mp_clientSocket; 2):在构造函数中添加如下代码: ui->m_serverIPLineEdit->setText("127.0.0.1"); ui->m_serverPortLineEdit_2->setText("5550"); 3):on_m_connectServerBtn_clicked()函数具体实现如下: mp_clientSocket = new QTcpSocket(); QString ip = ui->m_serverIPLineEdit->text(); int port = ui->m_serverPortLineEdit_2->text().toInt(); mp_clientSocket->connectToHost(ip, port); if(!mp_clientSocket->waitForConnected(30000)) { QMessageBox::information(this, "QT网络通信", "连接服务端失败!"); return; } connect(mp_clientSocket, SIGNAL(readyRead()), this, SLOT(ClientRecvData())); 4):on_pushButton_2_clicked()函数具体实现如下: //获取TextEdit控件中的内容 QString sendMsg = ui->m_sendTextEdit->toPlainText(); char sendMsgChar[1024] = {0}; strcpy_s(sendMsgChar, sendMsg.toStdString().c_str()); int sendRe = mp_clientSocket->write(sendMsgChar, strlen(sendMsgChar)); if(sendRe == -1) { QMessageBox::information(this, "QT网络通信", "向服务端发送数据失败!"); return; } 5):ClientRecvData()函数具体实现如下: //将接收内容存储到字符串中 char recvMsg[1024] = {0}; int recvRe = mp_clientSocket->read(recvMsg, 1024); if(recvRe == -1) { QMessageBox::information(this, "QT网络通信", "接收服务端数据失败!"); return; } QString showQstr = recvMsg; ui->m_recvTextEdit_2->setText(showQstr); 6):客户端ui具体设计如下:

7):最终实现如下图所示:

需要具体工程文件的可以访问:http://download.csdn.net/download/bailang_zhizun/10037740

3、基于QT的SOCKET程序与基于VS2012的SOCKET程序的通信

为了验证QT中SOCKET程序能否与VS2012中的SOCKET程序正常通信,编写了一个VS2012版的客户端程序,与QT版的服务端程序进行通信。双方都采用正常方式编写。经测试,双方能够正常通信。

结果如下所示:

PS:

1): 通过对两各程序的对比,总的来说,QT版的实现方式要比VS2012版的实现方式简单很多,因为QT把SOCKET相关的类进行了很好的封装,只暴露了几个简单的接口函数就能够实现SOCET的通信;而VS2012版的类的封装性不如QT,使用起来比较麻烦,需要记比较多的接口函数。

而且在QT中,基本上不需要翻看其他的内容,如果要查看某个函数的用法只需要按F1就可以,很方便;而VS2012版的,你懂得;

2): 其中我觉得区别最大的就是SOCKET通信的接收连接、接收数据的机制。在QT中,它采用的是信号-槽的形式,关于SOCKET通信的相关操作,可以通过信号的方式来触发对应的函数;而在VS2012中,它的实现方式则就要传统很多。比如拿服务端接收连接来说,QT只需要连接信号newConnection()与接收函数即可,不管会接收多少个连接,都会以非阻塞的方式在对应的槽函数中建立对应的套接字;而在VS2012中,接收一个连接很简单,但是当要接收多个连接时,while循环显然是不可用的,只能建立线程函数专门接收连接。

对于接收数据也是一样的,QT只需要建立信号readyRead()与具体的槽函数的映射关系,然后在槽函数读取数据即可。而在VS2012中,则需要通过while循环去接收数据,对于需要并行处理数据的程序来说,则需要引入多线程。

3): 本人只是对最常见的实现方式进行了对比,属于比较纯真的乌龟的。如有不足之处,还请见谅并指出,大家共同进步。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。