boost:asio网络库初学之echo服务器客户端实现

时间:2022-09-08 23:26:42

为什么想起来学网络库呢

前一阵在网上看到这么一段话

select 实在是太慢了.

在这种背景下, IBM 老大哥带领着MS老弟先搞了 IOCP . 然而开源的人有开源的做法, 在 NIH 综合症的影响下, BSD 的人敢为天下所不齿, 发明了 Kqueue. 同样在 NIH 综合症影响下, Linux 的一群 M* 的猴子捣鼓出了 epoll.

分裂, 让人头疼.

于是程序员们急需一个上天入地无所不能的法宝的法宝, 把这3家法宝给统御起来。

实在太符合我的心情了,我就很需要这样一个法宝,让自己舒服一点。因为是macos系统,类Unix,在服务器开发方面,linux有的基本都有,差不多是一致的,但就是没有Epoll!!!,这就有些麻烦了,上一次写网关服务器时候,开发过程是这样的:
用sublime远程连接云服务器,
再用终端ssh运行调试,
就这样循环往复,再加上还没有补全,适应了xcode的舒服,所以痛苦ing。

说重点,为什么选择asio呢

1.asio属于boost的一部分,有可能被加入c++标准库,其代码质量稳定性及可靠性已不言而喻。
2.还是c++的原因,其源码使用了大多c++11特性,想在对其源码的学习过程中,对自己的c++知识进行一次加深和巩固
3.其主要针对于异步Proactor模式,而此模式相比较Reactor模式,学习难度稍高,所以想借着学习库使用的同时,能对其源码进行学习,提高事件驱动编程的能力。
4.当然是跨平台了。

代码

客户端

//
// main.cpp
// AsioClient
//
// Created by shiyi on 2016/12/10.
// Copyright © 2016年 shiyi. All rights reserved.
//

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

using namespace boost;

int main(int argc, const char * argv[]) {

asio::io_service service;//创建调度器
asio::ip::tcp::socket sock(service);//创建socket
asio::ip::tcp::endpoint ep(asio::ip::address::from_string("127.0.0.1"), 6666);//创建目标地址对象
//异步连接
sock.async_connect(ep, [](const boost::system::error_code &error){
if(error)
{
std::cout << error.message() << std::endl;
return;
}
std::cout << "connect succeed" << std::endl;
});

//如果不进行run调用的话,程序会直接结束,所以这里会等待async_connect结束,
//因此上面connect同步还是异步其实是一样的
service.run();

char data[512];
boost::system::error_code ec;
size_t len;

while(true)
{
std::cin >> data;

//发送 如果不传入 ec(error_code)参数,则出错时会抛出异常,此时可以用try-catch进行捕获,如果也没捕获,程序会直接终止
len = sock.write_some(asio::buffer(data), ec);
if(ec)
{
std::cout << boost::system::system_error(ec).what() << std::endl;
break;
}

//接收
len = sock.read_some(asio::buffer(data), ec);
if(ec)
{
std::cout << boost::system::system_error(ec).what() << std::endl;
break;
}

std::cout << data << std::endl;

}

return 0;
}

服务端

//
// main.cpp
// AsioServer
//
// Created by shiyi on 2016/12/10.
// Copyright © 2016年 shiyi. All rights reserved.
//

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

using namespace boost;

using socket_ptr = boost::shared_ptr<asio::ip::tcp::socket>;//包装socket类型的智能指针

void client_session(socket_ptr sock)
{

auto ep = sock->local_endpoint();
std::cout<<ep.address().to_string()<<"连接"<<std::endl;

char data[512];
boost::system::error_code ec;
size_t len;

while(true)
{
len = sock->read_some(asio::buffer(data), ec);
if(ec)
{
std::cout << boost::system::system_error(ec).what() << std::endl;
break;
}

len = sock->write_some(asio::buffer(data), ec);
if(ec)
{
std::cout << boost::system::system_error(ec).what() << std::endl;
break;
}
}

std::cout<<ep.address().to_string()<<"关闭"<<std::endl;

}

int main(int argc, const char * argv[]) {

asio::io_service service;//创建调度器
asio::ip::tcp::endpoint ep(asio::ip::address::from_string("127.0.0.1"), 6666);
asio::ip::tcp::acceptor apt(service, ep);//创建连接器

while(true)
{
socket_ptr sock(new asio::ip::tcp::socket(service));
apt.accept(*sock);//接收新的连接
boost::thread(boost::bind(client_session, sock));//开辟线程去处理该连接上的事务
}

}

运行结果

客户端

boost:asio网络库初学之echo服务器客户端实现

服务端

boost:asio网络库初学之echo服务器客户端实现