数据丢失的假象
用buffer
封装字符串时,要注意字符串末尾的'\0'
,如下:
boost::asio::async_write(*sock,
boost::asio::buffer("hello,server!"),
boost::bind(&client::handle_write,this,
boost::asio::placeholders::error));
服务器端收到的也是包含'\0'
的,如果在某种情况(如下面要说的发送队列)下客户端很快速的发送多次同样的数据,在服务器端用std::cout << readdata << std::endl
查看控制台输出结果时会发现数据是不完整的,类似下面:
hello,server!
hello,server!
hello,server!
rver!
llo,server!
如果查看读取数据的长度时,会发现实际上接收的数据长度是正确,原因是std::cout
输出读到'\0'
时就截断了数据,忽略掉后面的数据了.为了避免这种情况,可限定buffer
发送的数据长度,把'\0'
截掉,如下:
boost::asio::async_write(*sock,
boost::asio::buffer("hello,server!",13),
boost::bind(&client::handle_write,this,
boost::asio::placeholders::error));
串行化发送队列
想要客户端连续的发送信息到服务器,于是乎这样写:
for ( int i = 0 ; i < 30 ; i++ )
{
boost::asio::async_write(*sock,
boost::asio::buffer("hello,server!",13),
boost::bind(&client::handle_write,this,
boost::asio::placeholders::error));
}
结果时对时错,输出如下:
hello,server!hello,server!hello,server!hello,serveoost_Servier
r!hello,server!hello,server!hello,server!hello,seroost_Servier
ver!hello,server!hello,server!hello,server!hello,soost_Servier
erver!hello,server!hello,server!hello,server!hellooost_Servier
,server!hello,server!hello,server!hello,server!heloost_Servier
lo,server!hello,server!hello,server!hello,server!
hello,server!
hello,server!
hello,server!hello,server!
hello,server!hello,server!
hello,server!
网上搜了很久才知道,要这样:
// ...
// some code
// ...
void do_write()
{
cout = 0;
boost::asio::async_write(*sock,
boost::asio::buffer("hello,server!",13),
boost::bind(&client::handle_write,this,
boost::asio::placeholders::error));
}
// ...
// some code
// ...
void handle_write(const boost::system::error_code& error)
{
if (error) return;
if (count == 30) return;
count++;
// 演示发送了30次,实际应用应该根据业务要求在此决定是否继续发送
boost::asio::async_write(*sock,
boost::asio::buffer("hello,server!",13),
boost::bind(&client::handle_write,this,
boost::asio::placeholders::error));
}
结论是,在一次异步操作到回调被调之前,要确保此次异步操作相关数据的完整性,否则结果难以预料.
获得数据长度
要在read时获得读到的数据长度,加占位符:boost::asio::placeholders::bytes_transferred
,如下:
m_socket.async_read_some(boost::asio::buffer(data_,max_len),
boost::bind(&clientSession::handle_read,shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
...
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
...
}
读写并发
一个socket多线程同时读写并发,网上有的说不行,亲测是可以的!socket的读写缓冲区是分开的.但是,多线程同时读一个socket,或多线程同时写一个socket就不行的,上面”发送队列”单线程都有时出问题,何况多线程.
说一下csdn的Markdown编辑器,开始一进来有个初始文章,是帮助,左边用法,右边结果,非常好,所有功能和用法一览无遗.可是写新文章后没了,只剩下个简约版的帮助,第一次写这东西,没经验,看不懂,没有开始那篇” 欢迎使用CSDN-markdown编辑器”来的直观,最后解决办法是申请了新账号,就为了看那个帮助.希望这个编辑器的色戒师能照顾一下初学者.