【问题标题】:Writing Secure Server Applications with Qt使用 Qt 编写安全的服务器应用程序
【发布时间】:2014-05-16 12:59:56
【问题描述】:

我已经按照教程“使用 Qt 编写安全服务器应用程序”(https://blog.quickmediasolutions.com/2012/09/18/writing-secure-server-applications-with-qt.html)但是我遇到了错误:

CSampleServer.h

#ifndef CSAMPLESERVER_H
#define CSAMPLESERVER_H

#include <QTcpServer>

class CSampleServer : public QTcpServer
{
public:
    CSampleServer();

private:
    void incomingConnection(int);

signals:
    void StatusMessage(QString);
};

#endif // CSAMPLESERVER_H

CSampleServer.cpp

#include "CSampleServer.h"
#include "CSecureSocket.h"

CSampleServer::CSampleServer()
{
}

void CSampleServer::incomingConnection(int handle)
{
    CSecureSocket * socket = new CSecureSocket(this);
    connect(socket, SIGNAL(StatusMessage(QString)), SIGNAL(StatusMessage(QString)));
    socket->Process(handle);
}

CSecureSocket.h

#ifndef CSECURESOCKET_H
#define CSECURESOCKET_H

#include <QSslSocket>

class CSecureSocket : public QSslSocket
{
public:
    CSecureSocket();
    void Process(int);


signals:
    void StatusMessage(QString);
};

#endif // CSECURESOCKET_H

CSecureSocket.cpp

#include "CSecureSocket.h"
#include <QHostAddress>

CSecureSocket::CSecureSocket()
{
}

void CSecureSocket::Process(int handle)
{
    /* Emit a message indicating the address of the client. */
    setSocketDescriptor(handle);
    emit StatusMessage(tr("Incoming connection from %1.").arg(peerAddress().toString()));

    /* Set the certificate and private key. */
    setLocalCertificate("server.crt");
    setPrivateKey("server.key.insecure");

    /* Start the server encryption process and wait for it to complete. */
    startServerEncryption();
    if(waitForEncrypted())
    {
        emit StatusMessage("Session with client is now encrypted.");

        /* Respond with a basic HTTP message. */
        write("HTTP/1.1 200 OK\r\n"
              "Content-type: text/plain\r\n"
              "Content-length: 12\r\n"
              "\r\n"
              "Hello World!");

        emit StatusMessage("Message sent to client. Closing connection.");
    }
    else
        emit StatusMessage(tr("An error occurred: %1.").arg(errorString()));

    /* Close the connection once the data is written. */
    disconnectFromHost();
}

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "CSampleServer.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void OnStart();
    void OnStatusMessage(QString);

private:
    Ui::MainWindow *ui;
    CSampleServer m_server;
};

#endif // MAINWINDOW_H

MainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(&m_server, SIGNAL(StatusMessage(QString)), SLOT(OnStatusMessage(QString)));
    connect(ui->pushButton, SIGNAL(clicked()), SLOT(OnStart()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::OnStart()
{
    quint16 port = ui->spinBox->value();
    if(m_server.listen(QHostAddress::Any, port))
        OnStatusMessage(tr("Listening on port %1...").arg(port));
    else
        OnStatusMessage(tr("Unable to listen on port %1.").arg(port));
}

void MainWindow::OnStatusMessage(QString message)
{
    ui->plainTextEdit->appendPlainText(message);
}

你能帮帮我吗?提前致谢!

【问题讨论】:

  • 隐式显示相关代码怎么样?
  • 我已经用我的代码更新了帖子
  • 为什么不用QSSLSocket?
  • 嗯好主意!是的。 tnx!

标签: c++ qt sockets ssl


【解决方案1】:

1.void CSampleServer::incomingConnection(int handle) 参数应该是 qintptr 而不是 int。

2.connect(socket, SIGNAL(StatusMessage(QString)), SIGNAL(StatusMessage(QString)));声明错误的接收者对象在哪里

3.void CSecureSocket::Process(int handle) 使用 qintptr

4.正确阅读文档有更多错误

【讨论】:

    【解决方案2】:

    问题是没有为 CSampleServer 和 CSecureSocket 类生成 moc_* 文件。

    要使该示例正常工作,您需要:

    1. 将 Q_OBJECT 宏添加到 CSampleServer.h 和 CSecureSocket.h 类定义中
    2. 清理项目
    3. 运行 qmake 并确保 moc_* 文件在那里。
    4. 再次构建项目,此时构建问题应该消失了。

    【讨论】:

      【解决方案3】:

      您可以使用 SSL 创建安全服务器。这是一个使用 QSsLSocket 的示例服务器:

      #include <QtNetwork>
      #include <QMessageBox>
      
      class server : public QTcpServer
      {
          Q_OBJECT
      public:
          explicit server(QObject *parent = 0);
          ~server();
      
          QSslSocket server_socket;
      
      public slots:
      
      
            void tcpReady();
      
            void encrypted();
      
            void sslError( QList<QSslError> errors );
      
            bool start_listen(int port_no);
      
      protected:
          void incomingConnection( int descriptor );
      
      };
      
      server::server(QObject *parent) :
          QTcpServer(parent)
      {
      
          server_socket.setProtocol(QSsl::SslV3);
      
          QByteArray key;
          QByteArray cert;
      
          QFile file_key("server.key");
          if(file_key.open(QIODevice::ReadOnly))
          {
              key = file_key.readAll();
              file_key.close();
          }
          else
          {
              qDebug() << file_key.errorString();
          }
      
          QFile file_cert("server.crt");
          if(file_cert.open(QIODevice::ReadOnly))
          {
              cert = file_cert.readAll();
              file_cert.close();
          }
          else
          {
              qDebug() << file_cert.errorString();
          }
      
      
          QSslKey ssl_key(key, QSsl::Rsa,QSsl::Pem,QSsl::PrivateKey,"server");
      
          QSslCertificate ssl_cert(cert);
      
          server_socket.addCaCertificate(ssl_cert);
          server_socket.setLocalCertificate(ssl_cert);
          server_socket.setPrivateKey(ssl_key);
      
      
          connect( &server_socket, SIGNAL(sslErrors(QList<QSslError>)),
                  this, SLOT(sslError(QList<QSslError>)) );
      
          connect(&server_socket,SIGNAL(encrypted()),this,SLOT(encrypted()));
      
          server_socket.setSocketOption(QAbstractSocket::KeepAliveOption, true );
      }
      
      server::~server()
      {
          server_socket.disconnectFromHost();
          server_socket.waitForDisconnected();
      }
      
      void server::tcpReady()
      {
          QByteArray array = server_socket.read( server_socket.bytesAvailable() );
          //...
      }
      
      void server::encrypted()
      {
          connect( &server_socket, SIGNAL(readyRead()),
                   this, SLOT(tcpReady()) );
          emit connection_established();
      }
      
      void server::sslError(QList<QSslError> errors)
      {
          QString erroStr="";
          foreach (const QSslError &e, errors)
              erroStr.append(e.errorString()).append("\n");
      
          QMessageBox::warning( (QWidget *)this->parent(), tr("Error"),erroStr );
      
          server_socket.ignoreSslErrors();
      }
      
      
      bool server::start_listen(int port_no)
      {
          if( !this->listen( QHostAddress::Any, port_no ) )
          {
              QMessageBox::warning( (QWidget *)this->parent(), tr("Error!"), tr("Cannot listen to port %1").arg(port_no) );
      
          }
          else
              return true;
      }
      
      void server::incomingConnection(int descriptor)
      {
          if(server_socket.state()!=QAbstractSocket::UnconnectedState)
              return;
          if( !server_socket.setSocketDescriptor( descriptor ) )
          {
              QMessageBox::warning( (QWidget *)this->parent(), tr("Error!"), tr("Socket error!") );
              return;
          }
          else
          {
              server_socket.startServerEncryption();
          }
      }
      

      您应该为您的应用程序生成一个 server.key 和一个 server.crt 文件。

      【讨论】:

      • 不错的解决方案@Nejat!我现在试试,希望一切都会好起来的:D
      • https 是一种网络协议。我认为我们正在谈论 TCP 连接。 https 也使用 SSL(或 TLS),即 HTTPS 是 HTTP-within-SSL。 SSL (TLS) 为两台主机之间的任意二进制数据建立安全的双向隧道。
      • 是的...根据指南可能...现在服务器运行,但是当我连接浏览器时 (localhost:8080) 错误消息:“QSslSocket::startServerEncryption: 无法开始握手非平面连接”
      【解决方案4】:

      这种用法:

      CSecureSocket * socket = new CSecureSocket(this);
      

      与此声明/定义不兼容:

      CSecureSocket();
      

      试试:

      CSecureSocket* socket = new CSecureSocket();
      

      ...

      【讨论】:

      • 我已经做了这个改变...现在当前的错误是:D:\Users\x\Documents\QT Projects\SSLSocket\CSecureSocket.cpp:12: error: undefined reference to `CSecureSocket::StatusMessage(QString)'
      • 你的 connect() 不是缺少另一个对象参数吗?在我看来,您正在将信号 CSecureSocket::StatusMessage(QString) 连接到自身。试试connect(socket, SIGNAL(StatusMessage(QString)), this, SIGNAL(StatusMessage(QString))) 或类似的东西...
      • 我已经做了这个更正...没什么...:(我关注了这篇文章:quickmediasolutions.com/blog/13/…
      猜你喜欢
      • 2010-12-29
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-12
      • 2014-06-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多