「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」
使用Socket那些事
在进行socket长链接时,我们通常是使用第三方的库,著名的长链接库有很多,比如Apache的mina、OkHttp中的WebSocket、SokcetIo等,它们之间有什么联系呢,又是怎么进行发送的呢。
一、双向通信
我们常用的HTTP协议实际上也是建立在TCP上的一种协议。
TCP 属于传输层,HTTP属于应用层,双向通信的长链接,也是建立在传输层之上进行通讯的,也是一种应用层协议。
HTTP是一种无状态协议,无法实现客户端和服务器的双向通信,协议中限制了只能客户端向服务器进行请求,由服务器进行返回。
而常说的长链接协议,是可以进行双向通信的,客户端可以主动向服务器发送消息,服务器也可以主动向客户端发送消息。
这样就被称为双向通信。
二、长链接协议的区别
所谓的协议,不要把它想的太复杂,协议本质上可以说是一种约定与规范。
我们在常用的长链接协议,前端来说就是websocket,安卓中就是OkHttp也有对webSocket的支持,有时候我们也会在安卓中利用socket写原生方法,TCP是非常复杂的,socket是对TCP的封装,方便了我们进行网络编程。
比如mina、还有github上7.2k Star的AndroidAsync。
最终我都没有使用它们,而是自己基于socket进行定制,因为mina虽然功能很全,但对客户端来说过于臃肿,编解码器相对复杂。AndroidAsync使用了一端时间也弃用了,因为我用了一种更简单的接收方式。
AndroidAsync 中的接收方法
do {
// if the handshake is finished, don't send
// 0 bytes of data, since that makes the ssl connection die.
// it wraps a 0 byte package, and craps out.
if (finishedHandshake && bb.remaining() == 0)
break;
remaining = bb.remaining();
try {
ByteBuffer[] arr = bb.getAllArray();
res = engine.wrap(arr, writeBuf);
bb.addAll(arr);
writeBuf.flip();
writeList.add(writeBuf);
if (writeList.remaining() > 0)
mSink.write(writeList);
int previousCapacity = writeBuf.capacity();
writeBuf = null;
if (res.getStatus() == Status.BUFFER_OVERFLOW) {
writeBuf = ByteBufferList.obtain(previousCapacity * 2);
remaining = -1;
}
else {
writeBuf = ByteBufferList.obtain(calculateAlloc(bb.remaining()));
handleHandshakeStatus(res.getHandshakeStatus());
}
}
catch (SSLException e) {
report(e);
}
}
while ((remaining != bb.remaining() || (res != null && res.getHandshakeStatus() == HandshakeStatus.NEED_WRAP)) && mSink.remaining() == 0);
我的接收方法
while ((line = br.readLine()) != null) {
handleReceiveTcpMessage(line);
}
可以注意到 readLine方法,它可以很方便的接收字符串,但是我记得很多长链接的库都是可以接受byte[]数组的,那怎么让socket同时支持接收字符串,又可以接受字节数组呢?
我现在也有一些疑惑,还在整理,总结完之后再来更新。