我提供了一个用 Asio 编写的简单客户端和服务器,以显示可能存在错误的内容。 客户端重复向服务器发送长度为102的固定字符串,服务器检查该字符串 要正确,如果不是这样就写一条错误信息并退出。
代码编译并在debian 7(amd64)中运行
我的处理器有2个核心
提升版是1.55
运行服务器和客户端时,发送几千个数据包 收到错误的数据包(可能需要重复测试几次)
问题是什么?
Makefile
CXX=g++
LIBS = -lboost_thread -lboost_filesystem -lboost_system
all: server asyncclient
server: server.o
$(CXX) $(LIBS) server.o -o server
asyncclient: asyncclient.o
$(CXX) $(LIBS) asyncclient.o -o asyncclient
server.o: server.cpp
$(CXX) -c server.cpp
asyncclient.o: asyncclient.cpp
$(CXX) -c asyncclient.cpp
server.cpp
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
using boost::asio::ip::tcp;
char teststr[]="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n";
void session(tcp::socket* sock)
{
boost::array<char, 102> buf;// 102 == sizeof(teststr)
int i=0;
try
{
for (;;)
{
std::cout<<i++<<std::endl;
boost::system::error_code error;
size_t length = boost::asio::read(*sock, boost::asio::buffer(buf), error);
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
if(strcmp(buf.data(), teststr)!=0)
{
std::cerr<<"error"<<std::endl;
std::cerr<<" buf.data() = "<<
std::string(buf.data(), buf.size())<<std::endl;
return;
}
}
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
}
int main()
{
std::cerr<<"sizeof(teststr) = "<<sizeof(teststr)<<std::endl;//DEBUG
boost::asio::io_service ios;
tcp::acceptor a(ios, tcp::endpoint(tcp::v4(), 41000));
tcp::socket sock(ios);
a.accept(sock);
boost::thread t(boost::bind(session, &sock));
t.join();
}
asyncclient.cpp
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
using boost::asio::ip::tcp;
char teststr[]="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n";
void handle_write(size_t num_bytes, boost::system::error_code e)
{
static int i=0;
if(!e)
{
std::cout<<i++<<std::endl;
}
else
{
std::cout<<"Error: "<<e.message()<<std::endl;
exit(1);
}
}
int main()
{
boost::asio::io_service ios;
tcp::resolver r(ios);
tcp::resolver::query q(tcp::v4(), "127.0.0.1", "41000");
tcp::resolver::iterator it = r.resolve(q);
tcp::socket sock(ios);
boost::asio::connect(sock, it);
boost::thread t(boost::bind(&boost::asio::io_service::run,&ios));
try
{
for(;;)
{
boost::asio::async_write(sock, boost::asio::buffer(teststr,102),
boost::bind(&handle_write,
boost::asio::placeholders::bytes_transferred,
boost::asio::placeholders::error));
}
}
catch(std::exception& e)
{
std::cout<<"Exception: "<<e.what()<<std::endl;
}
t.join();
}
答案 0 :(得分:2)
问题来自以下for循环:
for(;;)
{
boost::asio::async_write(sock, boost::asio::buffer(teststr,102),
boost::bind(&handle_write,
boost::asio::placeholders::bytes_transferred,
boost::asio::placeholders::error));
}
async_write操作可以在完成之前开始
以前的async_write是不允许的。
参考: async_write
正确的方法是消除for循环并调用async_write 在handle_write函数中:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
using boost::asio::ip::tcp;
char teststr[]="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n";
void handle_write(tcp::socket* sock, size_t num_bytes, boost::system::error_code e)
{
static int i=0;
if(!e)
{
std::cout<<i++<<std::endl;
boost::asio::async_write(*sock, boost::asio::buffer(teststr,102),
boost::bind(&handle_write, sock,
boost::asio::placeholders::bytes_transferred,
boost::asio::placeholders::error));
}
else
{
std::cout<<"Error: "<<e.message()<<std::endl;
exit(1);
}
}
int main()
{
boost::asio::io_service ios;
tcp::resolver r(ios);
tcp::resolver::query q(tcp::v4(), "127.0.0.1", "41000");
tcp::resolver::iterator it = r.resolve(q);
tcp::socket sock(ios);
boost::asio::connect(sock, it);
boost::thread t(boost::bind(&boost::asio::io_service::run,&ios));
boost::asio::async_write(sock, boost::asio::buffer(teststr,102),
boost::bind(&handle_write, &sock,
boost::asio::placeholders::bytes_transferred,
boost::asio::placeholders::error));
t.join();
}