Boost.Asio基础(四)

来源:互联网 发布:广电机顶盒破解网络 编辑:程序博客网 时间:2024/05/16 10:36

TCP vs UDP vs ICMP

如前所述,对于所有类型的socket,并不是都有同样的成员函数。下面的表格列出了3个socket中存在的成员函数:

名称 TCP UDP ICMP async_read_some Yes - - async_receive_from - Yes Yes async_write_some Yes - - async_send_to - Yes Yes read_some Yes - - receive_rom - Yes Yes write_some Yes - - send_to - Yes Yes

杂项函数

还有其他的一些函数用户处理连接或者输入/输出:

  • local_endpoint():返回socket的本地连接地址。
  • remote_endpoint():返回socket连接到的远程地址。
  • native_handle():返回原始socket的句柄。只在你确实需要不经过Boost.Asio来操作原始socket时使用。
  • non_blocking():返回socket是否是非阻塞的。
  • native_non_blocking():同non_blocking()一样的函数,但是这个是在你用native_handle()获取原始句柄之后,还想查询是否非阻塞时使用。
  • at_mark():返回true,当socket读取关于OOB数据的时候。极少用。

其他注意事项

最后需要注意的是,socket是不能复制的,它的复制构造函数是不可访问的:

ip::tcp::socket s1(service), s2(serviec);s1 = s2;  //编译错误ip::socket::socket s3(s1); //编译错误

这样可以避免很多麻烦的问题,加入允许复制,那么会出现,两个socket持有一个相同的原始socket,那么到底谁对资源负责呢,谁在合适的时候释放它呢,很麻烦。所以Boost.Asio不允许复制socket。假如你真要复制socket,直接使用智能指针就行了:

typedef boost::shared_ptr<ip::tcp::socket> socket_ptr;socket_ptr sock1(new ip::tcp::socket(service));socket_ptr sock2(sock1);socket_ptr sock3;sock3 = sock1; // 这是可以的

Socket缓冲区

当向socket读取和写入数据的时候,你需要使用到缓冲区,它负责保存输入和输出的数据。缓冲区中内存的生存期要比I/O操作要长;你必须要保证,在I/O操作最终完成之前,这部分内存不会被释放掉。
这对同步操作来说,是很容易的。毫无疑问,缓冲区的生存期要比receive和send的要长:

char buff[512];...sock.receive(buffer(buff));strcpy(buff, "ok\n");sock.send(buffer(buff));

但对于异步操作来说,就不是那么简单了,下面是示例代码:

//非常不好的代码void on_read(const boost::system::error_code& err, std::size_t read_bytes){...}void func(){    char buff[512];    sock.async_receive(buffer(buff), on_read);}

在调用async_receive之后,buff就脱离了作用域,这部分内存就被释放掉了。也就是说我们把需要的数据拷贝到了我们不在拥有的内存上去了,这部分内存很可能被释放,然后重新分配给其他一些代码使用,毫无疑问,内存腐烂了。
有多种方法可以解决上面的问题:

  • 使用全局缓冲区
  • 创建缓冲区,并在操作完成后销毁
  • 用一个连接对象来持有socket,以及socket的额外的数据,比如buffer(s)

第一个解决方法并不好,我们都知道全局变量是很不好的编码习惯。
第二种方法,我们使用智能指针,当操作完成后,缓冲区能够自动删除:

struct shared_buffer{    boost::shared_array<char> buff;    int size;    shared_buffer(size_t size) : buff(new char[size]), size(size)    {    }    mutable_buffers_1 asio_buff() const    {        return buffer(buff.get(), size);    }};//当脱离了on_read的作用域之后,async_receive也返回了,shared_buffer就被自动销毁了void on_read(shared_buffer, const boost::system::error_code& err,    std::size_t read_bytes){}...shared_buffer buff(512);sock.async_receive(buff.asio_buff(), boost::bind(on_read, buff, _1, _2));

第三种方法,就是用一个单独的对象来管理socket和socket相关的数据,比如buffers对象。这是比较好的解决方案,但是稍显复杂,本章的最后来讨论此方法。

0 0