移动平台下的Socket几个问题

简介: 在页游时代,使用Flash ActionScript 3.0进行开发,as3提供比较简单和健全的socket API。到了手游时代,基于tcp的socket编程遇到了一些棘手的问题。通常情况下手游都要支持至少二大主流平台:Android、IOS,二者共存,暂时没有迹象表现哪一方会没落。

在页游时代,使用Flash ActionScript 3.0进行开发,as3提供比较简单和健全的socket API。到了手游时代,基于tcp的socket编程遇到了一些棘手的问题。通常情况下手游都要支持至少二大主流平台:Android、IOS,二者共存,暂时没有迹象表现哪一方会没落。

 

页游跑在浏览器里,所有的连接成功、失败等操作,都可以通过addEventListener进行监听,很方便,一般也不存在频繁掉线的情况。而手游,因为手机的便携性决定了它的移动性,既然是可移动的那就会一定会面临网络不稳定的情况。

 

client与server通信如果使用TCP逻辑会比较简单一些,但存在一些问题,这个问题在移动平台下暴露的比较明显。QQ客户端使用的是UDP而非TCP,主要原因是因为网络的不稳定性。而TCP和UDP主要区别是什么呢?其实就是长连接与短连接的区别

 

长连接是比较消耗资源的,但是通常情况下,一方断了另一方会较为及时的收到消息,业务逻辑上是比较简单和及时的。

 

基于TCP的Socket网络编程,如果想跨平台,通常都使用C/C++进行封装,这样代码层面至少是统一了。但移动设备上面临的主要问题是频繁的掉线,Android好一点,IOS其实是比较麻烦的。下面列一下在Android、IOS设备上HOME、电源键对网络的影响:

 

平台 Home键切后(网络状态) 电源键(网络状态)
Android Y Y
IOS Y N

其它的2G/3G/4G/Wifi之间的相互切换,也是比较麻烦,必须要重连了(因为客户端的IP已经发生变化了)。

 

电源键按下时,IOS就锁屏了。Socket就断掉了,但Server端并不会收到Client掉线。问题来了,不是说TCP是长连接吗,我一端掉了那另一端应该收到断开的消息啊,嗯,理论上是这样子的,协议也是这么规定的,但要先注意这样一个问题:

TCP连接使用的是三次握手

TCP断开使用的是四次握手

连接使用三次握手,这个不多说了,主要原因是为了保证二端都能确认连接已经建立(SYN、ACK)。而断开为什么是四次?因为socket是双工(双向通信),相当于存在二条通讯的线路,一条用于接收,一条用于发送。一方主动关闭时(写通道被关闭了,但此时读通道还是正常的),它会发送FIN,另一端收到时会响应FIN+1(表示我收到你的关闭请求啦~),然后另一端处理完自己的逻辑后,告诉发起请求关闭的一方,我同意了你的关闭请求(不会再向你发送数据啦~),此时发起关闭的一方的读通道才是正常被关闭了。发起请求关闭的一方会在2MSL(报文最长生命周期的两倍 Maximum Segment Lifetime)后释放掉它所占用的端口(连接记录此时才会被清除)。

 

所以,你会发现哇,原来关闭也是需要确认的。假设服务器突然断电了,客户端是不知道服务器端已经无法连接了的,还会认为可以发送数据给服务器端。通常都是使用心跳包进行检测来双方的连接是否还存在。

 

我尝试过在cocos2dx使用libuv来实现网络通信,感觉异步写起来确实过于繁琐。libuv采用异步回调的写法,所有的回调函数必须是static的。通常一款游戏是有二个socket长连接的:游戏主逻辑、聊天服务器,好在libuv支持回调参数里“夹带自定义参数”,倒也问题不大。不过我遇到一件奇葩的事情是,在三星GTI9000 Android 2.3.6系统上,将游戏切入后台,网络状态由2G变成wifi,不回调socket,调用发送之后也没有触发关闭回调方法,其它能借用到的Android设备都测试过,没什么问题了。wifi切到2G/3G,后台切换至前台后立马触发关闭的回调函数。

 

后端处理是这样的,建立socket时会随机生成一个密钥串,当客户端断开连接时,拿这个密钥串向服务器进行验证,但是服务器验证时有个特殊的判定,如果请求生成密钥串的客户端IP与重连时的客户端IP不一致,则认为是非法请求。也就是说2G切换至WIFI时,IP变了,服务器其实是直接将连接断开了,但为什么没触发关闭的回调函数,这个或许是那个Android系统版本的bug吧

 

后来想的办法有二个:

1、针对Android平台,记录连接时的网络类型,然后切换至前台时再获取网络类型,如果发现二次的网络类型不一致就提示需要重新登录游戏了;

2、记录建立连接时的IP地址,当切换至前台再获取IP,如果这二个IP不致,也认为是需要重登录游戏了,因为无论你拿什么密钥串都将无法再登录游戏,服务器认为这个请求是非法的;

 

技术改变世界! --狂诗绝剑
目录
相关文章
|
存储 网络协议 Unix
iOS - Socket 网络套接字
1、Socket 套接字 所谓 Socket,通常称为 “套接字”,网络应用程序通过套接字向网络发送请求或者应答网络请求。Socket 通常用于描述 IP 地址和端口,是应⽤层与 TCP/IP 协议族通信的中间软件抽象层,它是一组接口,是一个通信链的句柄,可以用来实现不同虚拟机或者不同计算机之间的通信。
1883 0
|
Ubuntu TensorFlow 算法框架/工具
基于 socket 的即时通讯文件传输聊天软件
基于 socket 的即时通讯文件传输聊天软件
103 0
基于 socket 的即时通讯文件传输聊天软件
|
Android开发
|
网络协议 Unix API
《UNIX网络编程 卷1:套接字联网API(第3版)》——导读
本书想达到的目标是向大家提供网络编程指导。这些内容不仅适用于专业人士,也适用于初学者;不仅适用于维护已有代码,也适用于开发新的网络应用程序;此外,还适用于那些只是想了解一下自己系统中网络组件的工作原理的人。
1378 0
|
网络协议 Unix API
《UNIX网络编程 卷1:套接字联网API(第3版)》——2.14 小结
SCTP使用四路握手建立关联;使用三分组交换序列终止关联。当一个SCTP关联被建立时,它从CLOSED状态转换到ESTABLISHED状态;当该关联被终止时,它又回到CLOSED状态。一个SCTP关联可处于8种状态之一,其状态转换图给出从一种状态转换到另一种状态的规则。
1435 0
|
网络协议 Unix API
《UNIX网络编程 卷1:套接字联网API(第3版)》——1.12 小结
我们的客户程序与IPv4协议相关,我们于是把它修改成使用IPv6,但这样做却只是给了我们另外一个协议相关的程序。我们将在第11章中开发一些可用来编写协议无关代码的函数,这在因特网开始使用IPv6后会变得非常重要。
1619 0
|
网络协议 Unix API
《UNIX网络编程 卷1:套接字联网API(第3版)》——8.16 小结
UDP套接字可能产生异步错误,它们是在分组发送完一段时间后才报告的错误。TCP套接字总是给应用进程报告这些错误,但是UDP套接字必须已连接才能接收这些错误。
1476 0