欧美一区二区三区,国内熟女精品熟女A片视频小说,日本av网,小鲜肉男男GAY做受XXX网站

如何使用Socket在客戶端實現(xiàn)長連接

錢斌斌2年前16瀏覽0評論

如何使用Socket在客戶端實現(xiàn)長連接?

長連接貌似是一個很高深莫測的知識,但是只要你做直播、IM、游戲、彈幕里面的任何一種,或者是你的app想要實時的接收某些消息,你就會要接觸到長連接技術(shù)。本文主要教你如何在客戶端如何使用Socket實現(xiàn)長連接。

Socket背景知識

要做長連接的話,是不能用http協(xié)議來做的,因為http協(xié)議已經(jīng)是應(yīng)用層協(xié)議了,并且http協(xié)議是無狀態(tài)的,而我們要做長連接,肯定是需要在應(yīng)用層封裝自己的業(yè)務(wù),所以就需要基于TCP協(xié)議來做,而基于TCP協(xié)議的話,就要用到Socket了。

Socket是java針對tcp層通信封裝的一套網(wǎng)絡(luò)方案

TCP協(xié)議我們知道,是基于ip(或者域名)和端口對指定機(jī)器進(jìn)行的點對點訪問,他的連接成功有兩個條件,就是對方ip可以到達(dá)和端口是開放的

Socket能幫完成TCP三次握手,而應(yīng)用層的頭部信息需要自己去解析,也就是說,自己要制定好協(xié)議,并且要去解析byte

http也有長連接。在http1.0的時候,使用的是短連接,也就是說,每次請求一次數(shù)據(jù),都要重新建立連接。但是從http1.1之后,我們看到頭部會有一個

Connection:keep-alive

這個表示tcp連接建立之后不會馬上銷毀,而是保存一段時間,在這段時間內(nèi)如果需要請求改網(wǎng)站的其他數(shù)據(jù),都是使用這個連接來完成傳輸?shù)摹?/p>

Socket使用方式

Socket看上去不是很好用,因為他是基于java.io來實現(xiàn)的,你要直接跟InputStream和OutputStream打交道,也就是直接跟byte[]打交道,所以用起來并不是這么友好。

下面通過一個簡單的例子,往一臺服務(wù)器發(fā)\01 \00 \00 \00 \00這一串字節(jié),服務(wù)器也返回相同的字節(jié)流,上代碼:

@Test

public void testSocket() throws Exception {

logger.debug("start");

Socket socket = new Socket();

socket.connect(address);

byte[] output = new byte[]{(byte) 1, (byte) 0, (byte) 0, (byte) 0, (byte) 0};

socket.getOutputStream().write(output);

byte[] input = new byte[64];

int readByte = socket.getInputStream().read(input);

logger.debug("readByte " + readByte);

for (int i = 0; i < readByte; i++) {

logger.debug("read [" + i + "]:" + input[i]);

}

socket.close();

}

輸出:

11:40:40.326 [main] DEBUG com.roy.test.SocketTest - start

11:40:40.345 [main] DEBUG com.roy.test.SocketTest - readByte 5

11:40:40.345 [main] DEBUG com.roy.test.SocketTest - read 1

11:40:40.345 [main] DEBUG com.roy.test.SocketTest - read 0

11:40:40.345 [main] DEBUG com.roy.test.SocketTest - read 0

11:40:40.345 [main] DEBUG com.roy.test.SocketTest - read 0

11:40:40.345 [main] DEBUG com.roy.test.SocketTest - read 0

看出來寫起來還是比較麻煩的,主要就是InputStream, OutputStream 和byte[]使用起來太不方便了。

SocketChannel blocking

Socket為了優(yōu)化自己的封裝和并發(fā)性能,推出了nio包下面的SocketChannel,這個相比于Socket的好處就是并發(fā)性能的提高和封裝的優(yōu)化了。

SocketChannel有兩種方式——阻塞和非阻塞的,阻塞的用法和Socket差不多,都是在read和write的時候會阻塞線程,下面用一段代碼來實現(xiàn)相同的功能。

@Test

public void testSocketChannelBlock() throws Exception {

final SocketChannel channel = SocketChannel.open(address);

ByteBuffer output = ByteBuffer.allocate(5);

output.put((byte) 1);

output.putInt(0);

output.flip();

channel.write(output);

logger.debug("write complete, start read");

ByteBuffer input = ByteBuffer.allocate(5);

int readByte = channel.read(input);

logger.debug("readByte " + readByte);

input.flip();

if (readByte == -1) {

logger.debug("readByte == -1, return!");

return;

}

for (int i = 0; i < readByte; i++) {

logger.debug("read [" + i + "]:" + input.get());

}

}

log 輸出:

23:24:34.684 [main] DEBUG com.dz.test.SocketTest - write complete, start read

23:24:34.901 [main] DEBUG com.dz.test.SocketTest - readByte 5

23:24:34.901 [main] DEBUG com.dz.test.SocketTest - read [0]:1

23:24:34.901 [main] DEBUG com.dz.test.SocketTest - read [1]:0

23:24:34.901 [main] DEBUG com.dz.test.SocketTest - read [2]:0

23:24:34.901 [main] DEBUG com.dz.test.SocketTest - read [3]:0

23:24:34.901 [main] DEBUG com.dz.test.SocketTest - read [4]:0

從上面的。封裝優(yōu)化主要體現(xiàn)在ByteBuffer,IntBuffer這一系列類的封裝——因為是網(wǎng)絡(luò)相關(guān)的,所以這里用到的主要是ByteBuffer。

ByteBuffer和byte[]最大的區(qū)別,就是ByteBuffer可以很方便的讀取int, long等數(shù)據(jù)類型,他提供了getInt(), getInt(int offset)這樣的方法,這種方法主要用在識別頭部數(shù)據(jù)部分,因為頭部數(shù)據(jù)一般都是由多種數(shù)據(jù)類型組成,比方說表示數(shù)據(jù)格式的contentType:String,表示長度的length:int等等,這些就是getInt()這樣的方法主要的應(yīng)用場景,而byte[]如果要取int,String相對來說就要復(fù)雜一些了,這是java.nio相比于java.io優(yōu)勢的一點。

這里需要說明一個比較坑的點,就是ByteBuffer.flip()這個方法,這個方法的作用主要是重置索引,在write()之前和read()之后調(diào)用,否則會因為索引不對,導(dǎo)致你的數(shù)據(jù)寫不進(jìn)去,讀不出來。

ByteBuffer是一個功能強(qiáng)大的類,因為本文主要是講Socket和SocketChannel,所以在這里就不做過多描述。具體ByteBuffer的詳細(xì)介紹,可以參考:Java NIO系列教程(三) Buffer

而nio相比于io最大的優(yōu)勢還是在于并發(fā)性能,因為nio里面的n代表的就是non-blocking的意思,上面那個讀取數(shù)據(jù)的代碼也相對老舊,一般我們?nèi)绻肧ocketChannel,都是用non-blocking的方式來實現(xiàn)的,而如果要用non-blocking模式,首先要介紹的就是Selector。

Selector

我們知道,傳統(tǒng)io是阻塞的,也就是說,一個線程只能處理一個io流,也就是一個Socket。有了Selector之后,一個線程就能處理多個SocketChannel。

Selector的原

長連接短連接java,如何使用Socket在客戶端實現(xiàn)長連接