java socket編程實例 JAVA編程實例
夕逆IT
- 數(shù)據(jù)庫
- 2023-08-13
- 96

大家好,今天小編來為大家解答java這個問題,JAVA編程實例很多人還不知道,現(xiàn)在讓我們一起來看看吧!遇到java.net.SocketTimeoutException...
大家好,今天小編來為大家解答java這個問題,JAVA編程實例很多人還不知道,現(xiàn)在讓我們一起來看看吧!
遇到java.net.SocketTimeoutException:Readtimedout怎么辦
連接超時,確保網(wǎng)絡通暢后重連,若還連不上是他們服務器的問題這樣可以么?
java socket客戶端怎樣確認服務器端是否收到數(shù)據(jù)
在服務端接收完數(shù)據(jù)之后返回一個接收完畢的通知給客戶端,告訴客戶端我已經(jīng)把數(shù)據(jù)接收完了。
如何使用Socket在客戶端實現(xiàn)長連接
長連接貌似是一個很高深莫測的知識,但是只要你做直播、IM、游戲、彈幕里面的任何一種,或者是你的app想要實時的接收某些消息,你就會要接觸到長連接技術。本文主要教你如何在客戶端如何使用Socket實現(xiàn)長連接。
Socket背景知識
要做長連接的話,是不能用http協(xié)議來做的,因為http協(xié)議已經(jīng)是應用層協(xié)議了,并且http協(xié)議是無狀態(tài)的,而我們要做長連接,肯定是需要在應用層封裝自己的業(yè)務,所以就需要基于TCP協(xié)議來做,而基于TCP協(xié)議的話,就要用到Socket了。
Socket是java針對tcp層通信封裝的一套網(wǎng)絡方案
TCP協(xié)議我們知道,是基于ip(或者域名)和端口對指定機器進行的點對點訪問,他的連接成功有兩個條件,就是對方ip可以到達和端口是開放的
Socket能幫完成TCP三次握手,而應用層的頭部信息需要自己去解析,也就是說,自己要制定好協(xié)議,并且要去解析byte
http也有長連接。在http1.0的時候,使用的是短連接,也就是說,每次請求一次數(shù)據(jù),都要重新建立連接。但是從http1.1之后,我們看到頭部會有一個
Connection:keep-alive
這個表示tcp連接建立之后不會馬上銷毀,而是保存一段時間,在這段時間內如果需要請求改網(wǎng)站的其他數(shù)據(jù),都是使用這個連接來完成傳輸?shù)摹?/p>
Socket使用方式
Socket看上去不是很好用,因為他是基于java.io來實現(xiàn)的,你要直接跟InputStream和OutputStream打交道,也就是直接跟byte[]打交道,所以用起來并不是這么友好。
下面通過一個簡單的例子,往一臺服務器發(fā)\01\00\00\00\00這一串字節(jié),服務器也返回相同的字節(jié)流,上代碼:
@Test
publicvoidtestSocket()throwsException{
logger.debug("start");
Socketsocket=newSocket();
socket.connect(address);
byte[]output=newbyte[]{(byte)1,(byte)0,(byte)0,(byte)0,(byte)0};
socket.getOutputStream().write(output);
byte[]input=newbyte[64];
intreadByte=socket.getInputStream().read(input);
logger.debug("readByte"+readByte);
for(inti=0;i<readByte;i++){
logger.debug("read["+i+"]:"+input[i]);
}
socket.close();
}
輸出:
11:40:40.326[main]DEBUGcom.roy.test.SocketTest-start
11:40:40.345[main]DEBUGcom.roy.test.SocketTest-readByte5
11:40:40.345[main]DEBUGcom.roy.test.SocketTest-read1
11:40:40.345[main]DEBUGcom.roy.test.SocketTest-read0
11:40:40.345[main]DEBUGcom.roy.test.SocketTest-read0
11:40:40.345[main]DEBUGcom.roy.test.SocketTest-read0
11:40:40.345[main]DEBUGcom.roy.test.SocketTest-read0
看出來寫起來還是比較麻煩的,主要就是InputStream,OutputStream和byte[]使用起來太不方便了。
SocketChannelblocking
Socket為了優(yōu)化自己的封裝和并發(fā)性能,推出了nio包下面的SocketChannel,這個相比于Socket的好處就是并發(fā)性能的提高和封裝的優(yōu)化了。
SocketChannel有兩種方式——阻塞和非阻塞的,阻塞的用法和Socket差不多,都是在read和write的時候會阻塞線程,下面用一段代碼來實現(xiàn)相同的功能。
@Test
publicvoidtestSocketChannelBlock()throwsException{
finalSocketChannelchannel=SocketChannel.open(address);
ByteBufferoutput=ByteBuffer.allocate(5);
output.put((byte)1);
output.putInt(0);
output.flip();
channel.write(output);
logger.debug("writecomplete,startread");
ByteBufferinput=ByteBuffer.allocate(5);
intreadByte=channel.read(input);
logger.debug("readByte"+readByte);
input.flip();
if(readByte==-1){
logger.debug("readByte==-1,return!");
return;
}
for(inti=0;i<readByte;i++){
logger.debug("read["+i+"]:"+input.get());
}
}
log輸出:
23:24:34.684[main]DEBUGcom.dz.test.SocketTest-writecomplete,startread
23:24:34.901[main]DEBUGcom.dz.test.SocketTest-readByte5
23:24:34.901[main]DEBUGcom.dz.test.SocketTest-read[0]:1
23:24:34.901[main]DEBUGcom.dz.test.SocketTest-read[1]:0
23:24:34.901[main]DEBUGcom.dz.test.SocketTest-read[2]:0
23:24:34.901[main]DEBUGcom.dz.test.SocketTest-read[3]:0
23:24:34.901[main]DEBUGcom.dz.test.SocketTest-read[4]:0
從上面的。封裝優(yōu)化主要體現(xiàn)在ByteBuffer,IntBuffer這一系列類的封裝——因為是網(wǎng)絡相關的,所以這里用到的主要是ByteBuffer。
ByteBuffer和byte[]最大的區(qū)別,就是ByteBuffer可以很方便的讀取int,long等數(shù)據(jù)類型,他提供了getInt(),getInt(intoffset)這樣的方法,這種方法主要用在識別頭部數(shù)據(jù)部分,因為頭部數(shù)據(jù)一般都是由多種數(shù)據(jù)類型組成,比方說表示數(shù)據(jù)格式的contentType:String,表示長度的length:int等等,這些就是getInt()這樣的方法主要的應用場景,而byte[]如果要取int,String相對來說就要復雜一些了,這是java.nio相比于java.io優(yōu)勢的一點。
這里需要說明一個比較坑的點,就是ByteBuffer.flip()這個方法,這個方法的作用主要是重置索引,在write()之前和read()之后調用,否則會因為索引不對,導致你的數(shù)據(jù)寫不進去,讀不出來。
ByteBuffer是一個功能強大的類,因為本文主要是講Socket和SocketChannel,所以在這里就不做過多描述。具體ByteBuffer的詳細介紹,可以參考:JavaNIO系列教程(三)Buffer
而nio相比于io最大的優(yōu)勢還是在于并發(fā)性能,因為nio里面的n代表的就是non-blocking的意思,上面那個讀取數(shù)據(jù)的代碼也相對老舊,一般我們如果要用SocketChannel,都是用non-blocking的方式來實現(xiàn)的,而如果要用non-blocking模式,首先要介紹的就是Selector。
Selector
我們知道,傳統(tǒng)io是阻塞的,也就是說,一個線程只能處理一個io流,也就是一個Socket。有了Selector之后,一個線程就能處理多個SocketChannel。
Selector的原
自學java感到學到自己的瓶頸期了,各種框架亂七八糟,感覺好亂。該怎么辦
下面是我的視頻里大概要介紹的內容:
如何看待框架知其然,知其所以然。不僅要學會使用框架,還需要學會框架的原理。最好的方法是自己動手模仿著做一下。一動手你就開始從框架設計者的角度考慮問題了。你思考問題的角度和高度就和以前不一樣了。
如何突破瓶頸,更上一層樓學習算法和設計模式。思考框架要解決的本質問題。評價這種方法的優(yōu)缺點。如果是你,你有什么改進意見??梢詤⒖嘉业膭赢嬕曨l,講解了很多分布式系統(tǒng)的設計原理。
推薦幾本好書,值得精讀很多遍的書大多數(shù)人的悟性是差不多的。多讀好書,可以從前輩大牛,甚至是世界級頂級專家那里得到指導和啟發(fā)。
下面這本書是MIT的本科教材,網(wǎng)上有作者的公開課??梢哉伊丝纯?。
下面這本書是關于分布式系統(tǒng)應用設計中遇到的問題和通常的解決思路。比如hadoop,kafka,flink,zookeeper,raft他們都是用來解決什么問題的。
本人,@小馬過河Vizit,專注于分布式系統(tǒng)原理和實踐分享。希望利用動畫生動而又準確地演示抽象的原理。
關于我的名字。小馬過河Vizit,意為凡事像小馬過河一樣,需要自己親自嘗試、探索才能獲得樂趣和新知。Vizit是指Visualizeit的縮寫。一圖勝千言,希望可以利用動畫來可視化抽象的原理。
歡迎關注,點贊!謝謝支持。
socket建立連接的步驟
javasocket建立連接的過程如下:
1、首先調用Socket類的構造函數(shù),以服務器的指定的IP地址或指定的主機名和指定的端口號為參數(shù),創(chuàng)建一個Socket流,在創(chuàng)建Socket流的過程中包含了向服務器請求建立通訊連接的過程實現(xiàn)。
2、建立了客戶端通訊Socket后。就可以使用Socket的方法getInputStream()和getOutputStream()來創(chuàng)建輸入/輸出流。這樣,使用Socket類后,網(wǎng)絡輸入輸出也轉化為使用流對象的過程。
3、使用輸入輸出流對象的相應方法讀寫字節(jié)流數(shù)據(jù),因為流連接著通訊所用的Socket,Socket又是和服務器端建立連接的一個端點,因此數(shù)據(jù)將通過連接從服務器得到或發(fā)向服務器。這時我們就可以對字節(jié)流數(shù)據(jù)按客戶端和服務器之間的協(xié)議進行處理,完成雙方的通訊任務。
4、待通訊任務完畢后,我們用流對象的close()方法來關閉用于網(wǎng)絡通訊的輸入輸出流,在用Socket對象的close()方法來關閉Socket。
socket雙向連接的建立過程
javasocket建立連接的過程如下:socket
1、首先調用Socket類的構造函數(shù),以服務器的指定的IP地址或指定的主機名和指定的端口號為參數(shù),創(chuàng)建一個Socket流,在創(chuàng)建Socket流的過程中包含了向服務器請求建立通訊連接的過程實現(xiàn)。
2、建立了客戶端通訊Socket后。就可以使用Socket的方法getInputStream()和getOutputStream()來創(chuàng)建輸入/輸出流。這樣,使用Socket類后,網(wǎng)絡輸入輸出也轉化為使用流對象的過程。
3、使用輸入輸出流對象的相應方法讀寫字節(jié)流數(shù)據(jù),因為流連接著通訊所用的Socket,Socket又是和服務器端建立連接的一個端點,因此數(shù)據(jù)將通過連接從服務器得到或發(fā)向服務器。這時我們就可以對字節(jié)流數(shù)據(jù)按客戶端和服務器之間的協(xié)議進行處理,完成雙方的通訊任務。
4、待通訊任務完畢后,我們用流對象的close()方法來關閉用于網(wǎng)絡通訊的輸入輸出流,在用Socket對象的close()方法來關閉Socket。
OK,本文到此結束,希望對大家有所幫助。
本文鏈接:http://m.tiantaijiaoyu.cn/su/4163.html