更新時(shí)間:2022-12-22 11:21:05 來源:動(dòng)力節(jié)點(diǎn) 瀏覽4066次
1.長(zhǎng)連接與短連接的概念:
前者是整個(gè)通訊過程,客戶端和服務(wù)端只用一個(gè)Socket對(duì)象,長(zhǎng)期保持Socket的連接;后者是每次請(qǐng)求,都新建一個(gè)Socket,處理完一個(gè)請(qǐng)求就直接關(guān)閉掉Socket。所以,其實(shí)區(qū)分長(zhǎng)短連接就是:整個(gè)客戶和服務(wù)端的通訊過程是利用一個(gè)Socket還是多個(gè)Socket進(jìn)行的。
可能你會(huì)想:這還不簡(jiǎn)單,長(zhǎng)連接不就是不關(guān)Socket嘛,短連接不就是每次都關(guān)Socket每次都new Socket嘛。然而事實(shí)其實(shí)并沒有那么簡(jiǎn)單的。
2.關(guān)閉流而保持Socket正常?
在網(wǎng)上百度了一下,發(fā)現(xiàn)很多人都是以關(guān)閉流還是關(guān)閉Socket來區(qū)分長(zhǎng)連接和短連接的,其實(shí),這種區(qū)分方法并沒有什么意義:因?yàn)檫@里面有一個(gè)事實(shí)是,流關(guān)閉之后,便不能進(jìn)行消息的發(fā)送(對(duì)應(yīng)關(guān)閉輸出流)或者接受(對(duì)應(yīng)關(guān)閉輸入流),因?yàn)槠鋵?shí)關(guān)閉了對(duì)應(yīng)的流,對(duì)應(yīng)連接也就關(guān)閉了(這里所說的連接是發(fā)送消息的通道!),所以,流關(guān)閉而保持Socket開啟,是沒有達(dá)到長(zhǎng)連接的效果,貼上測(cè)試代碼:
//發(fā)送核心方法
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);
}
//進(jìn)行加密操作
list = encry(list);
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
writer.write(it.next());
}
writer.flush();
rtn = "發(fā)送成功!";
}finally{
//注意:直接關(guān)閉流將會(huì)導(dǎo)致socket關(guān)閉,只能通過shutdownOutput/input的方式關(guān)閉流
//另外,流關(guān)閉之后,相當(dāng)于關(guān)閉底層的連接,除非新new個(gè)socket,否則和客戶端的連接相當(dāng)于斷開
// if(writer!=null){
// writer.close();
// }
// if(ow!=null){
// ow.close();
// }
// if(os!=null){
//os.close();
// }
//socket.shutdownOutput();流關(guān)閉之后,相當(dāng)于關(guān)閉底層的連接,除非新<br>new個(gè)socket,否則和客戶端的連接相當(dāng)于斷開
}
return rtn;
}
實(shí)現(xiàn)長(zhǎng)連接的方法
A.客戶端自動(dòng)退出開讀取的動(dòng)作。前面說了,就算服務(wù)端調(diào)用了flush方法進(jìn)行輸出刷新,客戶端也不一定能退出read的動(dòng)作,所以還是會(huì)阻塞。所以,退出動(dòng)作必須有客戶端程序自己完成,我們可以在服務(wù)端沒發(fā)送完一段消息并且刷新前就進(jìn)行一個(gè)寫入結(jié)束符號(hào)的標(biāo)志,客戶端解析到結(jié)束符號(hào)時(shí),變可直接退出read的循環(huán)讀取操作,避免一直阻塞。
B.可以調(diào)用有讀取一定字節(jié)到某個(gè)數(shù)組的read方法(不過好像這個(gè)不太行,畢竟每次消息的長(zhǎng)度好像會(huì)變的),當(dāng)然,這只是針對(duì)消息定長(zhǎng)的情況。
下面貼上長(zhǎng)連接實(shí)現(xiàn)后的代碼(其實(shí)就是比前面的代碼加多了讀入結(jié)束標(biāo)記符號(hào))
//發(fā)送核心方法
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);
}
//進(jìn)行加密操作
list = encry(list);
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
writer.write(it.next());
}
//寫入結(jié)束標(biāo)志符號(hào):%
writer.write('%');
writer.flush();
rtn = "發(fā)送成功!";
}finally{
//注意:直接關(guān)閉流將會(huì)導(dǎo)致socket關(guān)閉,只能通過shutdownOutput/input的方式關(guān)閉流
//另外,流關(guān)閉之后,相當(dāng)于關(guān)閉底層的連接,除非新new個(gè)socket,否則和客戶端的連接相當(dāng)于斷開
// if(writer!=null){
// writer.close();
// }
// if(ow!=null){
// ow.close();
// }
// if(os!=null){
//os.close();
// }
//socket.shutdownOutput();流關(guān)閉之后,相當(dāng)于關(guān)閉底層的連接,除非新new個(gè)socket,否則和客戶端的連接相當(dāng)于斷開
}
return rtn;
}
每次關(guān)閉Socket和流時(shí)需要注意一下事情:
1.雖然前面說了流關(guān)閉了,Socket就不可用了,但是,我們還是要顯式的關(guān)閉Socket的,因?yàn)樵赟ocekt中還有中狀態(tài):叫做半連接狀態(tài),當(dāng)我們只是用到輸出流的時(shí)候,我們關(guān)閉了輸出流,并且不能直接調(diào)用close方法,只能調(diào)用shutDown對(duì)應(yīng)方法(具體請(qǐng)查看java API),其實(shí)輸入流還是連接著的(只是我們沒有用到而已!),這時(shí)候,如果沒有顯式關(guān)閉Soceket,很容易導(dǎo)致內(nèi)存泄露,所以,所有流Socket都要顯式關(guān)閉
2.短連接和長(zhǎng)連接有不同的用途:對(duì)于某次服務(wù)只需要一次回話的客戶,使用短連接顯得簡(jiǎn)單;但是,如果該次服務(wù)需要很多交互式的操作通信,那還是長(zhǎng)連接比較高性能,畢竟,Socket的打開和關(guān)閉都是很耗性能的。
相關(guān)閱讀
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問老師會(huì)電話與您溝通安排學(xué)習(xí)
初級(jí) 202925
初級(jí) 203221
初級(jí) 202629
初級(jí) 203743