使用Socket那些事

321 阅读2分钟

「这是我参与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同时支持接收字符串,又可以接受字节数组呢?

我现在也有一些疑惑,还在整理,总结完之后再来更新。