c++异网连续异步发送数据
c++异网连续异步发送数据
·
原文
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];
双队<串>写消息_;
};
更多推荐
已为社区贡献7条内容
所有评论(0)