asio学习笔记3

asio学习笔记3

是时候写点跟网络相关的东西了。

asio支持同步和异步的网络操作,而且可以混用。可能有人会吐槽我之前为啥只写异步的东西,因为同步的话其实就只直接调用函数..那样的话跟asio一点关系都没有了我还写啥。不过网络方面的函数到时可以一写,不过这样就是放弃了asio的异步功能。

对于异步和同步的优缺点,其实我自己也说不太清楚,毕竟也是刚接触异步不久,也不好乱说,所以目前就只管学会怎么用,但是大多数人都是对同步的操作比较熟悉,所以这里还是先写一下asio进行同步的网络操作的方法。

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

void session(boost::asio::ip::tcp::socket* sock)
{
    std::cout << "有客户端连接" << std::endl;

    char data[1024];

    for (;;)
    {
        boost::system::error_code error;
        size_t length = sock->read_some(boost::asio::buffer(data), error);
        if (error == boost::asio::error::eof)
            break; // Connection closed cleanly by peer.
        else if (error)
        {
            std::cout << "read_some发生错误:" << error.message() << std::endl; // Some other error.
            break;
        }

        boost::asio::write(*sock, boost::asio::buffer(data, length),error);
        if (error)
        {
            std::cout << "write发生错误:" << error.message() << std::endl;
            break;
        }
    }

    delete sock;

    std::cout << "完事走掉了" << std::endl;
}

int main(int argc, char* argv[])
{
    boost::asio::io_service ios;
    boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(),1234);

    boost::asio::ip::tcp::acceptor acceptor(ios, endpoint);

    for (;;)
    {
        boost::asio::ip::tcp::socket* sock = new boost::asio::ip::tcp::socket(ios);
        acceptor.accept(*sock);

        boost::thread(&session, sock).detach();
    }

    return 0;
}

看过asio自带的example的童鞋肯定能看出来我这是抄袭的example里面的echo server然后改了下 //馆长笑

功能呢就是在本地监听1234端口,有客人来了就从客人那里接收数据然后还给他,如下图:

20140218103345.jpg

输入什么字母就返回什么字母。

接下来就说明一下每个函数的作用..这里要吐槽一下asio的文档,什么都是寥寥几句话,说的不清不楚的,实在是让我等初学者抓狂。不过好在asio有优良的层次结构和接口,多看看示例写写代码还是比较容易理解的,我一直坚持用完整的命名空间而不用using namespace,就是为了看起来结构层次分明,不过坏处就是代码看起来好长啊啊啊。

boost::asio::io_service ios;这个大家都知道是啥了,但是还是得说一下,虽然在同步的程序里面这玩意意义不大,但是还是必须要有的,如果你确定io_service里面没有要执行的异步任务,可以不用调用ios.run(),即使是调用了也会立即返回,如果不确定的话还是调用一下ios.stopped()确认一下或者直接调用一下run函数确定的吧一步任务也都做完。

boost::asio::ip::tcp::endpoint表示一个tcp的endpoint(我不知道这个endpoint该怎么翻译好..)。asio中用一个endpoint来表示一个节点,因为asio不只是支持一种协议,每种协议都有个endpoint来表示一个节点,tpc协议的一个节点的标识就是IP地址和端口号,有了IP地址和端口号就能找到这个节点,所以endpoint的初始化需要一个IP地址和一个端口号。这里因为要监听本地网卡上的所有的IP地址,所以就用了boost::asio::ip::tcp::v4(),不需要多说,看一下这个函数的实现就知道是什么意思了:

20140218103637.jpg

后面的1234自然就是端口号了。如果你想从一个字符串转换成endpoint也可以这么写:

boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string(std::string("127.0.0.1")), 1234);

boost::asio::ip::address::from_string()函数可以从字符串里面解析得到一个IP地址,他可以自动检测你输入的字符串是IPv4还是v6的。如果自己确定是v4还是v6,可以明确地用boost::asio::ip::address_v4::from_string()或者boost::asio::ip::address_6::from_string()。

有了endpoint了,我们就可以继续往下搞了,如果这个endpoint是我们自己,我们可以在这个endpoint上进行监听,等待别人来进行连接,如果是一个远程的endpoint,我们可以连接这个endpoint(不过好像asio中很少用endpoint来进行连接,用什么等后面写连接的client的时候说)。这里我们是要做server,肯定就是要在这个endpoint上进行监听。

asio把原来的socket的bind、listen、accept之类的操作都封装成了一个类boost::asio::ip::tcp::acceptor,把io_service 和endpoint传给他创建一个acceptor,然后调用accept成员函数就可以等待客户端的连接了。accept函数需要一个boost::asio::ip::tcp::socket,这个就是与该客户端连接的socket句柄,后续与该客户端的通讯都需要他。因为这个类不准拷贝,为了防止他析构只能new出来了,在不用的时候自己delete。

接到一个客户端的连接就开一个线程与他通信,主线程继续accept,同步网络通讯的典型做法,不废话了,看session函数里面的操作。

也很简单,从客户端那里读取数据,然后原封不动的写回去。这里要注意下read_some和read的区别,read_some是读取到一段数据就返回,不管读取的大小是否已经达到用户提供的缓冲区大小,什么时候返回跟tcp协议和操作系统的实现有关,这点我也不太了解,就不乱说了;read则是一直读取直到读取到用户指定的大小然后才返回,没有读取完是不会返回的;相同原理的还有write_some和write。不过我有一点不太理解的是read_some和write_some是boost::asio::ip::tcp::socket的成员函数,而read和write则是boost::asio命名空间下的独立的函数,希望有高手指点下。

今天就写这些了,明天继续。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值