摘要:上,數據按有限大小的包傳輸,這些包成為數據報,每個數據報包含一個首部和一個有效載荷。不過,由于數據報長度有限,通常必須將數據分解為多個包,再在目的地重新組合。這兩個構造函數,在返回之前會與遠程主機建立一個活動的網絡連接。
Internet上,數據按有限大小的包傳輸,這些包成為數據報(datagram),每個數據報包含一個首部(header)和一個有效載荷(payload)。首部包含包發送到的地址和端口、包來自的地址和端口、檢測數據是否被破壞的校驗和,以及用于保證可靠傳輸的各種其他管理信息。
有效載荷包含數據本身。
不過,由于數據報長度有限,通常必須將數據分解為多個包,再在目的地重新組合。也有可能一個包或多個包在傳輸中丟失或遭到破壞,需要重傳。或者包亂序到達,需要重新排序。所有這些(將數據分解為包、生成首部、解析入站包的首部、跟蹤哪些包已經收到而哪些沒有收到等)是很繁重的工作,需要大量復雜的代碼。
Socket幫你掩蓋了這些底層細節,如錯誤檢測、包大小、包分解、包重傳、網絡地址等。Socket允許程序員將網絡連接看作是另外一個可以讀寫字節的流。
Socket是兩臺主機之間的一個連接,它可以完成7個基本操作:
1)連接遠程主機
2)發送數據
3)接收數據
4)關閉連接
5)綁定端口
6)監聽入站數據
7)在綁定端口上接受來自遠程機器的連接
一旦建立了socket連接,就可以使用輸入輸出流,這個連接是全雙工的(full-duplex),兩臺主機都可以同時發送和接收數據。
SMTP是服務器之間或郵件客戶端與服務器之間傳輸電子郵件所用的協議。
半關閉Socket:close方法同時關閉Socket的輸入流和輸出流,如果只希望關閉連接的一半(輸入/輸出),調用shutdownInput或shutdownOutput方法即可。這兩個方法并不關閉Scoket,實際上,它會調整與Socket連接的流,使它認為已經到了流的末尾。關閉輸入之后,再讀取輸入流會返回-1,關閉輸出流之后再寫入Socket則會拋出一個IOException異常。
即使半關閉了連接,或者將連接的兩半都關閉了,使用結束后還是需要關閉該Socket。shutdown只是影響了socket流,并不釋放與socket關聯的資源,如占用的端口等。
java.net.Socket是Java完成客戶端TCP操作的基礎類,它使用原生代碼與主機操作系統的本地TCP棧進行通信。
public Socket(String host, int port) throws UnknownHostException, IOException
public Socket(InetAddress host, int port) throws IOException
這兩個構造函數,在返回之前會與遠程主機建立一個活動的網絡連接。port在1~65535之間。
public Socket()
public Socket(Proxy proxy)
protected Socket(SocketImpl impl)
這三個函數可以創建未連接的Socket。
public Socket(String host, int port, InetAddress interface, int localPort)
throws IOException, UnknownHostException
public Socket(InetAddress host, int port, InetAddress interface, int localPort)
throws IOException
這兩個構造函數可以用來指定從哪個接口和端口連接。
SocketAddress
SocketAddress表示一個連接端點,理論上可以用于TCP和非TCP socket。實際上只支持TCP/IP Socket。
SocketAddress主要是為了暫時的socket連接信息(如IP地址和端口)提供一個方便的存儲,即使最初的socket已斷開并被垃圾回收,這些信息也可以重用來創建新的Socket。
boolean connected = socket.isConnected() && ! socket.isClosed();
isConnected表示是否連接過一個遠程主機,即使socket已經關閉,因而要判斷socket是否打開著的,還要判斷是否已經關閉了。
Socket選項 1)TCP_NODELAY設置為true,可確保包會盡可能快地發送,而不論包的大小。
正常情況下,小數據包在發送前會組合為更大的包,在發送另一個包之前,本地主機要等待遠程系統對前一個包的確認,這稱為Nagle算法。
Nagle算法的問題是如果遠程系統沒有足夠快地將確認發送回本地系統,那么依賴于小數據量信息穩定傳輸的應用程序會變慢。對于網絡或游戲等計算機應用程序(服務器需要實時跟蹤客戶端鼠標的移動),這個問題尤為嚴重,在一個相當慢的網絡中,即使簡單地打字也會由于持續的緩沖而變得太慢。設置為true,可以關閉這種緩沖模式,這樣素有包一旦就緒就會發送。
2)SO_LINGER指定了Socket關閉時如何處理尚未發送的數據報,默認情況下,close方法將立即返回,但系統仍然會嘗試發送剩余的數據,如果延遲時間設置為0,那么當Socket關閉時,所有未發送的數據包都將被丟棄,如果SO_LINGER打開而且延遲時間設置為任意正數,close方法會阻塞指定的時間,等待發送數據和接收確認。指定時間一過,Socket關閉,所有剩余的數據都不會發送,也不會接收確認。
返回-1表示該選項被禁用,會根據需要用更多的時間發送剩余的數據。
正常情況下,嘗試從Socket讀取數據時,read()調用會阻塞盡可能長的時間來得到足夠的字節。設置timeout確保這個調用會阻塞的時間不會超過指定的閾值,如果超出則拋異常,但是Socket仍然是連接的,可以再次嘗試肚餓去這個Socket,下一次調用可能會成功。
0表示無限超時。
TCP使用緩沖區來提升網絡性能,較大的緩沖區會提升快速連接(比如10M/s)的性能,而較慢的撥號連接利用較小的緩沖區會有更好地表現。
一般來講,傳輸連續的大數據塊時(在ftp和http中較為常見),可以從大緩沖區收益,而對于交互式會話的小數據量傳輸(比如telnet和很多游戲),大緩沖區則沒有多大幫助。如今128K字節已經是一個常見的默認設置。
可以達到的最大帶寬=緩沖區大小/延遲。例如,xp上,假設兩個主機之間的延遲為500ms,xp上的緩沖區大小為17520字節,則帶寬=17520/0.5=273.75kb/s。這是Socket的最大速度,而不論網絡速度有多快。對于一個撥號連接來說,這樣的速度已經很快了。
可以通過減少延遲來提升速度,不過,延遲與網絡硬件有關,另外還取決于你的應用控制之外的其他一些因素。
如果把緩沖區從17520字節提升到128K,則最大帶寬會增加到2Mb/s,如果加到256K時,最大帶寬會增大到4Mb/s。
當然網絡本身對最大帶寬也是有限制的,如果將緩沖區設置的過高,程序會試圖以過高的速度發送和接收數據,而網絡來不及處理,這就會導致擁塞、丟包和性能下降。因此,要得到最大帶寬,需要讓緩沖區大小與連接的延遲匹配,是它稍小于網絡的帶寬。
可以用ping去檢測主機的延遲。
SO_RCVBUF控制用于網絡輸入的建議的接收緩沖區的大小,雖然可以獨立地設置接收和發送緩沖區的大小,但是實際上緩沖區通常會設置為二者中較小的一個。
Linux系統通常指定一個最大緩沖區大小,一般是64KB或256KB,而且不允許任何socket有更大的緩沖區。
一般情況下,如果你發送你的應用不能充分利用可用帶寬(例如,你有一個25Mb/s的Internet連接,但是數據傳輸速率僅為1.5Mb/s),那么可以試著增加緩沖區的大小;相反,如果存在丟包和擁塞現象,則要減少緩沖區大小。
不過,大部分情況,除非網絡在某個方向上負載過大,否則默認值就很合適。具體來說,現代操作系統使用TCP窗口縮放來動態調整緩沖區的大小,以適應網絡。
一般經驗是,除非你檢測到某個問題,否則不要進行調整。一般調整操作系統的最大緩沖區比在Java里頭調整單個socket的緩沖區大小效益要高。
5)SO_KEEPALIVE如果打開這個,客戶端偶爾會通過一個空閑連接發送一個數據包(一般兩小時一次),以確保服務器沒有崩潰。如果服務器沒能響應這個包,客戶端會持續嘗試11分鐘多的時間,直到接收到響應為止。如果在12分鐘內未收到響應,則客戶端就關閉socket。如果不打開這個,不活動的客戶端可能會永遠存在下去,而不會注意到服務器是否已經崩潰。
6)OOBINLINETCP包括一個可以發送單字節帶外(Out Of Band,OOB)緊急數據的特性。這個數據會立即發送,此外,當接收方收到緊急數據時會得到通知,在處理其他已收到的數據之前可以選擇先處理這個緊急數據(必要時flush當前緩沖區)。
Java里對應的方法是sendUrgentData
默認情況下,Java會忽略從Socket接收的緊急數據,如果希望接收到正常數據中的緊急數據,需要setOOBInline為true。一旦開啟,到達的任何緊急數據將以正常方式放在Socket的輸入流中等待讀取。
7)SO_REUSEADDR一個Socket關閉時,可能不會立即釋放本地端口,尤其是當Socket關閉時若仍有一個打開的連接,就不會釋放本地端口,有時會等待一小段時間,確保接收到所有要發送到這個端口的延遲數據包,Socket關閉時這些數據包可能仍在網絡上傳輸,系統不會對接收到的延遲包做任何處理,只是希望確保這些數據不會意外地傳入綁定到同一端口的新進程。
如果使用隨機端口,則問題不大,但是如果Socket綁定到一個已知的端口,可能會有問題,因為這會阻止所有其他Socket同時使用這個端口,如果開啟這個參數(默認是關閉),則允許另外一個Socket綁定到這個端口,即使此時仍有可能存在前一個Socket未接收的數據。
setReuseAddress必須在綁定新Socket之前調用。只有之前連接的Socket和重用老地址的新Scoket的這個值都設置為true,才能生效。
8)IP_TOS不同類型的Internet服務對性能有不同的需求,比如視頻要求相對較高的帶寬和較短的延遲,而email可以通過較低帶寬的連接傳遞等。
服務類型存儲在IP首部中的一個名為IP_TOS的8位字段中。在Java中使用setTrafficClass來設定,java里頭是0-255,但是TCP首部要求是8位,因而只能使用int的低字節。
Socket異常
1)BindException,端口被占用或沒有權限使用該端口
2)ConnectException,連接遠程主機被拒絕(遠程主機忙或者沒有進程監聽該端口)
3)NoRouteToHostException,連接超時
4)ProtocolException,違反TCP/IP規定
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/65923.html
SSL,Secure Sockets Layer,安全Socket層TLS,Transport Layer Security,傳輸層安全協議 package network.secure; import java.io.*; import javax.net.ssl.*; public class HTTPSClient { public static void main(Strin...
摘要:單個請求范圍之外的異常可能會關閉服務器。客戶端可能超時或崩潰,用戶可能取消事務,網絡可能在流量高峰期間癱瘓,黑客可能發動拒絕服務攻擊。如果默認長度不夠大,一些的構造函數還允許改變這個隊列的長度,不能不能超過操作系統支持的最大值。 ServerSocket的生命周期 一個ServerSocket的基本生命周期:1)使用一個ServerSocket構造函數在一個特定端口創建一個新的Serv...
閱讀 2434·2021-10-11 10:57
閱讀 1285·2021-10-09 09:59
閱讀 2000·2019-08-30 15:53
閱讀 3217·2019-08-30 15:53
閱讀 1014·2019-08-30 15:45
閱讀 742·2019-08-30 15:44
閱讀 3450·2019-08-30 14:24
閱讀 956·2019-08-30 14:21