日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java如何实现Socket的长连接和短连接

發布時間:2023/12/10 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java如何实现Socket的长连接和短连接 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

討論Socket必討論長連接和短連接

一、長連接和短連接的概念

  1、長連接與短連接的概念:前者是整個通訊過程,客戶端和服務端只用一個Socket對象,長期保持Socket的連接;后者是每次請求,都新建一個Socket,處理完一個請求就直接關閉掉Socket。所以,其實區分長短連接就是:整個客戶和服務端的通訊過程是利用一個Socket還是多個Socket進行的。

  可能你會想:這還不簡單,長連接不就是不關Socket嘛,短連接不就是每次都關Socket每次都new Socket嘛。然而事實其實并沒有那么簡單的,請繼續看下面的整理

  2、關閉流而保持Socket正常?

    在網上百度了一下,發現很多人都是以關閉流還是關閉Socket來區分長連接和短連接的,其實,個人感覺這種區分方法并沒有什么意義:因為這里面有一個事實是,流關閉之后,便不能進行消息的發送(對應關閉輸出流)或者接受(對應關閉輸入流),因為其實關閉了對應的流,對應連接也就關閉了(這里所說的連接是發送消息的通道!),所以,流關閉而保持Socket開啟,是沒有達到長連接的效果,貼上測試代碼:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 //發送核心方法 ????public?String send(String send)?throws?IOException { ????????String rtn =?null; ????????BufferedWriter writer =?null; ????????OutputStreamWriter ow =?null; ????????OutputStream os =?null; ????????try{ ????????????os = socket.getOutputStream(); ????????????ow =?new?OutputStreamWriter(os); ????????????writer =?new?BufferedWriter(ow); ????????????char?[] sendChar = send.toCharArray(); ????????????ArrayList<Integer> list =?new?ArrayList<Integer>(); ????????????for(char?ch:sendChar){ ????????????????list.add((int)ch); ????????????} ????????????//進行加密操作 ????????????list = encry(list); ????????????Iterator<Integer> it = list.iterator(); ????????????while(it.hasNext()){ ????????????????writer.write(it.next()); ????????????} ????????????writer.flush(); ????????????rtn =?"發送成功!"; ????????}finally{ ????????????//注意:直接關閉流將會導致socket關閉,只能通過shutdownOutput/input的方式關閉流 ????????????//另外,流關閉之后,相當于關閉底層的連接,除非新new個socket,否則和客戶端的連接相當于斷開 //????????? if(writer!=null){ //????????????? writer.close(); //????????? } //????????? if(ow!=null){ //????????????? ow.close(); //????????? } //????????? if(os!=null){ ????????????????//os.close(); //????????? } ????????????//socket.shutdownOutput();流關閉之后,相當于關閉底層的連接,除非新<br>new個socket,否則和客戶端的連接相當于斷開 ????????} ????????return?rtn; ????}

  這是我寫的一個測試的發送消息的核心方法,在關閉了對應的流(無論是輸出或者輸入)之后,下一次調用getInputStream或者getOutputStream會拋出異常說:Socket is closed;這里講明一個事實:Socket和流聯系著,流關閉了,Socket其實也就相當于關閉狀態!

  其實這個也很好理解,Socket本來就是依靠流進行關閉的,流,就只有一個,你關閉了流,Socket賴以通訊的渠道也就關閉了,與客戶的連接也斷開了,所以拋出異常是很合理的。

  所以,流關閉而要求Socket正常通訊是不可能的!

  所以,如何實現長連接?

二、長連接的正確實現方式

  1、不關閉流實現長連接?

    前面討論了,流關閉了而不關閉Socket,還是無法達到長連接的效果的,所以,要長連接,流必須不能關閉!那么,是不是直接不關閉流,然后每次要發消息就直接往流里面任進去數據,然后調用flush()方法強制刷新就行了?其實不行的,這樣客戶端是無法正常接收信息的,你會發覺就算服務端flush了,客戶端還是會一直在read方法那里阻塞!具體原因各位可以看一下java api文檔的截圖:

?

?文檔說明了,如果流一直可用,而且沒有讀到流的末尾(就是對應著對方流已經關閉或者網絡斷開!),read會一直阻塞!其實這樣做也是可以解釋清楚的:本來服務端的read方法就不知道Server端的消息什么時候發送完,說不定我以為數據發送完 了,但其實是因為網絡延遲而導致部分數據延后到來(況且也不可能所有數據同時到達),所以,read方法只能一直在阻塞等待對方的應答。所以,怎么實現長連接?

  2、實現長連接的方法

  A、客戶端自動退出開讀取的動作。前面說了,就算服務端調用了flush方法進行輸出刷新,客戶端也不一定能退出read的動作,所以還是會阻塞。所以,退出動作必須有客戶端程序自己完成,我們可以在服務端沒發送完一段消息并且刷新前就進行一個寫入結束符號的標志,客戶端解析到結束符號時,變可直接退出read的循環讀取操作,避免一直阻塞。

  B、可以調用有讀取一定字節到某個數組的read方法(不過好像這個不太行,畢竟每次消息的長度好像會變的),當然,這只是針對消息定長的情況。

  下面貼上長連接實現后的代碼(其實就是比前面的代碼加多了讀入結束標記符號)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 //發送核心方法 ????public?String send(String send)?throws?IOException { ????????String rtn =?null; ????????BufferedWriter writer =?null; ????????OutputStreamWriter ow =?null; ????????OutputStream os =?null; ????????try{ ????????????os = socket.getOutputStream(); ????????????ow =?new?OutputStreamWriter(os); ????????????writer =?new?BufferedWriter(ow); ????????????char?[] sendChar = send.toCharArray(); ????????????ArrayList<Integer> list =?new?ArrayList<Integer>(); ????????????for(char?ch:sendChar){ ????????????????list.add((int)ch); ????????????} ????????????//進行加密操作 ????????????list = encry(list); ????????????Iterator<Integer> it = list.iterator(); ????????????while(it.hasNext()){ ????????????????writer.write(it.next()); ????????????} ????????????//寫入結束標志符號:% ????????????writer.write('%'); ????????????writer.flush(); ????????????rtn =?"發送成功!"; ????????}finally{ ????????????//注意:直接關閉流將會導致socket關閉,只能通過shutdownOutput/input的方式關閉流 ????????????//另外,流關閉之后,相當于關閉底層的連接,除非新new個socket,否則和客戶端的連接相當于斷開 //????????? if(writer!=null){ //????????????? writer.close(); //????????? } //????????? if(ow!=null){ //????????????? ow.close(); //????????? } //????????? if(os!=null){ ????????????????//os.close(); //????????? } ????????????//socket.shutdownOutput();流關閉之后,相當于關閉底層的連接,除非新new個socket,否則和客戶端的連接相當于斷開 ????????} ????????return?rtn; ????}

 三、短連接

    短連接就基本沒什么好講的啦,只是每次關閉Socket和流時需要注意一下事情:

    1、雖然前面說了流關閉了,Socket就不可用了,但是,我們還是要顯式的關閉Socket的,因為在Socekt中還有中狀態:叫做半連接狀態,當我們只是用到輸出流的時候,我們關閉了輸出流,并且不能直接調用close方法,只能調用shutDown對應方法(具體請查看java API),其實輸入流還是連接著的(只是我們沒有用到而已!),這時候,如果沒有顯式關閉Soceket,很容易導致內存泄露,所以,所有流Socket都要顯式關閉

    2、短連接和長連接有不同的用途:對于某次服務只需要一次回話的客戶,使用短連接顯得簡單;但是,如果該次服務需要很多交互式的操作通信,那還是長連接比較高性能,畢竟,Socket的打開和關閉都是很耗性能的。

?

四、總結

  1、對應流關閉,Socket的對應輸入(出)數據的通道也就關閉,此時無法達到長連接效果;

  2、關閉Socket,記得顯式關閉流與socket,順序是線管流再關socket.

  3、要實先長連接,一般需要發送結束標記符號來告訴客戶端服務端的某段消息已經發送完畢,否則客戶端會一直阻塞在read方法。

?

原文轉載:https://www.cnblogs.com/lcplcpjava/p/6581179.html

?

轉載于:https://www.cnblogs.com/AndyAo/p/8232700.html

總結

以上是生活随笔為你收集整理的java如何实现Socket的长连接和短连接的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。