19.1 Boost Asio 同步TCP通信

在同步模式下,程序发起I/O操作时,调用相应的同步I/O函数将操作添加到io_service中,该请求被添加到io_service的请求队列中等待处理。然后,io_service就会不断地从队列中取出请求,并将请求传递给操作系统进行处理,直到该请求被处理完成。程序在此期间会一直处于阻塞等待的状态,直到操作完成或者因为某种原因导致操作失败。

I/O操作在操作系统完成后,操作系统会通知io_serviceio_service接收到通知后会再次进入循环,将操作结果发送回程序进行处理。程序会在此等待操作结果,并在io_service返回结果时继续执行其余代码。

同步网络通信的实现原理与原生Socket套接字通信原理保持一致,只是在ASIO模型中,需要定义一个io_service对象,在服务端环境下,我们通过ip::tcp::acceptor来指定服务端地址与端口信息,使用ip::tcp::socket创建一个套接字,通过acceptor.accept(socket)则可用于同步等待一个套接字的链接,当有新套接字连入后,我们可以使用socket.write_some函数向客户端发送一段消息。

#include <iostream>
#include <boost/asio.hpp>

using namespace boost::asio;

int main(int argc, char* argv[])
{
io_service io;
ip::tcp::acceptor acceptor(io, ip::tcp::endpoint(ip::tcp::v4(), 6666));

while (1)
{
// 创建 socket 对象
ip::tcp::socket socket(io);

// 等待客户端连接
acceptor.accept(socket);

// 显示客户端IP
std::cout << "本机地址: " << socket.local_endpoint().address() << std::endl;
std::cout << "客户端地址: " << socket.remote_endpoint().address() << std::endl;

// 向客户端发送 hello lyshark
boost::system::error_code error;
socket.write_some(buffer("hello lyshark"), error);

// 如果出错,输出错误提示
if (error)
{
std::cout << boost::system::system_error(error).what() << std::endl;
break;
}
}
system("pause");
return 0;
}

对于客户端而言我们可以使用tcp::endpoint创建一个链接端点,当初始化结构后就可以使用socket.connect函数连接到这个端点上,当链接被建立后,则客户端就可以使用socket.read_some函数接收服务端传递过来的消息,此处读者需要注意接受的消息需要使用boost::array存储,当接收到消息后就可以使用buffer.data()方法打印出该缓冲区内的具体内容。

#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>

using namespace std;
using boost::asio::ip::tcp;

int main(int argc, char* argv[])
{
try
{
// 定义Socket对象
boost::asio::io_service io;
tcp::socket socket(io);

// 尝试连接服务器
tcp::endpoint end_point(boost::asio::ip::address::from_string("127.0.0.1"), 6666);
socket.connect(end_point);

while (1)
{
boost::array<char, 1024> buffer = { 0 };
boost::system::error_code error;

// 接受数据并存入buffer
size_t len = socket.read_some(boost::asio::buffer(buffer), error);

// 判断是否出错
if (error == boost::asio::error::eof)
break;
else if (error)
throw boost::system::system_error(error);

std::cout << "接收到数据: " << buffer.data() << std::endl;
}
}
catch (std::exception& e)
{
cout << e.what() << endl;
}
system("pause");
return 0;
}

读者可自行编译并运行上述服务端与客户端程序,当运行后即可看到如下图所示的输出效果;