javasocket緩存
Ⅰ java Socket重要參數講解
Java Socket的api可能很多人會用 但是Java Socket的參數可能很多人都不知道用來幹嘛的 甚至都不知道有這些參數
backlog
用於ServerSocket 配置ServerSocket的最大客戶端等待隊列 等待隊列的意思 先看下面代碼
public class Main { public static void main(String[] args) throws Exception { int port = int backlog = ServerSocket serverSocket = new ServerSocket(port backlog) Socket clientSock = serverSocket accept() System out println( revcive from + clientSock getPort()) while (true) { byte buf[] = new byte[ ] int len = clientSock getInputStream() read(buf) System out println(new String(buf len)) }這段測試代碼在第一次處理一個客戶端時 就不會處理第二個客戶端 所以除了第一個客戶端 其他客戶端就是等待隊列了 所以這個伺服器最多可以同時連接 個客戶端 其中 個等待隊列 大家可以telnet localhost 測試下
這個參數設置為 表示無限制 默認是 個最大等待隊列 如果設置無限制 那麼你要小心了 如果你伺服器無法處理那麼多連接 那麼當很多客戶端連到你的伺服器時 每一個TCP連接都會佔用伺服器的內存 最後會讓伺服器崩潰的
另外 就算你設置了backlog為 如果你的代碼中是一直Socket clientSock = serverSocket accept() 假設我們的機器最多可以同時處理 個請求 總共有 個線程在運行 然後你把在 個線程的線程池處理clientSock 不能處理的clientSock就排隊 最後clientSock越來越多 也意味著TCP連接越來越多 也意味著我們的伺服器的內存使用越來越高(客戶端連接進程 肯定會發送數據過來 數據會保存到伺服器端的TCP接收緩存區) 最後伺服器就宕機了 所以如果你不能處理那麼多請求 請不要循環無限制地調用serverSocket accept() 否則backlog也無法生效 如果真的請求過多 只會讓你的伺服器宕機(相信很多人都是這么寫 要注意點)
TcpNoDelay
禁用納格演算法 將數據立即發送出去 納格演算法是以減少封包傳送量來增進TCP/IP網路的效能 當我們調用下面代碼 如
Socket socket = new Socket() nnect(new InetSocketAddress(host )) InputStream in = socket getInputStream() OutputStream out = socket getOutputStream() String head = hello String body = world out write(head getBytes()) out write(body getBytes()) 我們發送了hello 當hello沒有收到ack確認(TCP是可靠連接 發送的每一個數據都要收到對方的一個ack確認 否則就要重發)的時候 根據納格演算法 world不會立馬發送 會等待 要麼等到ack確認(最多等 ms對方會發過來的) 要麼等到TCP緩沖區內容>=MSS 很明顯這里沒有機會 我們寫了world後再也沒有寫數據了 所以只能等到hello的ack我們才會發送world 除非我們禁用納格演算法 數據就會立即發送了
SoLinger
當我們調用socket close()返回時 socket已經write的數據未必已經發送到對方了 例如
Socket socket = new Socket() nnect(new InetSocketAddress(host )) InputStream in = socket getInputStream() OutputStream out = socket getOutputStream() String head = hello String body = world out write(head getBytes()) out write(body getBytes()) socket close()
這里調用了socket close()返回時 hello和world未必已經成功發送到對方了 如果我們設置了linger而不小於 如
bool on = true int linger = ……
socket setSoLinger(boolean on int linger)
……
socket close() 那麼close會等到發送的數據已經確認了才返回 但是如果對方宕機 超時 那麼會根據linger設定的時間返回
UrgentData和OOBInline
TCP的緊急指針 一般都不建議使用 而且不同的TCP/IP實現 也不同 一般說如果你有緊急數據寧願再建立一個新的TCP/IP連接發送數據 讓對方緊急處理
所以這兩個參數 你們可以忽略吧 想知道更多的 自己查下資料
SoTimeout
設置socket調用InputStream讀數據的超時時間 以毫秒為單位 如果超過這個時候 會拋出 SocketTimeoutException
KeepAlive
keepalive不是說TCP的常連接 當我們作為服務端 一個客戶端連接上來 如果設置了keeplive為true 當對方沒有發送任何數據過來 超過一個時間(看系統內核參數配置) 那麼我們這邊會發送一個ack探測包發到對方 探測雙方的TCP/IP連接是否有效(對方可能斷點 斷網) 在Linux好像這個時間是 秒 如果不設置 那麼客戶端宕機時 伺服器永遠也不知道客戶端宕機了 仍然保存這個失效的連接
SendBufferSize和ReceiveBufferSize
TCP發送緩存區和接收緩存區 默認是 一般情況下足夠了 而且就算你增加了發送緩存區 對方沒有增加它對應的接收緩沖 那麼在TCP三握手時 最後確定的最大發送窗口還是雙方最小的那個緩沖區 就算你無視 發了更多的數據 那麼多出來的數據也會被丟棄 除非雙方都協商好
lishixin/Article/program/Java/hx/201311/26575
Ⅱ Java Socket初步詳解
網路編程的基本模型就是客戶機到伺服器模型 簡單的說就是兩個進程之間相互通訊 然後其中一個必須提供一個固定的位置 而另一個則只需要知道這個固定的位置 並去建立兩者之間的聯系 然後完成數據的通訊就可以了 這里提供畝悉猜固定位置的通常稱為伺服器 而建立聯系的通常叫做客戶端 基於這個簡單的模型 就可以進入網路編程啦
Java對這個模型的支持有很多種Api 而這里我只想介紹有關Socket的編程介面 對於Java而言已經簡化了Socket的編程介面 首先我們來討論有關提供固定位置的服務方是如何建立的 Java提供了ServerSocket來對其進行支持 事實上當你創建該類的一個實力對象並提供一個埠資源你就建立了一個固定位置可以讓其他計算機來訪問你 ServerSocket server=new ServerSocket( );這里稍微要注意的是埠的分配必須是唯一的 因為埠是為了唯一標識每台計算機唯一服務的 另外埠號是從 ~ 之間的 前 個埠已經被Tcp/Ip 作為保留埠 因此你所分配的埠只能是 個之後的 好了 我們有了固定位置 現在所需要的就是一根連接線了 該連接線由客戶方首先提出要求 因此Java同樣提供了一個Socket對象來對其進行支持 只要客戶方創建一個Socket的實例對象進行支持就可以了 Socket client
=new Socket(InetAddress getLocalHost() );客戶機必須知道有關伺服器的IP地址 對於著一點Java也提供了一個相關的類InetAddress 該對象的實例必須通過它的靜態方法來提供 它的靜態方法主要提供了得到本機IP 和通過名字或IP直接得到InetAddress的方法
上面的方法基本可以建立一條連線讓兩台計算機相互交流了 可是數據是如何傳輸的呢?事實上I/O操作總是和網路編程息息相關的 因為底層的網路是繼續數據的 除非遠程調用 處理問題的核心在執行上 否則數據的陸帆交互還是依賴於IO操作的 所以你也必須導入java io這個包 java的IO操作也不復雜 它提供了針對於位元組流和Unicode的讀者和寫者 然後也提供了一個緩沖用於數據的讀寫
BufferedReader in=new BufferedReader(new InputStreamReader(server getInputStream()));
PrintWriter out=new PrintWriter(server getOutputStream());
上面兩句就是建立緩沖並把原始的位元組流轉變為Unicode可以操作 而原始的位元組流來源於Socket的兩個方法 getInputStream()和getOutputStream()方 分別用來得到輸入和輸出 那麼現在有了基本的模型和基本的操作工具 我們可以做一個簡單的Socket常式了
服務方:
import java io *;
import *;
public class MyServer {
public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket( );
Socket client=server accept();
BufferedReader in=new BufferedReader(new InputStreamReader(client getInputStream()));
迅型PrintWriter out=new PrintWriter(client getOutputStream());
while(true){
String str=in readLine();
System out println(str);
out println( has receive );
out flush();
if(str equals( end ))
break;
}
client close();
}
}
這個程序的主要目的在於伺服器不斷接收客戶機所寫入的信息只到 客戶機發送 End 字元串就退出程序 並且伺服器也會做出 Receive 為回應 告知客戶機已接收到消息
客戶機代碼:
import *;
import java io *;
public class Client{
static Socket server;
public static void main(String[] args)throws Exception{
server=new Socket(InetAddress getLocalHost() );
BufferedReader in=new BufferedReader(new InputStreamReader(server getInputStream()));
PrintWriter out=new PrintWriter(server getOutputStream());
BufferedReader wt=new BufferedReader(new InputStreamReader(System in));
while(true){
String str=wt readLine();
out println(str);
out flush();
if(str equals( end )){
break;
}
System out println(in readLine());
}
server close();
}
}
客戶機代碼則是接受客戶鍵盤輸入 並把該信息輸出 然後輸出 End 用來做退出標識
這個程序只是簡單的兩台計算機之間的通訊 如果是多個客戶同時訪問一個伺服器呢?你可以試著再運行一個客戶端 結果是會拋出異常的 那麼多個客戶端如何實現呢?
其實 簡單的分析一下 就可以看出客戶和服務通訊的主要通道就是Socket本身 而伺服器通過accept方法就是同意和客戶建立通訊 這樣當客戶建立Socket的同時 伺服器也會使用這一根連線來先後通訊 那麼既然如此只要我們存在多條連線就可以了 那麼我們的程序可以變為如下:
伺服器:
import java io *;
import *;
public class MyServer {
public static void main(String[] args) throws IOException{
ServerSocket server=new ServerSocket( );
while(true){
Socket client=server accept();
BufferedReader in=new BufferedReader(new InputStreamReader(client getInputStream()));
PrintWriter out=new PrintWriter(client getOutputStream());
while(true){
String str=in readLine();
System out println(str);
out println( has receive );
out flush();
if(str equals( end ))
break;
}
client close();
}
}
}
這里僅僅只是加了一個外層的While循環 這個循環的目的就是當一個客戶進來就為它分配一個Socket直到這個客戶完成一次和伺服器的交互 這里也就是接受到客戶的 End 消息 那麼現在就實現了多客戶之間的交互了 但是 問題又來了 這樣做雖然解決了多客戶 可是是排隊執行的 也就是說當一個客戶和伺服器完成一次通訊之後下一個客戶才可以進來和伺服器交互 無法做到同時服務 那麼要如何才能同時達到既能相互之間交流又能同時交流呢?很顯然這是一個並行執行的問題了 所以線程是最好的解決方案
那麼下面的問題是如何使用線程 首先要做的事情是創建線程並使得其可以和網路連線取得聯系 然後由線程來執行剛才的操作 要創建線程要麼直接繼承Thread要麼實現Runnable介面 要建立和Socket的聯系只要傳遞引用就可以了 而要執行線程就必須重寫run方法 而run方法所做的事情就是剛才單線程版本main所做的事情 因此我們的程序變成了這樣:
import *;
import java io *;
public class MultiUser extends Thread{
private Socket client;
public MultiUser(Socket c){
this client=c;
}
public void run(){
try{
BufferedReader in=new BufferedReader(new InputStreamReader(client getInputStream()));
PrintWriter out=new PrintWriter(client getOutputStream());
//Mutil User but can t parallel
while(true){
String str=in readLine();
System out println(str);
out println( has receive );
out flush();
if(str equals( end ))
break;
}
client close();
}catch(IOException ex){
}finally{
}
}
public static void main(String[] args)throws IOException{
ServerSocket server=new ServerSocket( );
while(true){
//transfer location change Single User or Multi User
MultiUser mu=new MultiUser(server accept());
mu start();
}
}
}
lishixin/Article/program/Java/hx/201311/27013
Ⅲ java中的socket是什麼意思
所謂socket通常也稱作"套接字",用於描述IP地址和埠,是一個通信鏈的句柄。應用程序通常通過"套接字"向網路發出請求或者應答網路請求。x0dx0a以J2SDK-1.3為例,Socket和ServerSocket類庫位於java.net包中。ServerSocket用於伺服器端,Socket是建立網路連接時使用的。在連接成功時,應用程序兩端都會產生一個Socket實例,操作這個實例,完成所需的會話。對於一個網路連接來說,套接字是平等的,並沒有差別,不因為在伺服器端或在客戶端而產生不同級別。不管是Socket還是ServerSocket它們的工作都是通過SocketImpl類及其子類完成的。x0dx0a重要的Socket API:x0dx0ajava.net.Socket繼承於java.lang.Object,有八個構造器,其方法並不鬧李多,下面介紹使用最頻繁的三個方法,其它方法大家可以見JDK-1.3文檔。x0dx0a. Accept方法用於產生"阻塞",直到接受到一個連接,並且返回一個客戶端的Socket對象實例。"阻塞"是一個術語,它使程序運行暫時"停留"在這個地方,直到一個會話產生,然後程序繼續;通常"阻塞"是由循環產生的。x0dx0a. getInputStream方法獲得網路連接輸入,同時返回一個InputStream對象實例。x0dx0a. getOutputStream方法連接的另一端將得到輸入,同時返回一個OutputStream對象實例。x0dx0a注意:其中getInputStream和getOutputStream方法均會產生一個IOException,它必須被捕獲,因為它們返回的流對象,通常都會被另一個流對象使用。x0dx0a2ServerSocket類例子編輯x0dx0ax0dx0apackage com.lanber.socket;x0dx0aimport java.io.DataInputStream;x0dx0aimport java.io.DataOutputStream;x0dx0aimport java.io.IOException;x0dx0aimport java.net.ServerSocket;x0dx0aimport java.net.Socket;x0dx0apublic class ServerDemo {x0dx0a/**x0dx0a* 注意:Socket的發送與接收是需要同步進行的,即客戶端發送一條信息,伺服器必需先接收這條信息,x0dx0a* 而後才可以碰吵向客戶端發送信息,否則將會有運行時出錯。x0dx0a* @param argsx0dx0a*/笑彎侍x0dx0apublic static void main(String[] args) {x0dx0aServerSocket ss = null;x0dx0atry {x0dx0ass = new ServerSocket(8888);x0dx0a//伺服器接收到客戶端的數據後,創建與此客戶端對話的Socketx0dx0aSocket socket = ss.accept();x0dx0a//用於向客戶端發送數據的輸出流x0dx0aDataOutputStream dos = new DataOutputStream(socket.getOutputStream());x0dx0a//用於接收客戶端發來的數據的輸入流x0dx0aDataInputStream dis = new DataInputStream(socket.getInputStream());x0dx0aSystem.out.println("伺服器接收到客戶端的連接請求:" + dis.readUTF());x0dx0a//伺服器向客戶端發送連接成功確認信息x0dx0ados.writeUTF("接受連接請求,連接成功!");x0dx0a//不需要繼續使用此連接時,關閉連接x0dx0asocket.close();x0dx0ass.close();x0dx0a} catch (IOException e) {x0dx0ae.printStackTrace();x0dx0a}x0dx0a}x0dx0a}x0dx0ax0dx0a3客戶端的例子編輯x0dx0apackage com.lanber.socket;x0dx0aimportjava.io.DataInputStream;x0dx0aimport java.io.DataOutputStream;x0dx0aimportjava.io.IOException;x0dx0aimport java.io.OutputStream;x0dx0aimport java.net.Socket;x0dx0aimport java.net.UnknownHostException;x0dx0apublic class ClientDemo {x0dx0a/**x0dx0a* @param argsx0dx0a*/x0dx0apublic static void main(String[] args) {x0dx0aSocket socket = null;x0dx0atry {x0dx0asocket = new Socket("localhost",8888);x0dx0a//獲取輸出流,用於客戶端向伺服器端發送數據x0dx0aDataOutputStream dos = new DataOutputStream(socket.getOutputStream());x0dx0a//獲取輸入流,用於接收伺服器端發送來的數據x0dx0aDataInputStream dis = new DataInputStream(socket.getInputStream());x0dx0a//客戶端向伺服器端發送數據x0dx0ados.writeUTF("我是客戶端,請求連接!");x0dx0a//列印出從伺服器端接收到的數據x0dx0aSystem.out.println(dis.readUTF());x0dx0a//不需要繼續使用此連接時,記得關閉哦x0dx0asocket.close();x0dx0a} catch (UnknownHostException e) {x0dx0ae.printStackTrace();x0dx0a} catch (IOException e) {x0dx0ae.printStackTrace();x0dx0a}x0dx0a}x0dx0a}
Ⅳ Java Socket如何清空接收緩沖區的內容
java.io.InputStream
int available()Returns an estimate of the number of bytes that can be read (or
skipped over) from this input stream without blocking by the next
invocation of a method for this input stream.
skip(long n)Skips over and discards n bytes of data from this input
stream.