Ⅰ android推送SDK(9)-TCP网络问题
主目录见: Android高级进阶知识(这是总目录索引)
[written by 无心追求 ]
常
把Http和TCP连接服务做区分导致IM的TCP使用80端口连接进来的时候被误
识别成是一个Http请求,所以就对IM的TCP数据流(TLV格式)进行解析导
致报错返回了一个Http请求报错的网页的Html数据,具体返回的数据格式
客户端打印是:
以上是客户端TCP数据流read到100字节打印出来的数据,是一个Http请求
失败返回Http状态码为400的网页Html数据
以上是tcpmp抓包信息,从抓包信息中可以得知返回的数据确实是一个
Http请求失败的网页,对比客户端程序log打印是吻合的
式的数据,所以对read到的数据进行常规的TLV数据解析导致程序解析报错
(数组越界):
客户端发生数据解析报错之后会认为当前接收到的数据已经不正确,同时
也会认为后面接续读取的数据也将不正确,所以会把socket连接关闭重连
:
应该下调心跳周期,但是旧版(1.0.1Realease-1.0.6Realease版本)存在
不足,并没有对此做过滤处理,所以会不断的下调心跳
断线后会马上重连
接断开的域名和端口再次尝试重连,在重试重连失败的时候才会去切换域
名或者端口,而遇到这种情况,每次尝试重连TCP都能连接成功,连接成功
之后,数据解析失败又把TCP连接断开,然后再拿原来的域名和端口,再重
连,再断开,如此陷入死循环,无法切换域名或者端口,断线重连频率很
高:
TCP连接IM服务器gw.im.okii.com成功,连接端口为80
入的TCP数据为323个字节
的数据进行解析
srcPos=2 dst.length=121 dstPos=0 length=121表示数据解析报错,数组
越界
误的识别成Http短连接
不下调心跳间隔,避免心跳误下调,影响心跳探测的准确性
时间间隔递增重连,避免频繁的重连
一些常用的端口,例如8080,443,1000一下的端口等都不能使用,避免出
现类似的问题
和端口去再次连接IM服务器导致无法跳出这个域名和端口连接造成的异常
,如果客户端有成功切换域名或者端口,那么遇到上述情况会立即切换到
8000端口,次数连接就会恢复正常
有上传大数据的手表分析来看全部都恢复正常使用
111.44.228.186这个地址(正确的应该是106.75.86.52),而被误识别成
Http短链接,然后返回一个错误的网页html数据,然后客户端接收到数据
后解析报错,导致频繁的断线重连和心跳下调
跳误下调,重连频繁,与香港的原因类似
gw.im.okii.com本地dns解析出来的ip为111.44.228.186,由此确认是被劫
持了
客户端对接收到的TCP数据解析异常,数
组越界
客户端在数据解析异常后断线
连接断开后心跳下调
Ⅱ Android-Socket
由于二者不属于同一层面,所以本来是没有可比性的。但随着发展,默认的Http里封装了下面几层的使用,所以才会出现Socket & HTTP协议的对比:(主要是工作方式的不同):
Socket可理解为一种特殊的文件,在服务器和客户端各自维护一个文件,并使用SocketAPI函数对其进行文件操作。在建立连接打开后,可以向各自文件写入内容供对方读取或读取对方内容,通信结束时关闭文件。在UNIX哲学中“一切皆文件”,文件的操作模式基本为“打开-读写-关闭”三大步骤,Socket其实就是这个模式的一个实现。
创建socket的时候,也可以指定不同的参数创建不同的socket描述符,socket函数的三个参数分别为:
当我们调用socket创建一个socket时,返回的socket描述字它存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind()函数,否则就当调用connect()、listen()时系统会自动随机分配一个端口。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
函数的三个参数分别为:
如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。
TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就想TCP服务器发送了一个连接请求。TCP服务器监听到这个请求之后,就会调用accept()函数取接收请求,这样连接就建立好了。之后就可以开始网络I/O操作了,即类同于普通文件的读写I/O操作。
注意:accept的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept函数返回的是已连接的socket描述字。一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。
万事具备只欠东风,至此服务器与客户已经建立好连接了。可以调用网络I/O进行读写操作了,即实现了网咯中不同进程之间的通信!网络I/O操作有下面几组:
read()/write()
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendto()
我推荐使用recvmsg()/sendmsg()函数,这两个函数是最通用的I/O函数,实际上可以把上面的其它函数都替换成这两个函数。
从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。
总结:客户端的connect在三次握手的第二个次返回,而服务器端的accept在三次握手的第三次返回。
某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;
另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;
一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;
接收到这个FIN的源发送端TCP对它进行确认。
这样每个方向上都有一个FIN和ACK。
所谓短连接,即连接只保持在数据传输过程,请求发起,连接建立,数据返回,连接关闭。它适用于一些实时数据请求,配合轮询来进行新旧数据的更替。
https://github.com/nuisanceless/MySocketDemo
https://github.com/xuuhaoo/OkSocket
Ⅲ Android网络请求知识(三)授权,TCP/IP,HTTPS建立过程
由身份或持有的令牌确认享有的权限,登录过程实质上的目的也是为了确认权限。
Cookie是客户端给服务器用的,setCookie是服务器给客户端用的。cookie由服务器处理,客户端负责存储
客户端发送cookie:账户和密码
服务端收到后确认登录setCookie:sessionID=1,记下sessionID
客户端收到sessionID后记录,以后请求服务端带上对比记录下sessionID,说明已经登录
会话管理:登录状态,购物车
个性化:用户偏好,主题
Tracking:分析用户行为
XXS:跨脚本攻击,及使用javaScript拿到浏览器的cookie之后,发送到自己的网站,以这种方式来盗用用户Cookie。Server在发送Cookie时,敏感的Cookie加上HttpOnly,这样Cookie只能用于http请求,不能被JavaScript调用
XSRF:跨站请求伪造。Referer 从哪个网站跳转过来
两种方式:Basic和Bearer
首先第三方网站向授权网站申请第三方授权合作,拿到授权方颁发的client_id和client_secret(一般都是appid+appkey的方式)。
在这就过程中申请的client_secret是服务器持有的,安全起见不能给客户端,用服务端去和授权方获取用户信息,再传给客户端,包括④,⑤的请求过程也是需要加密的。这才是标准的授权过程。
有了access_token之后,就可以向授权方发送请求来获取用户信息
步骤分析就是上面的内容,这里把第4,6,8请求的参数分析一下
第④步参数:
response_type:指授权类型,必选,这里填固定值‘code’
client_id:指客户端id,必选,这里填在平台报备时获取的appid
redirect_uri:指重定向URI,可选
scope:指申请的权限范围,可选
state:指客户端当前状态,可选,若填了,则认证服务器会原样返回该值
第⑥步参数:
grant_type:指使用哪种授权模式,必选,这里填固定值‘authorization_code’
code:指从第⑤步获取的code,必选
redirect_uri:指重定向URI,必选,这个值需要和第④步中的redirect_uri保持一致
client_id:指客户端id,必选,这里填在平台报备时获取的appid
client_secret:指客户端密钥,必选,这里填在平台报备时获取的appkey
第⑧步参数:
access_token:指访问令牌,必选,这里填第⑦步获取的access_token
token_type:指令牌类型,必选,大小写不敏感,bearer类型 / mac类型
expires_in:指过期时间,单位秒,当其他地方已设置过期时间,此处可省略该参数
refresh_token:指更新令牌,可选,用即将过期token换取新token
scope:指权限范围,可选,第④步中若已申请过某权限,此处可省略该参数
我们在上面的第八步中会有refresh_token的参数,这个在实际操作中也比较常见
有时候我们在自己的项目中,将登陆和授权设计成类似OAuth2的过程,不过去掉Authorization code。登陆成功返回access_token,然后客户端再请求时,带上access_token。
我们常常会说到TCP/IP,那到底是什么呢。这就需要讲到网络分层模型。TCP在传输层,IP在网络层。那为什么需要分层?因为网络不稳定,导致需要重传的问题。为了提高传输效率我们就需要分块,在传输层中就会进行分块。TCP还有两个重要的内容就是三次握手,四次分手。
HTTPS 协议是由 HTTP 加上TLS/SSL协议构建的可进行加密传输、身份认证的网络协议,主要通过数字证书、加密算法、非对称密钥等技术完成互联网数据传输加密,实现互联网传输安全保护
1.客户端通过发送Client Hello报文开始SSL通信。报文中包含客户端支持的SSL的指定版本、加密组件列表(所使用的加密算法及密钥长度),客户端随机数,hash算法。
2.服务器可进行SSL通信时,会以Server Hello报文作为应答。和客户端一样,在报文中包含SSL版本以及加密组件,服务端随机数。服务器的加密组件内容是从接收到客户端加密组件内筛选出来的。
3.之后服务器发送Certificate报文。报文中包含公开密钥证书。一般实际有三层证书嵌套,其实像下面图二直接用根证书机构签名也是可以的,但是一般根证书机构比较忙,需要类似中介的证书机构来帮助。
4.最后服务器发送Server Hello Done报文通知客户端,最初阶段的SSL握手协商部分结束。
5.SSL第一次握手结束后,客户端以Client Key Exchange报文作为回应。报文中包含通信加密中使用的一种被称为Pre-master secret的随机密码串。该报文已用步骤3中的公开密钥进行加密。
6.接着客户端继续发送Change Cipher Spec报文。该报文会提示服务器,在此报文之后的通信会采用Pre-master secret密钥加密。
7.客户端发送Finished报文。该报文包含连接至今全部报文的整体校验值。这次握手协商是否能够成功,要以服务器是否能够正确解密报文作为判定标准。
8.服务器同样发送Change Cipher Spec报文。
9.服务器同样发送Finished报文。
10.服务器和客户端的Finished报文交换完毕之后,SSL连接就算建立完成。当然,通信会受到SSL的保护。从此处开始进行应用层协议的通信,即发送HTTP响应。
11.应用层协议通信,即发送HTTP响应。
12.最后由客户端断开连接。断开连接时,发送close_notify报文。这步之后再发送TCP FIN报文来关闭与TCP的通信。
利用客户端随机数,服务端随机数,per-master secret随机数生成master secret,再生成客户端加密密钥,服务端加密密钥,客户端MAC secert,服务端MAC secert。MAC secert用于做报文摘要,这样能够查知报文是否遭到篡改,从而保护报文的完整性。
Android网络请求知识(一)HTTP基础概念
Android网络请求知识(二)对称和非对称加密、数字签名,Hash,Base64编码
Android网络请求知识(三)授权,TCP/IP,HTTPS建立过程
Ⅳ Android上实现TCP服务端
之前已经讲过了tcp客户端的实现了,大家有兴趣的话,可以参看文章
Android上实现TCP客户端
那么,今天我们就来讲讲tcp之服务端的封装吧。我已经将tcp服务端封装成了一个类—TcpServer,下面就来讲讲它的使用吧。
今天涉及内容:
先来波效果图
在 tcp服务端 建立 ServerSocket 的时候,我们通常是这样的:
其实以上方法调用的是
其中涉及到的参数:
鉴于tcp服务端 ServerSocket 一般运行在 "本机" 上,则快速初始化 ServerSocket 运用上面的方法:
意思是建立的ServerSocket IP地址为本机,可容纳socket个数为 50 。
在理解了 ServerSocket 初始化问题后,让我们来看看封装类TcpServer的几个主要方法:
TcpServer 主要是在 java 上运行,所以就让我们在 Androidstudio 上模拟下在 Java 中运行tcp服务端的场景:
这里涉及到的两个类 SocketConfig 和 SocketHelper 和之前的一样,大家可以参考文章 Android上实现TCP客户端 中与之相关的介绍,这里就不赘述了。
tcp服务端主要容易出现以下两个问题:
对于第一个问题,这里需要强调的是 TcpServer 的接收方法 receiveMessage(String charsetName) 是以 (result = bufferedReader.readLine()) != null 做判断读取 stream 的,所以客户端向 TcpServer 发送消息时,需要在结尾加上\n,这样 TcpServer 的receiveMessage(String charsetName)方法才能将传过来的数据接收完整。
对于第二个问题,则需要客户端与服务端设置相同的字符集以保证数据不乱码。
封装类 TcpServer 源码如下:
Ⅳ android socket用TCP方式client端怎么监听服务器发送来的数据
服务器端就是需要一个循环不停的接收,这样才能保证服务器能一直监听客户端传过来的数据 你这是同步的,如果用异步socket的话,BeginReceive里面注册了一个回调函数,在回调里面再次调用BeginReceive就可以一直监听了
Ⅵ Android中TCP客户端怎么可以及时判断与服务端的异常断开呀 我想在客户
直接用BufferedReader
如果readLine() 返回为null的话, 表示socket已经断开连接了, 因为readLine() 是阻塞的, 就是等服务器的数据输出, 一直等到返回了回车换行, 才会继续执行。
Ⅶ android开发tcp客户端循环接收信息,为什么收不到呀
InputStream reader = socket.getInputStream()
byte[] bbuf = new byte[1000];
int count = reader.read(bbuf);
把读取数据的方式改成这种试试,怕是你使用readline()方法的时候接收不到最后的“回车换行符”导致的。
Ⅷ 安卓串口转tcp
安卓串口转tcp是将设备串口数据传到网络服务器中,除了用DTU之外,还可以使用“MX虚拟串口”工具软件,安装在电脑或控制器中,简单两步配置即可实现。
1、下载安装“MX虚拟串口”到官网下载www.meixuannet.cn。
2、创建“串口TCP客户端”,实现串口转tcp网络,写入串口的数据会发给远程tcp服务器,方便实现远程串口应用。
Ⅸ Android的APP客户端和服务器端一般是用什么协议
HTTP 协议,建立在TCP/IP 的基础上
FTP 协议
TCP/IP 协议,socket 编程(分客户端和服务端)
Ⅹ android 客户端用wifi socket Tcp/ip 连接上pc服务器后一段时间后wifi关闭再打开,为什么服务器就收不到客
没设置