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_H
dialog.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);}



0 0