Qt模块化笔记之network——写第一个Tcp程序(1)
来源:互联网 发布:域名被微信封了怎么办 编辑:程序博客网 时间:2024/04/29 18:53
本节以QTcpServer与QTcpSocket为主,联合其它知识(sql与json),编写TCP服务器与客户端,以让读者更好理解Qt的TCP部分各函数功能。程序结构参考自qtcn上的liudianwu的TCP调试工具,原程序链接:点击打开链接。由于是业余爱好者,不知软件公司里这种程序结构,欢迎指点。
————————————————————————————————————————————————————————————
工程 结果图:
整个程序的思路如下:dialog中创建一个Server类(继承自QTcpServer),并调用它的listen函数开始监听。Server类重载了QTcpServer的 incomingConnection(qintptr socketDescriptor)函数,当有新连接时,在这个函数中不断new出新的ServerSocket(继承自QTcpSocket),并用ServerSocket的setSocketDescriptor(qintptr socketDescriptor)函数,将socketDescriptor从Server中传到new出来的socket中,在类Server中,用QMap<int,ServerSocket *> idSocketMap;这个容器,保存new出来的ServerSocket与它对应的id(即socketDescriptor)。可相像为Server抓住了一大把电话机与它们对应的ID,这时Server就可以通过ID找到对应电话机,自由地向其中某个发送数据了。
在Server类中,我们添加了两个自定义功能,即:
1,实现用户名登陆。函数为:bool login(QString userName,QString passWord);
2,查某用户名的信息(需先登陆),并以json格式返回数据到客户端。函数为:QString getInfoJson(QString userName);
————————————————————————————————————————————————————————————
先写服务器部分。
新建一个带ui的dialog工程。
从局部到整体的顺序,先编写我们的"电话“socket,类名为ServerSocket,继承自 QTcpSocket。向导中如图:
同理,其它类也这样
————————————————————————————————————————————————————————————
下面通过各个头文件,了解各个类及它们的功能
serversocket.h:
#ifndef SERVERSOCKET_H#define SERVERSOCKET_H#include <QTcpSocket>#include <QHostAddress>#include <QAbstractSocket>class ServerSocket : public QTcpSocket{ Q_OBJECTpublic: explicit ServerSocket(QObject *parent = 0,int serverSocketID=0);//在这里为它多加了serverSocketID,将TcpServer的SocketDescriptor传进来。signals: void serverSocketReadData(int serverSocketID,QString IP,int Port,QByteArray data);//自建的server类,通过这个信号,得到传输来的数据的来源及具体内容 void serverSocketDisConnect(int serverSocketID,QString IP,int Port);//断开连接时,通过这个信号,Server类将容器idSocketMap内对应的套接字删除private: int serverSocketID;private slots: void ReadData();//具体实现读取数据 void DisConnect(); void outPutError(QAbstractSocket::SocketError);//qDebug输出套接字出错信息};#endif // SERVERSOCKET_H
server.h
#ifndef SERVER_H#define SERVER_H#include "serversocket.h"#include <QTcpServer>#include <QMap>#include <QJsonDocument>#include <QJsonParseError>#include <QJsonObject>#include <QSqlDatabase>#include <QSqlQuery>class Server : public QTcpServer{ Q_OBJECTpublic: explicit Server(QObject *parent = 0); bool login(QString userName,QString passWord);//通过查询sqlite数据库对比用户名进行登陆,登陆后,将登陆成功的用户添加到用户列表QMap<int,QString> idUserMap; QString getInfoJson(QString userName); int serverSocketCount;//用于统计连接的用户数,private: QSqlDatabase db; QMap<int,ServerSocket *> idSocketMap; QMap<int,QString> idUserMap;protected: void incomingConnection(int serverSocketID);signals: void hasData(int serverSocketID,QString IP,int Port,QByteArray data);//这三个信号用于告诉dialog信息,用于dialog的UI的信息显示,比如更新显示用户连接数 void hasConnect(int serverSocketID,QString IP,int Port); void hasDisConnect(int serverSocketID,QString IP,int Port);private slots: void ReadData(int serverSocketID,QString IP,int Port,QByteArray data);//连接到ServerSocket的void serverSocketReadData……信号 void DisConnect(int serverSocketID,QString IP,int Port);};#endif // SERVER_Hdialog.h
#ifndef DIALOG_H#define DIALOG_H#include <QDialog>#include "server.h"namespace Ui {class Dialog;}class Dialog : public QDialog{ Q_OBJECTpublic: explicit Dialog(QWidget *parent = 0); ~Dialog();private: Ui::Dialog *ui; Server *server;public slots: void updateCount(); void updateData(int a,QString b,int c,QByteArray d);};#endif // DIALOG_H
————————————————————————————————————————————————————
三个类的具体实现:
serversocket.cpp
#include "serversocket.h"#include "myhelper.h"ServerSocket::ServerSocket(QObject *parent,int serverSocketID) : QTcpSocket(parent){ this->serverSocketID=serverSocketID; connect(this,SIGNAL(readyRead()),this,SLOT(ReadData()));//挂接读取数据信号 connect(this,SIGNAL(disconnected()),this,SLOT(DisConnect()));//关闭连接时,发送断开连接信号 connect(this,SIGNAL(disconnected()),this,SLOT(deleteLater()));//关闭连接时,对象自动删除 connect(this,SIGNAL(error(QAbstractSocket::SocketError)), this,SLOT(outPutError(QAbstractSocket::SocketError)));}void ServerSocket::ReadData(){ myHelper::Sleep(100); //读取完整一条数据并发送信号 QByteArray data=this->readAll(); emit serverSocketReadData(this->serverSocketID,this->peerAddress().toString(),this->peerPort(),data);}void ServerSocket::DisConnect(){ //断开连接时,发送断开信号 emit serverSocketDisConnect(this->serverSocketID,this->peerAddress().toString(),this->peerPort());}void ServerSocket::outPutError(QAbstractSocket::SocketError){ this->disconnectFromHost(); qDebug()<< this->errorString();}server.cpp
#include "server.h"#include "serversocket.h"#include <QDebug>#include <QSqlRecord>Server::Server(QObject *parent) : QTcpServer(parent){ db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("myDB.db"); if(!db.open()) { qDebug()<< "打开数据库出错"; }}bool Server::login(QString userName, QString passWord){ QSqlQuery query_select(QString("SELECT * FROM userInfo where userName=\"%1\" and passWord=\"%2\" ").arg(userName).arg(passWord)); while(query_select.next()) { if(query_select.value("userName").toString()=="" ) { return false; }else { return true; } } return false;}QString Server::getInfoJson(QString userName){ qDebug()<<userName; QString sex; QString age; QString height; QSqlQuery query_select(QString("SELECT * FROM userInfo where userName=\"%1\"").arg(userName)); while (query_select.next()) { sex =query_select.value("sex").toString(); age = query_select.value("age").toString(); height = query_select.value("height").toString(); } qDebug()<<sex; QString a=QString("{\"type\":\"getInfo result\",\"sex\":\"%1\",\"age\":\"%2\", \"height\":\"%3\"}").arg(sex).arg(age).arg(height); return a;}void Server::incomingConnection(int serverSocketID){ ServerSocket *serverSocket=new ServerSocket(this,serverSocketID); serverSocket->setSocketDescriptor(serverSocketID); connect(serverSocket,SIGNAL(serverSocketReadData(int,QString,int,QByteArray)),this,SLOT(ReadData(int,QString,int,QByteArray))); connect(serverSocket,SIGNAL(serverSocketDisConnect(int,QString,int)),this,SLOT(DisConnect(int,QString,int))); connect(serverSocket,SIGNAL(aboutToClose()),this,SLOT(deleteLater()));//关闭监听时,对象自动删除 idSocketMap.insert(serverSocketID,serverSocket); serverSocketCount++; emit hasConnect(serverSocketID, serverSocket->peerAddress().toString(),serverSocket->peerPort()); qDebug()<<serverSocketCount;}void Server::ReadData(int serverSocketID,QString IP,int Port,QByteArray data){ emit hasData(serverSocketID,IP,Port,data); QJsonDocument jsonAnalyse; QJsonParseError *jsonError=new QJsonParseError; jsonAnalyse=QJsonDocument::fromJson(data,jsonError); if(! jsonError->error==QJsonParseError::NoError) { qDebug()<< "接收到的数据不完整或出错"; return; } if(jsonAnalyse.isObject()) { QJsonObject obj=jsonAnalyse.object();//取得最外层这个大对象 QString str=obj["type"].toString(); QByteArray arrSend; if(str=="login") { QString userName = obj["userName"].toString(); QString passWord = obj["passWord"].toString(); if(login(userName,passWord)) { qDebug()<< userName << "登陆成功"; idUserMap.insert(serverSocketID,userName); arrSend.append("{\"type\":\"login result\",\"result\":\"success\"}"); }else { qDebug()<< userName << "登陆失败"; arrSend.append("{\"type\":\"login result\",\"result\":\"failed\"}"); } }else if(str=="getInfo") { if(idUserMap.contains(serverSocketID)) { QString a=getInfoJson(idUserMap.value(serverSocketID)); arrSend=a.toLatin1(); }else { arrSend.append("{\"type\":\"login result\",\"result\":\"do not logined\"}"); } } ServerSocket *Socket = idSocketMap.value(serverSocketID); Socket->write(arrSend); }}void Server::DisConnect(int serverSocketID,QString IP,int Port){ idSocketMap.remove(serverSocketID); idUserMap.remove(serverSocketID); serverSocketCount--; emit hasDisConnect(serverSocketID,IP,Port);}
#include "dialog.h"#include "ui_dialog.h"#include <QHostAddress>Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog){ ui->setupUi(this); server = new Server(this); server->listen(QHostAddress::LocalHost,1992); connect(server,SIGNAL(hasConnect(int,QString,int)),this,SLOT(updateCount())); connect(server,SIGNAL(hasDisConnect(int,QString,int)),this,SLOT(updateCount())); connect(server,SIGNAL(hasData(int,QString,int,QByteArray)),this,SLOT(updateData(int,QString,int,QByteArray)));}Dialog::~Dialog(){ delete ui;}void Dialog::updateCount(){ ui->label_2->setText(QString::number(server->serverSocketCount));}void Dialog::updateData(int a, QString b, int c, QByteArray d){ QString str=QString("来自:%1;ip:%2;port:%3;data:%4").arg(a).arg(b).arg(c).arg(QString(d)); ui->plainTextEdit->appendPlainText(str);}
- Qt模块化笔记之network——写第一个Tcp程序(1)
- Qt模块化笔记之network——写第一个Tcp程序(2)
- Qt模块化笔记之network——第二个TCP程序,传输图片文件的实现(1)
- Qt模块化笔记之network——第二个TCP程序,传输图片文件的实现(2)
- Qt模块化笔记之network——第二个TCP程序,传输图片文件的实现(2)
- Qt模块化笔记之core——QXmlStreamWriter写XML
- Qt模块化笔记之network——套接字Socket网络编程起步
- Qt模块化笔记之network——TcpServer与监听说明
- Qt模块化笔记之network——DNS域名系统与查询功能
- Qt模块化笔记之Qt_Quick——给Qt编写的安卓程序添加图标
- QT——第一个QT程序
- VS2013写QT的第一个程序
- Qt模块化笔记之Qt Widgets——日历类
- Qt模块化笔记之core——QProcess控制外部程序
- Qt模块化笔记——QuickProxy代理程序
- Qt学习笔记:第一个程序HelloWorld
- Qt模块化笔记之sql——前期准备
- Qt模块化笔记之sql——连接数据库
- [Android] ListView中getView的原理+如何在ListView中放置多个item + android中ListView多次刷新多次重复执行getView的问题另解
- 开源爬虫软件汇总
- 测试员,敢问路在何方?读后感!
- MyTreeSet(with parent node)
- 关于codeforces比赛规则介绍(转载)
- Qt模块化笔记之network——写第一个Tcp程序(1)
- 简易的学生管理系统
- 在eclipse中搭建android开发平台
- oracle定时备份-增量备份
- 贪心问题
- Android获取视屏的缩略视图和图片的缩略视图
- 实现类似小米手机的秒表指针旋转动画摸索
- 《小情绪》
- 数据结构---设计一个栈,push, pop, min 时间复杂度都是 O(1)