原文
asio的异步接口能连续调用吗?比如可以这样调用异步写接口吗?

向量<>消息{"你好","发送许多"};(&消息:消息){
    异网::异步写(套接字_,
    异网::缓冲(消息.数据(),消息.长度()),
    [](错误码 ec,大小型 长度){(ec)关闭();
    })
}

asio不允许连续调用异步接口,必须在上次调用完成之后才能再调用异步接口.
如何连续发送消息呢?
一个简单思路是client内部搞一个发送队列,用户连续发送数据丢到队列中,然后再异步发送队列中的数据.chat_client的例子中展示了如何使用队列实现连续发送消息:

空 写(常 串&消息)
  {
      极 正在写=!写消息_.空的();
      写消息_.压后(消息);(!正在写)
      {
          干写();
      }
  }

  空 干写()
  {
    异网::异步写(套接字_,
      异网::缓冲(写消息_.().数据(),
        写消息_.().长度()),
      [](错误码 ec,大小型/*长度*/)
      {(!ec)
        {
          写消息_.弹前();(!写消息_.空的())
          {
            干写();
          }
        }{
          套接字_.关闭();
        }
      });
  }

  双队<>写消息_;

干写展示了异步调用链,每次异步写时从队列头拿数据去发送,发送完成回调里移除头部已发送完成数据,接着再检查队列中是否还有数据,如果有就继续调用异步发送接口发送,直到队列为空.

这里一个小问题需要注意,队列中有很多数据时,正在递归异步发送数据时,如何保证外部用户不会调用异步写接口呢?
外面用户不知道是否已发送完成内部队列数据,如果这时用户在外面调用了异步写接口,那就相当于连续调用了异步接口,产生未定义行为(两次缓冲区交叠).这时应在用户发送接口中判断队列是否为空,如果不为空就放到队列中并返回,如果队列为空,就调用异步发送数据的接口.所以队列是否为空可判断能否调用异步写接口.

这个write_msgs_,还有线程安全问题.因为用户线程和io_context线程都可能访问这个write_msgs_.还要修改一下来保证线程安全.


#包含<io流>
#包含<异网.h++>
#包含<双队>
#包含<>
#包含<向量>
#包含<互斥锁>

用 异网::ip::传控;

类 聊天客户
{:
  聊天客户(异网::io环境&io环境,
    常 传控::解析器::结果类型&端点)
    :io环境_(io环境),
    套接字_(io环境)
  {
    干连接(端点);
  }

  空 写(常 串&消息)
  {
      独锁 锁(写互斥锁_);
      极 正在写=!写消息_.空的();
      写消息_.压后(消息);(!正在写)
      {
          干写();
      }
  }

  空 关闭()
  {
    异网::提交(io环境_,[](){套接字_.关闭();});
  }

  空 跑一(){
      io环境_.跑一();
  }:
  空 干连接(常 传控::解析器::结果类型&端点)
  {
    异网::异步连接(套接字_,端点,[](错误码 ec,传控::端点){(!ec)干读();
      });
  }

  空 干读()
  {
    套接字_.异步读些(异网::缓冲(读消息_,512),
      [](错误码 ec,大小型 长度)
      {(!ec)
        {
          输出<<"接收消息:"<<(读消息_,长度)<<"\n";
          干读();
        }{
          套接字_.关闭();
        }
      });
  }

  空 干写()
  {
    异网::异步写(套接字_,
      异网::缓冲(写消息_.().数据(),
        写消息_.().长度()),
      [](错误码 ec,大小型/*长度*/)
      {(!ec)
        {
          独锁 锁(写互斥锁_);
          写消息_.弹前();(!写消息_.空的())
          {
            干写();
          }
        }{
          套接字_.关闭();
        }
      });
  }:
  异网::io环境&io环境_;
  传控::套接字 套接字_;
  符 读消息_[512];
  双队<>写消息_;
  互斥锁 写互斥锁_;//用互斥锁来锁定.
};

整 主(整 参个数,*参值[])
{{(参个数!=3)
        {
            c错误<<"使用:聊天客户<主机><端口>\n";1;
        }

        异网::io环境 io环境;

        传控::解析器 解析器(io环境);
        动 端点=解析器.解析(参值[1],参值[2]);
        聊天客户 c(io环境,端点);
        c.跑一();

        线程 t([&io环境](){io环境.();});

        向量<>向量{"你好","发送许多"};(&消息:向量){
            c.(消息);
        }

        t.合并();
        io环境.();
    }(异常&e)
    {
        c错误<<"异常:"<<e.什么()<<"\n";
    }0;
}

asio提供了strand,strand会保证并发调用异步接口的安全性,用strand就不用锁了,代码会更简单.

类 提交客户
{:
    提交客户(异网::io环境&io环境,
        常 传控::解析器::结果类型&端点)
        :io环境_(io环境),
        套接字_(io环境)
    {
        干连接(端点);
    }

    空 写(串 消息)
    {
        异网::提交(io环境_,
          [,消息=移动(消息)]()
          {
            极 正在写=!写消息_.空的();
            写消息_.压后(移动(消息));(!正在写)
            {
              干写();
            }
          });
    }

    空 关闭()
    {
        异网::提交(io环境_,[](){套接字_.关闭();});
    }

    空 跑一(){
        io环境_.跑一();
    }:
    空 干连接(常 传控::解析器::结果类型&端点)
    {
        异网::异步连接(套接字_,端点,
            [](错误码 ec,传控::端点)
            {(!ec)
                {
                    输出<<"连接好\n";
                    干读();
                }
            });
    }

    空 干读()
    {
        套接字_.异步读些(异网::缓冲(读消息_,512),
            [](错误码 ec,大小型 长度)
            {(!ec)
                {
                    输出<<"接收消息:"<<(读消息_,长度)<<"\n";
                    干读();
                }{
                    关闭();
                }
            });
    }

    空 干写()
    {
        异网::异步写(套接字_,
            异网::缓冲(写消息_.().数据(),
                写消息_.().长度()),
            [](错误码 ec,大小型/*长度*/)
            {(!ec)
                {
                    写消息_.弹前();(!写消息_.空的())
                    {
                        干写();
                    }
                }{
                    关闭();
                }
            });
    }:
    空 关闭()
    {
        异网::提交(io环境_,[]{(!套接字_.是打开()){;
            }
            异网::错误码 忽略误码;
            套接字_.关闭(传控::套接字::都关闭,忽略误码);
            套接字_.关闭(忽略误码);
            });
    }
    异网::io环境&io环境_;
    传控::套接字 套接字_;
    符 读消息_[512];
    双队<>写消息_;
};

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐