Qt模块化笔记之network——写第一个Tcp程序(1)

本节以QTcpServerQTcpSocket为主,联合其它知识(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_OBJECT
public:
    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_OBJECT
public:
    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_OBJECT

public:
    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);
}



  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值