一、问题点
在测试合宙CAT1模块TCP socket功能的时候,经常会遇到这样的问题: 已经建立了socket链接了, 开始发送数据正常,十几分钟不发任何数据,再发数据的时候提示发送成功,但是服务器侧未收到任何数据.
二、问题原因
cat1模块不是直接跟服务器连接的,而是通过NAT(即网络地址转换)与服务器连接。
一个会话建立后会在NAT设备上建立一个关联表,在会话静默的这段时间,NAT网关会进行老化操作。这是任何一个NAT网关必须做的事情,因为IP和端口资源有限,通信的需求无限,所以必须在会话结束后回收资源。
NAT会维护一个映射表,这个映射表会定时检查,如果10分钟内这路socket跟服务器没任何数据往来,就会回收这路的地址,10分钟后应用上再发数据就找不到路由地址了;如果10分钟内有数据更新,计时器会重新置为10分钟。
如果10分钟内这路socket跟服务器没任何数据往来,就会回收这路的地址,10分钟后应用上再发数据就找不到路由地址了—— 这个就是发送数据提示成功,服务器却收不到任何数据的原因。
三、解决之道
合宙AT命令版本固件的cat1模块解决这个问题的方式有两种:应用层发心跳包以及TCP保活探针的方式,具体在我另外一个帖子里有描述:http://doc.openluat.com/article/1396/0 ,这里就不再赘述。
本文着重介绍合宙Lua版本cat1模块如何维持socket连接不掉线。Lua也是这两种方法:
1) 在应用层发心跳包数据
这种方式模块会在应用层发送明文数据,以维持socket链接不掉线
合宙提供的上层软件中的\demo\socket\sync\sendWaitRecv\longConnection 示例支持应用层心跳包的发送(见socketOutMsg.lua脚本):
第一步: 建立socket客户端:
socketClient=socket.tcp()
第二步: 连接服务器
socketClient:connect(“mydomain.aa.bbb”,”12345″)
注:mydomain.aa.bbb为服务器地址和12345为端口号, 因为仅为示例,所以皆为虚构.
第三步: 发送数据
socketClient:send(data)
详细内容请看该示例。
上层软件下载地址为: http://doc.openluat.com/article/1334/0
2)采用保活探针方式
这种方式是TCP协议层实现的,只适用于TCP链接。这种实现方式不会对应用层的数据产生任何影响,应用层也看不到心跳包的内容。
这种实现方式叫做TCP保活探针(TCP Keep-Alive Probe),是用socket的属性参数设置socketcore.sock_setopt()这个API来实现的。
关于这个API的说明如下:
以下代码示例如何实现TCP保活探针:
if socket.isReady() then
--创建一个socket tcp客户端
local socketClient = socket.tcp()
--阻塞执行socket connect动作,直至成功
local result,id = socketClient:connect("mydomain.aa.bbb","12345")
if result then
log.info("socketClient.id = ",id)
--开启保活功能
socketcore.sock_setopt(id,socketcore.SOL_SOCKET, socketcore.SO_KEEPALIVE,1)
--在300秒内,链接上无任何数据交互,则发送初始保活探针
socketcore.sock_setopt(id,socketcore.IPPROTO_TCP, socketcore.TCP_KEEPIDLE,300)
--如果保活探针发送失败,60s再次重传
socketcore.sock_setopt(id,socketcore.IPPROTO_TCP, socketcore.TCP_KEEPINTVL,60)
--保活探针的最大重传数量为3
socketcore.sock_setopt(id,socketcore.IPPROTO_TCP, socketcore.TCP_KEEPCNT,3)
end
end
做完这些设置后,TCP socket链接就能一直保持不掉线。