『boost』ASIO学习

boost::asio


一个不太懂TCP机制及其实现的网友上的ASIO帖子,跟帖中有“正解”,TCP中设计上的问题,得翻翻《tcpip详解》并结合平台实现

摘录几句对话:(看大家回复的内容,联想其出发点,等等有关交流的方式,是有趣的,但“泡”论坛这种还是浪费时间的。)

楼主:不说了,官方example\echo\async_tcp_echo_server.cpp
开2个客户端用telnet方式连上echo_server,长时间后关掉telnet后,echo_server竟然不会断开客户端?
而且在echo_server的机器上用netstat -ano -p tcp查看,服务端于客户端的连接还处于ESTABLISHED状态,这就是所谓的终极网络库?搞笑的吧!

游客甲:呵呵,别管什么库,掌握“机制”是最重要的。
如果因为存在某个库,而使你丧失了学习此技术之内部机制的可能,那么,我劝你还是不要先使用这个库为好。
就像这个asio,如果因为它的存在,而令你不再学习异步重叠I/O,那么,还是先不要使用这个库为好。

游客乙:asio当然在机制仅会支持TCP或UDP支持的feature,而TCP保活超时是半个小时以上,半个小时(或45分钟)后会产生一个“网络错误”,那个时候就asio就会给客户事件了。如果要建立商业级的服务器软件,仅仅依赖“传输层”的feature是远远不够的,你要自己做心跳来保活。
长连接服务器需要做心跳,在“问答式服务器”里做定时器就可以了。当你收到一个包,就对这个socket开始计时,如果再收到包就重新计时,如果超时,就自己产生一个事件以关掉socket。

ok,如果说asio建立在tcp协议栈上,那么保活超时之后,也要给调用者返回所谓的“网络错误”,事实上是并无任何返回(handle_read未触发),还是麻烦LS的兄台自己跑一下example那个例子,再来解答,哦可?
不要跟我讲应用层面要保证的机制,写server都会这样处理,现在问题关键是底层的所谓"终极神器"的asio,在socket keeplive超时后,并无任何异常触发并返回,你可明白?

你等了多长时间?

昨天晚上在公网机器上跑的server,然后在另外2个公网机器上开的telnet客户端,今天早上发现连接都没断很正常,然后把2个telnet关掉后,server没有任何hand_read()调用,无error_code,在netstat -ano -p tcp里面,还显示与2个telnet的连接处于ESTABLISHED已连接状态,其他的话我也不想多说了,谁不相信谁自己试下就知道了,无奈的asio,连最基本的保活机制都没检测。
server用的官方example代码,无任何改动。
我相信select/iocp都不可能出现这么低级的问题(同样的方法测试过)

“在netstat -ano -p tcp里面,还显示与2个telnet的连接处于ESTABLISHED已连接状态”,
呵呵,你想想看。 tcp协议栈认为这两个连接依然是ESTABLISHED,这跟asio有什么关系呢? 
select / iocp不用你本机的tcp协议栈吗?  
ESTABLISHED状态是协议栈决定的,还是asio抑或iocp决定的?

不知道你看清楚我的回答没?
"然后把2个telnet关掉后,server没有任何hand_read()调用,无error_code,在netstat -ano -p tcp里面,还显示与2个telnet的连接处于ESTABLISHED已连接状态"
随便做个c/s,c关掉后,我不信s与这个c的staus还是ESTABLISHED,说明什么问题?
说明c断开后,s并没有将和c连接的socket断开,asio也一样,也就是说asio的GCQS无返回 或 没出现错误。你想想这样正常吗?
还要怎样说?真是无语,你完全连问题都没看懂!

请翻开斯蒂文斯的卷1,182页,请仔细看看TCP状态变迁图。
当ESTABLISHED收到FIN,应转为CLOSE_WAIT状态,就是说,你的服务器的TCP协议栈并未受到远端(主动关闭端)发出的FIN。
这跟asio一点关系都没有,协议栈未收到FIN,套接口层当然不会得到事件。

算了,不跟你解释了,你自己试下官方那个例子就知道了!
在telnet连上server后:
1、很短时间内关闭telnet,此时server会调用handle_read,因为有error_code,所以自动delete this,一切正常;
2、很长时间后关闭telnet(我是过了1晚上,大概10-12小时),同样关闭telnet,此时server不会调用handle_read,更无error_code,可笑的是:server所在的机器上,server与这个已经关闭的telnet连接状态还是ESTABLISHED。
ps:其他的话不多说了,如果你们以为这样是正常的,asio也正常的,可以无视了。
LS的你也不用回帖了,你适合去看书。

看来你还是分不清运输层和套接口层甚至是asio所在的上层机制之间的区别,你应该看看书,补充这些知识,再来讨论综合性的问题吧。

另外如果服务端网络状态还是 ESTABLISHED, 那么这本身和asio无关
说明你虽然关闭了client端,但是client并没有正常发送fin,这种情况就是我们常说的异常断开。
那么通常你有两种方式处理:
1. Keep_alive  正常windows下2小时左右(另外windows下有WSAIoctl这个API来实现类似TCP层的保活,而linux下setsockopt有超时选项也可以用来实现tcp层保活)
2. 通过自己的上层协议发送心跳包等来保活

楼主提供的所有证据,不能证明telnet正常关闭了套节字。
楼主的意思是:
一:用telnet连上服务端,短时间内退出telnet,服务端正常;
二:用telnet连上服务端,长时间内退出telnet,服务端异常;
这两条不能证明异常是服务端设计有问题,还是telnet设计有问题。
对于上面第二点,你可以像4楼所说的,等长一点时间,比如1小时,看看asio会不会有网络断开的提示。
楼主没有理解4楼的“你等了多长时间”的意思,4楼的意思是,你断开telnet之后,等了多长时间,而不是你用telnet连接上服务端之后,等了多长时间。
如果在telnet退出之后,等了足够长的时间,比如1小时,asio检测到了网络断开,那说明你的telnet没有正常关闭套节字。


下面看一段boost::asio的daytime示例代码:注释来自于boost::asio::ip::tcp实现网络通信的小例子(转载)

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

using boost::asio::ip::tcp;//ASIO的TCP协议通过boost::asio::ip名 空间下的tcp类进行通信。

int main(int argc, char *argv[])
{
	try
	{
		boost::asio::io_service io_service;
		tcp::resolver resolver(io_service);
		//A resolver takes a query object and turns it into a list of endpoints. We construct a query using the name of the server, specified in argv[1], and the name of the service, in this case "daytime".
		tcp::resolver::query query("127.0.0.1"/* host */, "daytime"/* service name */);

		tcp::resolver::iterator endpoint_iterater = resolver.resolve(query);
		tcp::socket socket(io_service);
		boost::asio::connect(socket, endpoint_iterater);
		//or like this

		// 连接端点,这里使用了本机连接,可以修改IP地址测试远程连接
		//ip::tcp::endpoint ep(ip::address_v4::from_string("127.0.0.1"), 1000);
		//IP地址(address,address_v4,address_v6)、 端口号和协议版本组成一个端点(tcp:: endpoint)。用于在服务器端生成tcp::acceptor对 象,并在指定端口上等待连接;或者在客户端连接到指定地址的服务器上。
		//socket是 服务器与客户端通信的桥梁,连接成功后所有的读写都是通过socket对 象实现的,当socket析 构后,连接自动断 开。
		//socket.connect(ep,ec);

		for (;;)
		{
			boost::array<char, 128> buf;
			boost::system::error_code error;
			
			size_t len = socket.read_some(boost::asio::buffer(buf), error);
			if (error == boost::asio::error::eof)
			{
				break;
			}
			else if (error)
			{
				throw boost::system::error_code(error);
			}

			std::cout.write(buf.data(), len);
		}
	}
	catch (std::exception &e)
	{
		std::cerr << e.what() << std::endl;
	}
	
	return 0;
}

boost文档实在是详细!


再转两则,其他就靠自己写了。范例在这里:examples

Boost::asio范例分析 客户端

Boost::asio范例分析 服务端



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值