在 SSL 客户端服务器模型中,我使用下面的代码从客户端或服务器端的套接字读取数据。
我只在有可用数据时才读取数据。为了知道何时有可用数据,我检查了 asio::ssl::stream 的 lowest_layer() 上的 available() 方法.
当我从客户端向服务器发送380个字节并在服务器上进入读取方法后,我看到以下内容。
‘s’是我提供的缓冲区。
“n”是我提供的缓冲区的大小。
‘a1’是读取前available()的结果,将报告458字节。
‘r’是实际读取的字节数。它会报告380,这是正确的。
‘a2’是读取后 available() 的结果,将报告 0 字节。这是我所期望的,因为我的客户发送了 380 个字节,我已经全部阅读了。
为什么第一次调用 available() 报告字节太多?
类型:
/**
* Type used as SSL Socket. Handles SSL and socket functionality.
*/
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SslSocket;
/**
* A shared pointer version of the SSL Socket type.
*/
typedef boost::shared_ptr<SslSocket> ShpSslSocket;
成员:
ShpSslSocket m_shpSecureSocket;
部分读取方法:
std::size_t a1 = 0;
if ((a1 = m_shpSecureSocket->lowest_layer().available()) > 0)
{
r += boost::asio::read(*m_shpSecureSocket,
boost::asio::buffer(s, n),
boost::asio::transfer_at_least(1));
}
std::size_t a2 = m_shpSecureSocket->lowest_layer().available();
添加信息:
所以我改变了我的读取方法来更彻底地检查是否还有数据可以从 boost::asio::ssl::stream 中读取。我不仅需要检查套接字级别是否有可用数据,而且还可能有数据卡在某处的 OpenSSL 缓冲区中。 SSL_peek 可以解决问题。除了检查可用数据之外,它还会检查 TCP 端口状态并在没有超时的情况下执行所有这些操作。
这是我创建的 boost::iostreams::device 类的完整读取方法。
std::streamsize SslClientSocketDevice::read(char* s, std::streamsize n)
{
// Request from the stream/device to receive/read bytes.
std::streamsize r = 0;
LIB_PROCESS::TcpState eActualState = LIB_PROCESS::TCP_NOT_EXIST;
char chSslPeekBuf; // 1 byte peek buffer
// Check that there is data available. If not, wait for it.
// Check is on the lowest layer (tcp). In that layer the data is encrypted.
// The number of encrypted bytes is most often different than the number
// of unencrypted bytes that would be read from the secure socket.
// Also: Data may be read by OpenSSL from the socket and remain in an
// OpenSSL buffer somewhere. We also check that.
boost::posix_time::ptime start = BOOST_UTC_NOW;
int nSslPeek = 0;
std::size_t nAvailTcp = 0;
while ((*m_shpConnected) &&
(LIB_PROCESS::IpMonitor::CheckPortStatusEquals(GetLocalEndPoint(),
GetRemoteEndPoint(),
ms_ciAllowedStates,
eActualState)) &&
((nAvailTcp = m_shpSecureSocket->lowest_layer().available()) == 0) &&
((nSslPeek = SSL_peek(m_shpSecureSocket->native_handle(), &chSslPeekBuf, 1)) <= 0) && // May return error (<0) as well
((start + m_oReadTimeout) > BOOST_UTC_NOW))
{
boost::this_thread::sleep(boost::posix_time::millisec(10));
}
// Always read data when there is data available, even if the state is no longer valid.
// Data may be reported by the TCP socket (num encrypted bytes) or have already been read
// by SSL and not yet returned to us.
// Remote party can have sent data and have closed the socket immediately.
if ((nAvailTcp > 0) || (nSslPeek > 0))
{
r += boost::asio::read(*m_shpSecureSocket,
boost::asio::buffer(s, n),
boost::asio::transfer_at_least(1));
}
// Close socket when state is not valid.
if ((eActualState & ms_ciAllowedStates) == 0x00)
{
LOG4CXX_INFO(LOG4CXX_LOGGER, "TCP socket not/no longer connected. State is: " <<
LIB_PROCESS::IpMonitor::TcpStateToString(eActualState));
LOG4CXX_INFO(LOG4CXX_LOGGER, "Disconnecting socket.");
Disconnect();
}
if (! (*m_shpConnected))
{
if (r == 0)
{
r = -1; // Signal stream is closed if no data was retrieved.
ThrowExceptionStreamFFL("TCP socket not/no longer connected.");
}
}
return r;
}
最佳答案
所以也许我知道这是为什么。这是一个 SSL 连接,因此传输的字节将被加密。由于 block 的大小,加密数据的大小很可能不同。我想这回答了为什么 TCP 级别的可用字节数与读取的字节数不同的问题。
关于c++ - Boost asio tcp socket available 报告不正确的字节数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12949274/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参
我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:
我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co
我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent
导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri
我正在使用Ruby,我正在与一个网络端点通信,该端点在发送消息本身之前需要格式化“header”。header中的第一个字段必须是消息长度,它被定义为网络字节顺序中的2二进制字节消息长度。比如我的消息长度是1024。如何将1024表示为二进制双字节? 最佳答案 Ruby(以及Perl和Python等)中字节整理的标准工具是pack和unpack。ruby的packisinArray.您的长度应该是两个字节长,并且按网络字节顺序排列,这听起来像是n格式说明符的工作:n|Integer|16-bitunsigned,network(bi
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我在OSX上(如果重要的话)。如果我使用RVM安装Ruby,它会默认将Bundler安装到@globalgemset假设我想要一个不同版本的bundler。我假设我需要做的就是执行geminstallbundler--version但是,这会将bundler安装到默认gemset并且RVM不会为其设置路径。因此,如果我键入bundler,它仍会启动一个与Ruby一起安装到@global中的bundler两个问题:如何将bundler安装到@globalgemset。将bundler安装到@globalgemset中的模式是否正确,或者我遗漏了什么 最佳答案