客户端TCPSocket链接服务器 ,连接成功时服务器返回connected信号 弹出相应窗口(showConnect())
//链接服务器
connect(&m_tcpSocket,&QTcpSocket::connected,[=](){
this->showConnect();
});
m_tcpSocket.connectToHost(m_strIP,m_usPort);
m_tcpSocket.connectToHost(m_strIP,m_usPort);
这行代码是实际发起TCP连接请求的。它告诉m_tcpSocket
对象尝试连接到指定的IP地址和端口。这个操作是异步的,意味着connectToHost
函数会立即返回,而实际的连接过程会在后台进行。当连接成功时,m_tcpSocket
会发射connected()
信号。
搭建服务器:创建TcpServer文件
加载配置文件:TcpServer.cpp
与在搭建客户端(TcpClient)加载资源文件的过程一致,打开文件,读取IP.PROT。
创建MyTcpServer.h继承QTcpServer,使用MyTcpServer创建的对象监听客户端的连接申请,
void incomingConnection()在客户端申请连接服务器时自动调用。
MyTcpServer创建的对象监听客户端的连接申请:MyTcpServer::getInstance().listen(IP,PROT)
#include "mytcpserver.h"
#include <QDebug>
MyTcpServer::MyTcpServer(QObject *parent)
: QTcpServer{parent}
{}
MyTcpServer &MyTcpServer::getInstance()
{
static MyTcpServer instance;
return instance;
}
void MyTcpServer::incomingConnection(qintptr handle)
{
qDebug()<<"new client connected";
}
客户端通过TcpSocket将数据传入到PDU协议中的caMsg中发送
服务器通过TcpSocket接受PDU中的数据,将收到的信息写到数据库中,通过OpeDB.h文件进行实现。
服务器接收到消息的具体操作:
1.客户端与数据库相互链接:
m_db=QSqlDatabase::addDatabase("QSQLITE");//添加SQLite数据库连接
void OpeDB::init()
{
m_db.setHostName("localhost");//连接数据库
m_db.setDatabaseName("D:/SQLite3/TcpServer/cloud.db");//操作的数据库名称
if(m_db.open())
{
//查询数据库
QSqlQuery query;
query.exec("select * from usrInfo");
while(query.next())//遍历结果集,按行读取
{
QString data=QString("%1,%2,%3").arg(query.value(0).toString()).arg(query.value(1).toString()).arg(query.value(2).toString());
qDebug()<<data;
}
qDebug()<<"数据库打开成功";
}
else
{
qDebug()<<"数据库打开失败";
//QString title=QString("打开数据库");
//QString mes=QString("数据库打开失败");
//QMessageBox::critical(this,title,mes);
}
}
2.使用socket读取从客户端传来的PDU的信息;
(1)先读取总的信息长度;
(2)再创建PDU,按照设置的PDU格式读取其他的信息;
//使用Socket读取从客户端传来的PDU的信息
qDebug()<<this->bytesAvailable();
uint uiPDULen=0;
this->read((char*)&uiPDULen,sizeof(uint));//接受数据的起始地址和地址长度 先接受总大小
uint uiMsgLen=uiPDULen-sizeof(PDU);//实际数据长度
PDU *pdu=mkPDU(uiMsgLen);
this->read((char*)pdu+sizeof(uint),uiPDULen-sizeof(uint));//读取除了第一项数据总长度之外,PDU中其他的数据
(3)判断接收消息的类型进而进行不同的后续操作,此时接收的为注册申请,将用户信息写入数据库,写入操作如下:
char caName[32]={'\0'};
char caPwd[32]={'\0'};
strncpy(caName,pdu->caData,32);
strncpy(caPwd,pdu->caData+32,32);
//将pdu信息写入数据库
bool ret=OpeDB::getInstance().handleRegist(caName,caPwd);
bool OpeDB::handleRegist(const char *name, const char *pwd)
{
if(name==nullptr || pwd==nullptr)
{
qDebug()<<"name==nullptr || pwd==nullptr false";
return false;
}
QString data=QString("insert into usrInfo(name,pwd) values(\'%1\',\'%2\')").arg(name).arg(pwd);//在数据库的用户表中插入信息
qDebug()<<data;
QSqlQuery query;
return query.exec(data);//在数据库中查询信息是否存在--数据是否插入成功
}
(4)数据写入成功后,返还给客户端 申请回复 的消息,将消息放入PDU中并由Socket进行发送write
PDU *resPDU=mkPDU(0);//将回复信息放到resPDU的caData中
if(ret)
{
//在数据库中写入信息成功,服务器回复客户端加入成功
resPDU->uiMsgType=ENUM_MSG_TYPE_REGIST_RESPONE;
strcpy(resPDU->caData,REGIST_OK);
}
else
{
QString str="regist false";
strcpy(resPDU->caData,REGIST_FAILED);
}
//使用socket将存储的信息通过PDU发给客户端
write((char*)resPDU,pdu->uiPDULen);
freePDU(resPDU);
resPDU=nullptr;
resvMsg具体代码
void MyTcpSocket::recvMsg()
{
//使用Socket读取从客户端传来的PDU的信息
qDebug()<<this->bytesAvailable();
uint uiPDULen=0;
this->read((char*)&uiPDULen,sizeof(uint));//接受数据的起始地址和地址长度 先接受总大小
uint uiMsgLen=uiPDULen-sizeof(PDU);//实际数据长度
PDU *pdu=mkPDU(uiMsgLen);
this->read((char*)pdu+sizeof(uint),uiPDULen-sizeof(uint));//读取除了第一项数据总长度之外,PDU中其他的数据
//判断接收的数据类型
switch (pdu->uiMsgType) {
case ENUM_MSG_TYPE_REGIST_REQUEST://注册申请
{
char caName[32]={'\0'};
char caPwd[32]={'\0'};
strncpy(caName,pdu->caData,32);
strncpy(caPwd,pdu->caData+32,32);
//将pdu信息写入数据库
bool ret=OpeDB::getInstance().handleRegist(caName,caPwd);
PDU *resPDU=mkPDU(0);//将回复信息放到resPDU的caData中
if(ret)
{
//在数据库中写入信息成功,服务器回复客户端加入成功
resPDU->uiMsgType=ENUM_MSG_TYPE_REGIST_RESPONE;
strcpy(resPDU->caData,REGIST_OK);
}
else
{
QString str="regist false";
strcpy(resPDU->caData,REGIST_FAILED);
}
//使用socket将存储的信息通过PDU发给客户端
write((char*)resPDU,pdu->uiPDULen);
freePDU(resPDU);
resPDU=nullptr;
break;
}
default:
break;
}
freePDU(pdu);
pdu=nullptr;
}
服务器返回信息,客户端进行相应接收:
服务器向客户端发送信号时,产生readyRead信号
使用socket读取来自客户端的PDU信息,读取方式与服务器的接收过程相同
void TcpClient::recvMsg()
{
//使用socket读取来自服务器PDU的数据
qDebug()<<m_tcpSocket.bytesAvailable();
uint uiPDULen=0;
m_tcpSocket.read((char*)&uiPDULen,sizeof(uint));//读取总数据大小的信息
uint uiMsgLen=uiPDULen-sizeof(PDU);//实际信息的长度
PDU *pdu=mkPDU(uiMsgLen);//创建对应的PDU协议进行读取
m_tcpSocket.read((char*)pdu+sizeof(uint),uiPDULen-sizeof(uint));
switch (pdu->uiMsgType) {
case ENUM_MSG_TYPE_REGIST_RESPONE://回复数据类型
{
if(strcmp(pdu->caData,REGIST_OK)==0)
{
QMessageBox::information(this,"注册结果","注册成功");
}
else
{
QMessageBox::warning(this,"注册结果","注册失败");
}
break;
}
default:
break;
}
}