You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

gSOAP SSL服务器报错:soap_ssl_accept()无套接字,求问题排查

问题:gSOAP SSL服务器启动时出现"No socket in soap_ssl_accept()"错误

我正尝试搭建一个带SSL的gSOAP示例服务器,操作步骤如下:

  • 生成自签名证书:openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
  • 将证书合并为一个文件:cat cert.pem key.pem >both.pem
  • 运行如下代码:
#include <stdsoap2.h>
#include <stdexcept>
#include <sstream>
#include <iostream>
#define PORT 6667
int main(int argc, char **argv) {
 struct soap engine(SOAP_C_UTFSTRING);
 engine.bind_flags=SO_REUSEADDR;
 soap_ssl_noinit();
 int rc = soap_ssl_server_context(&engine, SOAP_SSL_DEFAULT, "both.pem", // keyfile
 nullptr, // password
 nullptr, // cacert
 nullptr, // capath
 nullptr, // dhfile
 nullptr, // randfile
 nullptr // serverid
 );
 if (rc) {
 std::stringstream error;
 soap_stream_fault(&engine, error);
 throw std::runtime_error("soap_ssl_server context failed " + error.str());
 }
 rc = soap_bind(&engine, NULL, PORT, 100);
 if (rc < 0) {
 throw std::runtime_error("soap_bind failed " + std::to_string(rc));
 }
 int master_socket = rc;
 std::cout << "master socket: " << master_socket << std::endl;
 engine.accept_timeout = 50;
 engine.send_timeout = 50;
 engine.recv_timeout = 50;
 rc = soap_ssl_accept(&engine);
 if (rc) {
 soap_stream_fault(&engine, std::cout);
 throw std::runtime_error("soap_ssl_accept failed " + std::to_string(rc));
 }
 std::cout << "soap_ssl_accept " << rc << std::endl;
 return 0;
}

但运行后输出:

master socket: 3
Error 30 fault detected[no subcode]
"SSL/TLS error"
Detail: No socket in soap_ssl_accept()
terminate called after throwing an instance of 'std::runtime_error'
what(): soap_ssl_accept failed 30

请问我哪里操作有误?


解答

看起来你在gSOAP SSL服务器的流程上踩了个小坑——问题出在soap_ssl_accept()的调用时机不对!

soap_ssl_accept()的作用是完成SSL握手,但它需要先有一个已经建立的客户端连接socket才行。你的代码在soap_bind()之后直接调用它,可此时soap结构体里只有监听用的主socket,并没有客户端连接的socket,所以才会抛出"No socket in soap_ssl_accept()"的错误。

正确的流程应该是这样:

  1. 初始化soap结构体并配置SSL上下文(这部分你已经做对了)
  2. 用soap_bind()绑定端口,拿到监听用的主socket
  3. 调用soap_accept()等待客户端连接,这个函数会把客户端的连接socket关联到soap结构体中
  4. 最后再调用soap_ssl_accept()完成SSL握手

修正后的代码示例:

#include <stdsoap2.h>
#include <stdexcept>
#include <sstream>
#include <iostream>
#define PORT 6667
int main(int argc, char **argv) {
 struct soap engine(SOAP_C_UTFSTRING);
 engine.bind_flags=SO_REUSEADDR;
 soap_ssl_noinit();
 int rc = soap_ssl_server_context(&engine, SOAP_SSL_DEFAULT, "both.pem", // keyfile
 nullptr, // password
 nullptr, // cacert
 nullptr, // capath
 nullptr, // dhfile
 nullptr, // randfile
 nullptr // serverid
 );
 if (rc) {
 std::stringstream error;
 soap_stream_fault(&engine, error);
 throw std::runtime_error("soap_ssl_server context failed " + error.str());
 }
 rc = soap_bind(&engine, NULL, PORT, 100);
 if (rc < 0) {
 throw std::runtime_error("soap_bind failed " + std::to_string(rc));
 }
 int master_socket = rc;
 std::cout << "master socket: " << master_socket << std::endl;
 engine.accept_timeout = 50;
 engine.send_timeout = 50;
 engine.recv_timeout = 50;

 // 先接收客户端的连接请求,拿到客户端socket
 rc = soap_accept(&engine);
 if (rc < 0) {
 throw std::runtime_error("soap_accept failed " + std::to_string(rc));
 }
 std::cout << "Accepted client connection, socket: " << rc << std::endl;

 // 现在再完成SSL握手
 rc = soap_ssl_accept(&engine);
 if (rc) {
 soap_stream_fault(&engine, std::cout);
 throw std::runtime_error("soap_ssl_accept failed " + std::to_string(rc));
 }
 std::cout << "SSL handshake succeeded!" << std::endl;

 // 这里可以添加处理客户端SOAP请求的逻辑,比如调用soap_serve(&engine)

 // 记得释放资源
 soap_destroy(&engine);
 soap_end(&engine);
 soap_done(&engine);
 return 0;
}

额外提醒:

  • 实际生产环境的服务器,通常需要套一个循环,不断调用soap_accept()和soap_ssl_accept()来处理多个客户端连接
  • 一定要记得在程序结束时调用soap_destroy()、soap_end()、soap_done(),避免内存泄漏
  • 如果需要验证客户端证书,可以在soap_ssl_server_context()中传入CA证书路径(cacert参数),并把SOAP_SSL_DEFAULT换成SOAP_SSL_REQUIRE_CLIENT_AUTH这类需要客户端认证的标志

内容的提问来源于stack exchange,提问作者Adam Trhon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:49:10