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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

java socket/Serversocket编程详解(中/英文)

發(fā)布時間:2025/4/5 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java socket/Serversocket编程详解(中/英文) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

socket /套接字?

??? Sockets let you send raw streams of bytes back and forth between two computers, giving you fairly low-level access to the TCP/IP protocol. See the File I/O Amanuensis for sample code to do that. In TCP/IP each computer has a name, such as roedy.mindprod.com. However, various TCP/IP programs could be running on that computer. Each Socket gets a assigned a number called a port. The HTTP server would usually be assigned 80. DbAnywhere is usually 8889. This way you can specify which service on the local or remote machine you want to connect with. The Socket is specified like this: roedy.mindprod.com:8889.?



???? socket提供了在主機之間傳遞原始字節(jié)流的功能,以比較底層的方式訪問tcp/ip協(xié)議層.可以類似訪問文件i/o的方式實現(xiàn)這一功能(在unix 中,系統(tǒng)資源是以文件的方式進行訪問的,其中也包括網(wǎng)絡資源).tcp/ip協(xié)議規(guī)定,每臺主機都有一個名稱,例如 roedy.mindprod.com.然而,同一臺主機上有可能同時運行很多tcp/ip程序.每個socket被指派了一個叫做端口的數(shù)字以加以區(qū)分不同的應用或者連接.http應用服務器的端口一般被指定為80,DbAnywhere通常指定為8889.我們通過這種方式區(qū)分你向遠程或者本地主機請求連接的服務.一個socket被定義為 地址:端口, 例如 roedy.mindprod.com:8889?


??? Flush / 刷新?


??? If you write to a Socket, you usually need to call flush to force the data out onto the net. If you fail to do that, you could wait forever for a response because your complete query was never sent. You don’t need flush if you are sending a steady stream of data that will push earlier data out onto the net.?



???? 如果向一個socket寫入數(shù)據(jù),通常需要調(diào)用flush方法去把數(shù)據(jù)發(fā)送到網(wǎng)絡.如果操作失敗,可能由于完整的請求信息未曾發(fā)送成功而導致持續(xù)等待響應.如果使用穩(wěn)定的數(shù)據(jù)流的方式,不需要調(diào)用flush方法,因為數(shù)據(jù)流會自動把先前的數(shù)據(jù)發(fā)送到網(wǎng)絡.?



??? Blocking Read / 讀堵塞?

?? If you read from a Socket, you can hang waiting forever if you use a blocking read. Socket.setSoTimeout controls the timeout. The read will eventually die when the Socket connection fails. This will happen when:?

??????? * You close the Socket at this end.?
??????? * The far end sends a disconnect signal.?
??????? * TCP cannot get an acknowlegement for packets it has sent, even after several retransmissions. These packets could either be data sent by the application, or keep-alive messages (if keep-alive has been turned on). Don’t confuse this with the meaningless HTTP Keep-Alive parameter.?



????? 由socket讀取數(shù)據(jù)時,如果使用堵塞的讀操作,可能會導致永久地等待.Socket的setSoTimeout方法 控制了超時的期限.在socket連接失敗的情況下,讀取數(shù)據(jù)的操作最終會被停止.?

這種情況通常發(fā)生在以下幾種情況:?

??????? 1.本地關(guān)閉了socket,?

??????? 2.遠程主機/終端發(fā)送了斷開連接的信號,?

??????? 3.tcp協(xié)議實現(xiàn)在嘗試多次重發(fā)數(shù)據(jù)仍無法獲得對方針對已發(fā)送數(shù)據(jù)包的確認信息,或者無法獲得keep-alive的信息(如果tcp協(xié)議的keep- alive選項已經(jīng)被啟用).另外不要和http協(xié)議的keep-alive參數(shù)相混淆.(http的keep-alive選項是指客戶端與服務器之間建立有效的長連接,避免了重復建立連接的消耗,尤其對提供靜態(tài)資源訪問的網(wǎng)站能夠很大的提高訪問效率)?



??? Timeouts /超時?


??? Java offers Socket.setSoTimeout to control how long you are willing to wait for a read to complete and Socket.setSoLinger to control how long it lingers, (waits to close when there are still unsent data). When you shutdown, the other end should continue to read any buffered data to let the other end close before closing itself. setSoTimeout has no effect on how long you are willing to wait for a write (how long you are willing to wait for the other end to accept data), just on how long you are willing to wait for the other end to produce data.?

??? To add to the misery, Windows partially ignores the timeout. On connect, the JVM tries to resolve the hostname to IP/port. Windows tries a netbios ns query on UDP port 137 with a timeout of 1.5 seconds, ignores any ICMP port unreachable packets and repeats this two more times, adding up to a value of 4.5 seconds. I suggest putting critical hostnames in your HOSTS file to make sure they are resolved quickly. Another possibility is turning off NETBIOS altogether and running pure TCP/IP on your LAN.?



??? socket的java實現(xiàn)接口提供了setSoTimeout方法設(shè)置希望等待完成讀取操作的時間期限,提供setSoLinger方法控制關(guān)閉等待期限(等待尚未發(fā)送的數(shù)據(jù),然后關(guān)閉連接). 當一方關(guān)閉連接時,另一方仍會在讀取到緩沖區(qū)中的通知關(guān)閉連接的數(shù)據(jù)以后關(guān)閉連接(這句話不知道這樣翻譯是否準確,不過實際操作應該是這樣的,可以這樣理解,當一端單方面關(guān)閉連接的時候,應該通知另一方你已經(jīng)關(guān)閉連接,以便對方獲悉并且關(guān)閉連接).setSoTimeout選項對等待完成寫操作的期限沒有影響(等待對方對方接收數(shù)據(jù)的期限),只和等待對方產(chǎn)生數(shù)據(jù)的期限有關(guān).(setSoTimeout和對方發(fā)送響應數(shù)據(jù)是否超時有關(guān)和對方何時接收數(shù)據(jù)沒有關(guān)系).?



???? 比較令人苦悶的是,windows系統(tǒng)不負責任地忽略超時.對于一個連接.java虛擬機努力將域名解析為ip地址和端口號.而windows使用udp 的137端口向域名解析服務器發(fā)送域名解析查詢,超時設(shè)為1.5秒.忽略了任何的icmp端口不可訪問的數(shù)據(jù)包并且連續(xù)再重復發(fā)送兩次相同的請求(一共是三次).總計需要等待4.5秒.因此強烈建議把常用的域名地址和對應的ip地址和端口寫在hosts文件中以確??梢匝杆俳馕?另外就是在局域網(wǎng)完全中關(guān)閉windows的NETBIOS服務,完全使用tcp/ip訪問資源.?



??? Disconnet Detection / 探測連接關(guān)閉?


??? Since TCP/IP sends no packets except when there is traffic, without Socket.setKeepAlive( true ), it has no way of noticing a disconnect until you start trying to send (or to a certain extent receive) traffic again. Java has the Socket.setKeepAlive( true ) method to ask TCP/IP to handle heartbeat probing without any data packets or application programming. Unfortunately, you can’t tell it how frequently to send the heartbeat probes. If the other end does not respond in time, you will get a socket exception on your pending read. Heartbeat packets in both directions let the other end know you are still there. A heartbeat packet is just an ordinary TCP/IP ack packet without any piggybacking data.?



??? 當網(wǎng)絡繁忙的時候,tcp/ip無法發(fā)送數(shù)據(jù)包.如果沒有設(shè)定socket的setKeepAlive為true,我們無法獲悉一個連接已經(jīng)關(guān)閉除非試圖再次進行發(fā)送操作(或者進行某些接收操作).java通過設(shè)定socket的setKeepAlive為true的方式要求tcp/ip協(xié)議進行心跳檢測,不需要發(fā)送任何數(shù)據(jù)包或者應用級別的編程.然而不幸地是你無法肯定tcp/ip以怎樣的頻率發(fā)送心跳探測信號.如果另一方無法及時響應,當你試圖進行讀取操作的時候就會產(chǎn)生socket的異常.心跳包使雙方都能獲知對方是否保持連接.心跳包只是一個普通的tcp/ip的ack報文不需要搭載任何的其他數(shù)據(jù).?


??? When the applications are idling, your applications could periodically send tiny heartbeat messages to each other. The receiver could just ignore them. However, they force the TCP/IP protocol to check if the other end is still alive. These are not part of the TCP/IP protocol. You would have to build them into your application protocols. They act as are-you-still-alive? messages. I have found Java’s connection continuity testing to be less that 100% reliable. My bullet-proof technique to detect disconnect is to have the server send an application-level heartbeat packet if it has not sent some packet in the last 30 seconds. It has to send some message every 30 seconds, not necessarily a dummy heartbeat packet. The heartbeat packets thus only appear when the server is idling. Otherwise normal traffic acts as the heartbeat. The Applet detects the lack of traffic on disconnect and automatically restarts the connection. The downside is your applications have to be aware of these heartbeats and they have to fit into whatever other protocol you are using, unlike relying on TCP/IP level heartbeats.?



???? 當應用處于空閑狀態(tài)的時候,你的應用可以間斷地向彼此發(fā)送小的心跳信息.接收者可以完全忽視它們,但是它們強制tcp/ip協(xié)議去核實另一方是否存活.這不是tcp/ip協(xié)議通信規(guī)范的一部分,你需要建立自己的心跳協(xié)議,例如 發(fā)送內(nèi)容為' are-you-still-alive? '的信息,原作者通過測試發(fā)現(xiàn)java的連接持續(xù)性并非100%的可靠.他的銀彈技術(shù)是通過服務端每隔30秒發(fā)送一個應用級別的心跳包,如果最近30秒內(nèi)沒有接收到任何數(shù)據(jù)包.服務器必須每隔30秒發(fā)送一個數(shù)據(jù)包,不一定必須是傀儡的心跳數(shù)據(jù)包.心跳數(shù)據(jù)包只當服務器空閑的時候才會產(chǎn)生.否則的話,普通的網(wǎng)絡通信就可以替代心跳數(shù)據(jù)包的功能.applet探測發(fā)現(xiàn)由于斷開連接導致的通信中斷后就會重新建立連接.負面影響是你的應用必須時時關(guān)注這些心跳狀態(tài),并且如果你使用其它網(wǎng)絡協(xié)議你也要實現(xiàn)相應的心跳協(xié)議,不同余依賴于tcp/ip層的心跳.?


??? However, it is simpler to use the built-in Socket.setKeepAlive( true ) method to ask TCP/IP to handle the heartbeat probing without any data packets or application programming. Each end with nothing to say just periodically sends an empty data packet with its current sequence, acknowledgement and window numbers.?


?? 然而,使用socket內(nèi)置的setKeepAlive(true)方法去要求tcp/ip進行心跳探測不使用任何數(shù)據(jù)包或者應用級別地編程實現(xiàn)看起來更加容易一些.每個終端只需間歇地發(fā)送一個包含當前序列的空的數(shù)據(jù)包,確認信息和滑動窗口號就可以了.?


??? The advantage of application level heartbeats is they let you know the applications at both ends are alive, not just the communications software.?



??? 應用級別的心跳優(yōu)點在于它們能夠使你了解兩端的應用都是否存活,而不在于只是通信軟件.?



Server Side Socketing /服務器端套接字?


??? For a server to accept connections from the outside world, first it opens a ServerSocket on a port, but not connected to any client in particular.?



??? 對于一個接收外部連接的服務器,首先在某個沒有連接任何客戶端的端口上開啟一個serversocket,代碼如下?


??? ServerSocket serverSocket = new ServerSocket( port );?

??? Then it calls accept, which blocks until a call comes in.?

??? Socket clientSocket = serverSocket.accept();?

??? At that point a new ordinary Socket gets created that is connected to the incoming caller. Usually the server would spin off a Thread, or assign a Thread from a pool to deal with the new Socket and loop back to do another accept.?



???? 當接收到一個請求時會新建一個的普通的socket,通常服務器會啟動一個線程或者由線程池中取出一個線程處理新產(chǎn)生的socket,然后循環(huán)處理下一個請求.?


??? You can set up your miniature server even if you don’t have a domain name. They can get to you by name: ip:port e.g. 65.110.21.43:2222. Even if your are behind a firewall, you use the external facing IP of the firewall. You must then configure your firewall to let incoming calls through and to direct them to the correct server on the lan.?



???? 即使你并不擁有一個域名,你也可以建立自己的服務器.他人可以通過ip地址和端口的方式( e.g. 65.110.21.43:2222)訪問你的服務器(如果在廣域網(wǎng)上這要求你擁有自己的固定ip,這一般比擁有域名的成本還要高,不過在局域網(wǎng)內(nèi)你可以嘗試局域網(wǎng)地址),如果你在處于防火墻保護的局域網(wǎng)內(nèi),你可以使用防火墻的對外ip.你必須配置你的防火墻以便請求數(shù)據(jù)包可以通過并且訪問局域網(wǎng)內(nèi)正確的服務器.?



??? Flow Control / 流控制?


??? With Socket.setReceiveBufferSize() you can hint to the underlying OS how much to buffer up incoming data. It is not obligated to listen to you. Don’t confuse this with the buffer on the BufferedInputStream. This is the lower level buffer on the raw socket. Large buffers are not always desirable. Using small buffers can tell the other end you are getting behind, and it won’t send data as quickly. If the data is real time, and the amount of data sent is variable depending on how fast you process it, large buffers mean you can get way behind and never catch up.?



???? 使用socket的setReceiveBufferSize()方法你可以告訴底層的操作系統(tǒng)緩存多大的接收數(shù)據(jù).但是這并非完全由你決定.不要將 socket的緩沖區(qū)和BufferedInputStream的緩沖區(qū)混淆.這是原始socket的底層的緩沖區(qū).過大的緩沖區(qū)并不總能很好地滿足需要.使用小的緩沖區(qū)能夠通知另一端你的處理速度已經(jīng)落后了,因此對方不會繼續(xù)馬上發(fā)送數(shù)據(jù)過來(大的緩沖區(qū),對方發(fā)送過來的數(shù)據(jù)有可能還沒有讀取并被處理,但還留有很大的空間,因此對方會繼續(xù)發(fā)送數(shù)據(jù)填滿余下的空間,但是有可能導致大量的數(shù)據(jù)堆積在緩沖區(qū)中無法處理,理想狀態(tài)是使用小的緩存區(qū),處理完當前數(shù)據(jù)后在接收,處理下一個數(shù)據(jù)).如果數(shù)據(jù)不是實時的,發(fā)送過來的數(shù)據(jù)量動態(tài)地依賴于處理數(shù)據(jù)的速度,過大的緩沖區(qū)會導致你處理的數(shù)據(jù)量一直落后于接收的數(shù)據(jù)量,并且永遠無法趕上.?


??? There is a mysterioous method Socket.setTcpNoDelay( true ) to "disable Nagle’s algorithm". As is typical, there is no explanation what Nagle’s algorinthm is. My TCP/IP text book makes no mention of it. If you are dealing with near real-time data then you may want to look into disabling Nagle’s algorithm. That algorithm attempts to ensure that TCP doesn’t send lots of undersized IP packets by buffering-up submitted data and keeping it for typically for a few milliseconds to see if you are going to give it some more data that could go into the same packet. I am not sure if flush is sufficient to send a packet on its way immediately.?



???? socket的setTcpNoDelay( true )很神秘地用來關(guān)閉Nagle算法.正如這里不解釋Nagle算法一樣,這里也不討論這個setTcpNoDelay方法. 如果你處理近乎實時的數(shù)據(jù),你可能會研究如何關(guān)閉Nagle算法.Nagle算法通過暫存已經(jīng)提交發(fā)送的數(shù)據(jù)包許多毫秒的時間以便判斷是否還需要向這個數(shù)據(jù)包寫入更多數(shù)據(jù),確保tcp不發(fā)送大量的長度過小的數(shù)據(jù)包.我不確定是否flush方法能夠充分地立即發(fā)送一個數(shù)據(jù)包.?



?? Graceful Shutdown / 優(yōu)雅地關(guān)閉?


??? If you simply close a socket, you can lose data that were previously sent but which have not yet been delivered. You may chop things off in mid message. So, how to shut down gracefully? My approach is this. When the client wants to shut down, it sends a close message. The server echos it back and on receipt of the close message, the client closes the socket. That way the client is guaranteed to be unhooked from waiting on a read, and you are guaranteed the server and client each recieved the last remaining messages before the socket was closed.?



???? 如果你簡單地關(guān)閉一個socket連接,你可能會丟失先前發(fā)送但并未抵達(交付)的數(shù)據(jù).這可能會導致數(shù)據(jù)不完整.所以,如果優(yōu)雅地關(guān)閉連接呢?作者的理論是:當客戶端試圖關(guān)閉連接時,它首先要發(fā)送一條關(guān)閉信息.服務器原樣返回關(guān)閉信息內(nèi)容和確認關(guān)閉信息(增加確認關(guān)閉信息的做法可能是為了避免發(fā)送超時的數(shù)據(jù)包返回給發(fā)送者,兩者內(nèi)容可能是相同的),客戶端收到確認信息后關(guān)閉連接.這時客戶端要確保解除等待讀取操作的狀態(tài),并且你要確??蛻舳撕头掌髟陉P(guān)閉前都收到了最后的信息.?




?

本篇文章觀點和例子來自 《Java網(wǎng)絡編程精解》, 作者為孫衛(wèi)琴, 出版社為電子工業(yè)出版社。

?

????? 在客戶/服務器通信模式中, 客戶端需要主動創(chuàng)建與服務器連接的 Socket(套接字), 服務器端收到了客戶端的連接請求, 也會創(chuàng)建與客戶連接的 Socket. Socket可看做是通信連接兩端的收發(fā)器, 服務器與客戶端都通過 Socket 來收發(fā)數(shù)據(jù).

?

這篇文章首先介紹Socket類的各個構(gòu)造方法, 以及成員方法的用法, 接著介紹 Socket的一些選項的作用, 這些選項可控制客戶建立與服務器的連接, 以及接收和發(fā)送數(shù)據(jù)的行為.

?

一. 構(gòu)造Socket

?

???? Socket的構(gòu)造方法有以下幾種重載形式:??

  • Socket()
  • Socket(InetAddress address, int port) throws UnknowHostException, IOException
  • Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException
  • Socket(String host, int port) throws UnknowHostException, IOException
  • Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException
  • ???? 除了第一個不帶參數(shù)的構(gòu)造方法以外, 其他構(gòu)造方法都會試圖建立與服務器的連接, 如果連接成功, 就返回 Socket對象; 如果因為某些原因連接失敗, 就會拋出IOException .

    ?

    1.1 使用無參數(shù)構(gòu)造方法, 設(shè)定等待建立連接的超時時間

    ???

    ??Socket socket = new Socket();
    ??SocketAddress remoteAddr = new InetSocketAddress("localhost",8000);
    ??socket.connect(remoteAddr, 60000); ?//等待建立連接的超時時間為1分鐘

    ?

    ????? 以上代碼用于連接到本地機器上的監(jiān)聽8000端口的服務器程序, 等待連接的最長時間為1分鐘. 如果在1分鐘內(nèi)連接成功則connet()方法順利返回; 如果在1分鐘內(nèi)出現(xiàn)某種異常, 則拋出該異常; 如果超過1分鐘后, 即沒有連接成功, 也沒有出現(xiàn)其他異常, 那么會拋出 SocketTimeoutException. Socket 類的 connect(SocketAddress endpoint, int?timeout) 方法負責連接服務器, 參數(shù)endpoint 指定服務器的地址, 參數(shù)timeout 設(shè)定超時數(shù)據(jù), 以毫秒為單位. 如果參數(shù)timeout 設(shè)為0, 表示永遠不會超時, 默認是不會超時的.?

    ?

    1.2?設(shè)定服務器的地址

    ?

    ??????除了第一個不帶參數(shù)的構(gòu)造方法, 其他構(gòu)造方法都需要在參數(shù)中設(shè)定服務器的地址, 包括服務器的IP地址或主機名, 以及端口:

    ??Socket(InetAddress address, int port)????????????? //第一個參數(shù)address 表示主機的IP地址
    ??Socket(String host, int port)??????????????????????????????//第一個參數(shù)host 表示主機的名字

    ?

    ????? InetAddress 類表示服務器的IP地址, InetAddress 類提供了一系列靜態(tài)工廠方法, 用于構(gòu)造自身的實例, 例如:

    ?

    ??//返回本地主機的IP地址
    ??InetAddress addr1 = InetAddress.getLocalHost();
    ??//返回代表 "222.34.5.7"的 IP地址
    ??InetAddress addr2 = InetAddress.getByName("222.34.5.7");
    ??//返回域名為"www.javathinker.org"的 IP地址
    ??InetAddress addr3 = InetAddress.getByName("www.javathinker.org");

    ?

    ?

    1.3 設(shè)定客戶端的地址

    ?

    ????? 在一個Socket 對象中, 即包含遠程服務器的IP 地址和端口信息, 也包含本地客戶端的IP 地址和端口信息. 默認情況下, 客戶端的IP 地址來自于客戶程序所在的主機, 客戶端的端口則由操作系統(tǒng)隨機分配. Socket類還有兩個構(gòu)造方法允許顯式地設(shè)置客戶端的IP 地址和端口:

    ?

    ??//參數(shù)localAddr 和 localPort 用來設(shè)置客戶端的IP 地址和端口
    ??Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException
    ??Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException

    ?

    ?????如果一個主機同時屬于兩個以上的網(wǎng)絡, 它就可能擁有兩個以上的IP 地址. 例如, 一個主機在Internet 網(wǎng)絡中的IP 地址為 "222.67.1.34", 在一個局域網(wǎng)中的IP 地址為 "112.5.4.3". 假定這個主機上的客戶程序希望和同一個局域網(wǎng)的一個服務器程序(地址為:"112.5.4.45: 8000")通信, 客戶端可按照如下方式構(gòu)造Socket 對象:

    ?????

    ??InetAddress remoteAddr1 = InetAddress.getByName("112.5.4.45");
    ??InetAddress localAddr1 = InetAddress.getByName("112.5.4.3");
    ??Socket socket1 = new Socket(remoteAddr1, 8000, localAddr1, 2345);?? //客戶端使用端口2345

    ?

    ?

    ?1.4 客戶連接服務器時可能拋出的異常

    ?

    ?????? 當Socket 的構(gòu)造方法請求連接服務器時, 可能會拋出下面的異常.

    • UnKnownHostException: 如果無法識別主機的名字或IP 地址, 就會拋出這種異常.
    • ConnectException: 如果沒有服務器進程監(jiān)聽指定的端口, 或者服務器進程拒絕連接, 就會拋出這種異常.
    • SocketTimeoutException: 如果等待連接超時, 就會拋出這種異常.
    • BindException: 如果無法把Socket 對象與指定的本地IP 地址或端口綁定, 就會拋出這種異常.

    ?????? 以上4中異常都是IOException的直接或間接子類.??????如圖2-1所示.

    ?

    ??????? IOException-------? UnknownHostException

    ????????????????????????????? |---- InterruptedIOException??-----------? SocketTimeoutException

    ????????????????????????????? |---- SocketException????????????? -----------? BindException

    ?????????????????????????????????????????????????????????????????????????????|----------? ConnectException

    ???????

    ??????????????????????????????????? 圖2-1 客戶端連接服務器時可能拋出的異常

    ?

    ?

    二. 獲取Socket 的信息

    ?

    ????

    ????? 在一個Socket 對象中同時包含了遠程服務器的IP 地址和端口信息, 以及客戶本地的IP 地址和端口信息. 此外, 從Socket 對象中還可以獲得輸出流和輸入流, 分別用于向服務器發(fā)送數(shù)據(jù), 以及接收從服務器端發(fā)來的數(shù)據(jù). 以下方法用于獲取Socket的有關(guān)信息.

    • getInetAddress(): 獲得遠程服務器的IP 地址.
    • getPort(): 獲得遠程服務器的端口.
    • getLocalAddress(): 獲得客戶本地的IP 地址.
    • getLocalPort(): 獲得客戶本地的端口.
    • getInputStream(): 獲得輸入流. 如果Socket 還沒有連接, 或者已經(jīng)關(guān)閉, 或者已經(jīng)通過 shutdownInput() 方法關(guān)閉輸入流, 那么此方法會拋出IOException.
    • getOutputStream(): 獲得輸出流, 如果Socket 還沒有連接, 或者已經(jīng)關(guān)閉,?或者已經(jīng)通過 shutdownOutput() 方法關(guān)閉輸出流, 那么此方法會拋出IOException.

    ?????這里有個HTTPClient 類的例子, 代碼我是寫好了, 也測試過了, 因為篇幅原因就不貼了. 這個HTTPClient 類用于訪問網(wǎng)頁?www.javathinker.org/index.jsp. 該網(wǎng)頁位于一個主機名(也叫域名)為?www.javathinker.org?的遠程HTTP服務器上,?它監(jiān)聽?80 端口. 在HTTPClient 類中, 先創(chuàng)建了一個連接到該HTTP服務器的Socket對象, 然后發(fā)送符合HTTP 協(xié)議的請求, 接著接收從HTTP 服務器上發(fā)回的響應結(jié)果.

    ?

    三. 關(guān)閉Socket

    ?

    ???? 當客戶與服務器的通信結(jié)束, 應該及時關(guān)閉Socket , 以釋放Socket 占用的包括端口在內(nèi)的各種資源. Socket 的 close() 方法負責關(guān)閉Socket. 當一個Socket對象被關(guān)閉, 就不能再通過它的輸入流和輸出流進行I/O操作, 否則會導致IOException.

    ?

    ????? 為了確保關(guān)閉Socket 的操作總是被執(zhí)行, 強烈建議把這個操作放在finally 代碼塊中:

    ?

    ???Socket socket = null;
    ???try{
    ????????socket = new Socket(www.javathinker.org,80);
    ????????//執(zhí)行接收和發(fā)送數(shù)據(jù)的操作
    ????????..........
    ???}catch(IOException e){
    ?????????e.printStackTrace();
    ???}finally{
    ????????try{
    ?????????????if(socket != null)? socket.close();
    ???????}catch(IOException e){e.printStackTrace();}
    ???}

    ?

    ???

    ? ??Socket 類提供了3 個狀態(tài)測試方法.

    • isClosed(): 如果Socket已經(jīng)連接到遠程主機, 并且還沒有關(guān)閉, 則返回true , 否則返回false .
    • isConnected(): 如果Socket曾經(jīng)連接到遠程主機, 則返回true , 否則返回false .
    • isBound(): 如果Socket已經(jīng)與一個本地端口綁定, 則返回true , 否則返回false .

    ???? 如果要判斷一個Socket 對象當前是否處于連接狀態(tài), 可采用以下方式:

    ?

    ??????boolean isConnected = socket.isConnected() && !socket.isClosed();??????????????????????????????????????

    ?

    ?

    四. 半關(guān)閉Socket

    ?

    ???? 進程A 與進程B 通過Socket 通信, 假定進程A 輸出數(shù)據(jù), 進程B 讀入數(shù)據(jù). 進程A 如何告訴進程B 所有數(shù)據(jù)已經(jīng)輸出完畢? 下文略......

    ?

    ?

    五. 設(shè)置Socket 的選項

    ?

    ???? Socket 有以下幾個選項.

    • TCP_NODELAY: 表示立即發(fā)送數(shù)據(jù).
    • SO_RESUSEADDR: 表示是否允許重用Socket 所綁定的本地地址.
    • SO_TIMEOUT: 表示接收數(shù)據(jù)時的等待超時數(shù)據(jù).
    • SO_LINGER: 表示當執(zhí)行Socket 的 close()方法時, 是否立即關(guān)閉底層的Socket.
    • SO_SNFBUF: 表示發(fā)送數(shù)據(jù)的緩沖區(qū)的大小.
    • SO_RCVBUF: 表示接收數(shù)據(jù)的緩沖區(qū)的大小.
    • SO_KEEPALIVE: 表示對于長時間處于空閑狀態(tài)的Socket , 是否要自動把它關(guān)閉.
    • OOBINLINE: 表示是否支持發(fā)送一個字節(jié)的TCP 緊急數(shù)據(jù).

    ?

    5.1 TCP_NODELAY 選項

    • 設(shè)置該選項: public void setTcpNoDelay(boolean on) throws SocketException
    • 讀取該選項: public boolean getTcpNoDelay() throws SocketException

    ?????默認情況下, 發(fā)送數(shù)據(jù)采用Negale 算法. Negale 算法是指發(fā)送方發(fā)送的數(shù)據(jù)不會立即發(fā)出, 而是先放在緩沖區(qū), 等緩存區(qū)滿了再發(fā)出. 發(fā)送完一批數(shù)據(jù)后, 會等待接收方對這批數(shù)據(jù)的回應, 然后再發(fā)送下一批數(shù)據(jù). Negale 算法適用于發(fā)送方需要發(fā)送大批量數(shù)據(jù), 并且接收方會及時作出回應的場合, 這種算法通過減少傳輸數(shù)據(jù)的次數(shù)來提高通信效率.

    ?

    ???? 如果發(fā)送方持續(xù)地發(fā)送小批量的數(shù)據(jù), 并且接收方不一定會立即發(fā)送響應數(shù)據(jù), 那么Negale 算法會使發(fā)送方運行很慢. 對于GUI 程序, 如網(wǎng)絡游戲程序(服務器需要實時跟蹤客戶端鼠標的移動), 這個問題尤其突出. 客戶端鼠標位置改動的信息需要實時發(fā)送到服務器上, 由于Negale 算法采用緩沖, 大大減低了實時響應速度, 導致客戶程序運行很慢.

    ?

    ????? TCP_NODELAY 的默認值為 false, 表示采用 Negale 算法. 如果調(diào)用setTcpNoDelay(true)方法, 就會關(guān)閉 Socket的緩沖, 確保數(shù)據(jù)及時發(fā)送:

    ?

    ?????? if(!socket.getTcpNoDelay()) socket.setTcpNoDelay(true);???????????????????????????????????????????????????????????????????????????????????

    ?

    ??????如果Socket 的底層實現(xiàn)不支持TCP_NODELAY 選項, 那么getTcpNoDelay() 和 setTcpNoDelay 方法會拋出 SocketException.

    ?

    ?

    5.2 SO_RESUSEADDR 選項

    • 設(shè)置該選項: public void setResuseAddress(boolean on) throws SocketException
    • 讀取該選項: public boolean getResuseAddress() throws SocketException

    ?????當接收方通過Socket 的close() 方法關(guān)閉Socket 時, 如果網(wǎng)絡上還有發(fā)送到這個Socket 的數(shù)據(jù), 那么底層的Socket 不會立即釋放本地端口, 而是會等待一段時間, 確保接收到了網(wǎng)絡上發(fā)送過來的延遲數(shù)據(jù), 然后再釋放端口.? Socket接收到延遲數(shù)據(jù)后, 不會對這些數(shù)據(jù)作任何處理. Socket 接收延遲數(shù)據(jù)的目的是, 確保這些數(shù)據(jù)不會被其他碰巧綁定到同樣端口的新進程接收到.

    ?

    ?????客戶程序一般采用隨機端口, 因此出現(xiàn)兩個客戶程序綁定到同樣端口的可能性不大. 許多服務器程序都使用固定的端口. 當服務器程序關(guān)閉后, 有可能它的端口還會被占用一段時間, 如果此時立刻在同一個主機上重啟服務器程序, 由于端口已經(jīng)被占用, 使得服務器程序無法綁定到該端口, 啟動失敗. (第三篇文章會對此作出介紹).

    ?

    ???? 為了確保一個進程關(guān)閉Socket 后, 即使它還沒釋放端口, 同一個主機上的其他進程還可以立即重用該端口, 可以調(diào)用Socket 的setResuseAddress(true) 方法:

    ?

    ?????? ?if(!socket.getResuseAddress()) socket.setResuseAddress(true);????????????????????????????????????????????????????????????????????????????

    ?

    ????值得注意的是?socket.setResuseAddress(true) 方法必須在 Socket 還沒有綁定到一個本地端口之前調(diào)用, 否則執(zhí)行?socket.setResuseAddress(true) 方法無效. 因此必須按照以下方式創(chuàng)建Socket 對象, 然后再連接遠程服務器:

    ???

    ? Socket socket = new Socket();??????????? //此時Socket對象未綁定本地端口,并且未連接遠程服務器
    ??socket.setReuseAddress(true);
    ??SocketAddress remoteAddr = new InetSocketAddress("localhost",8000);
    ??socket.connect(remoteAddr); ???????????? //連接遠程服務器, 并且綁定匿名的本地端口

    ?

    ??? 或者:?

    ?

    ??Socket socket = new Socket();????????????? //此時Socke 對象為綁定本地端口, 并且未連接遠程服務器
    ??socket.setReuseAddress(true);
    ??SocketAddress localAddr = new InetSocketAddress("localhost",9000);
    ??SocketAddress remoteAddr = new InetSocketAddress("localhost",8000);
    ??socket.bind(localAddr);?????????????//與本地端口綁定
    ??socket.connect(remoteAddr); //連接遠程服務器

    ?

    ????此外, 兩個共用同一個端口的進程必須都調(diào)用 socket.setResuseAddress(true) 方法, 才能使得一個進程關(guān)閉 Socket后, 另一個進程的 Socket 能夠立即重用相同端口.

    ?

    ?

    ?5.3 SO_TIMEOUT 選項

    • 設(shè)置該選項: public void setSoTimeout(int milliseconds) throws SocketException
    • 讀取該選項: public int getSoTimeout() throws SocketException

    ?????當通過Socket 的輸入流讀數(shù)據(jù)時, 如果還沒有數(shù)據(jù), 就會等待. 例如, 在以下代碼中, in.read(buff) 方法從輸入流中讀入 1024個字節(jié):?

    ?

    ??byte[] buff = new byte[1024];
    ??InputStream in = socket.getInputStream();
    ??in.read(buff);?

    ?

    ???? 如果輸入流中沒有數(shù)據(jù), in.read(buff) 就會等待發(fā)送方發(fā)送數(shù)據(jù), 直到滿足以下情況才結(jié)束等待:

    ?

    ???? 略...............

    ?

    ???? Socket 類的 SO_TIMEOUT 選項用于設(shè)定接收數(shù)據(jù)的等待超時時間, 單位為毫秒, 它的默認值為 0, 表示會無限等待, 永遠不會超時. 以下代碼把接收數(shù)據(jù)的等待超時時間設(shè)為 3 分鐘:

    ?

    ??????? if(socket.getSoTimeout() == 0) socket.setSoTimeout(60000 * 3);???//注意, 原書中這里的代碼錯誤, 里面的方法名字都少了"So"???

    ?

    ?????Socket?的 setSoTimeout() 方法必須在接收數(shù)據(jù)之前執(zhí)行才有效. 此外, 當輸入流的 read()方法拋出 SocketTimeoutException 后, Socket 仍然是連接的, 可以嘗試再次讀數(shù)據(jù):?????

    ?

    ??socket.setSoTimeout(180000);
    ??byte[] buff = new byte[1024];
    ??InputStream in = socket.getInputStream();
    ??int len = -1;
    ??do{
    ???try{
    ????len = in.read(buff);
    ????//處理讀到的數(shù)據(jù)
    ????//.........
    ???}catch(SocketTimeoutException e){
    ????//e.printStackTrace();?
    ??? System.out.println("等待讀超時!");
    ????len = 0;
    ???}????
    ??}while(len != -1);

    ?

    ???? 例子ReceiveServer.java 和 SendClient.java 是一對簡單的服務器/客戶程序. sendClient 發(fā)送字符串 "hello everyone" ,接著睡眠 1 分鐘, 然后關(guān)閉 Socket. ReceiveServer 讀取 SendClient 發(fā)送來的數(shù)據(jù), 直到抵達輸入流的末尾, 最后打印 SendClient 發(fā)送來的數(shù)據(jù).

    ?

    ???? ReceiveServer.java 略....... ,???????? SendClient.java 略..........

    ?

    ???? 在 SendClient 發(fā)送字符串 "hello everyone" 后, 睡眠 1 分鐘. 當 SendClient 在睡眠時, ReceiveServer 在執(zhí)行 in.read(buff) 方法, 不能讀到足夠的數(shù)據(jù)填滿 buff 緩沖區(qū), 因此會一直等待 SendClient 發(fā)送數(shù)據(jù). 如果在 ReceiveServer 類中 socket.setSoTimeout(20000) , 從而把等待接收數(shù)據(jù)的超時時間設(shè)為 20 秒, 那么 ReceiveServer 在等待數(shù)據(jù)時, 每當超過 20 秒, 就會拋出SocketTimeoutException . 等到 SendClient 睡眠 1 分鐘后, SendClient 調(diào)用 Socket 的 close() 方法關(guān)閉 Socket, 這意味著 ReceiveServer 讀到了輸入流的末尾, ReceiveServer 立即結(jié)束讀等待, read() 方法返回 -1 . ReceiveServer最后打印接收到的字符串 "hello everyone", 結(jié)果如下:

    ??等待讀超時!
    ??等待讀超時!
    ??hello everyone

    5.4 SO_LINGER 選項

    • 設(shè)置該選項: public void setSoLinger(boolean on, int seconds) throws SocketException
    • 讀取該選項: public int getSoLinger() throws SocketException

    ????? SO_LINGER 選項用來控制 Socket 關(guān)閉時的行為. 默認情況下, 執(zhí)行 Socket 的 close() 方法, 該方法會立即返回, 但底層的 Socket 實際上并不立即關(guān)閉, 它會延遲一段時間, 直到發(fā)送完所有剩余的數(shù)據(jù), 才會真正關(guān)閉 Socket, 斷開連接.

    ?

    ????? 如果執(zhí)行以下方法:

    ?

    ????? socket.setSoLinger(true, 0);???????????????????????????????????????????????????????????????????????????????????????????????

    ?

    ????? 那么執(zhí)行Socket 的close() 方法, 該方法也會立即返回, 并且底層的 Socket 也會立即關(guān)閉, 所有未發(fā)送完的剩余數(shù)據(jù)被丟棄.

    ?

    ????? 如果執(zhí)行以下方法:

    ?

    ????? socket.setSoLinger(true, 3600);???????????????????????????????????????????????????????????????????????????????????????????

    ?

    ????? 那么執(zhí)行Socket 的 close() 方法, 該方法不會立即返回, 而是進入阻塞狀態(tài). 同時, 底層的 Socket 會嘗試發(fā)送剩余的數(shù)據(jù). 只有滿足以下兩個條件之一, close() 方法才返回:

    ????? ⑴ 底層的 Socket 已經(jīng)發(fā)送完所有的剩余數(shù)據(jù);

    ?

    ????? ⑵ 盡管底層的 Socket 還沒有發(fā)送完所有的剩余數(shù)據(jù), 但已經(jīng)阻塞了 3600 秒(注意這里是秒, 而非毫秒), close() 方法的阻塞時間超過 3600 秒, 也會返回, 剩余未發(fā)送的數(shù)據(jù)被丟棄.

    ?

    ????? 值得注意的是, 在以上兩種情況內(nèi), 當close() 方法返回后, 底層的 Socket 會被關(guān)閉, 斷開連接. 此外, setSoLinger(boolean on, int seconds) 方法中的 seconds 參數(shù)以秒為單位, 而不是以毫秒為單位.????

    ?

    ????? 如果未設(shè)置 SO_LINGER 選項, getSoLinger()? 返回的結(jié)果是 -1, 如果設(shè)置了 socket.setSoLinger(true, 80) , getSoLinger()? 返回的結(jié)果是 80.

    ?

    Tips: 當程序通過輸出流寫數(shù)據(jù)時, 僅僅表示程序向網(wǎng)絡提交了一批數(shù)據(jù), 由網(wǎng)絡負責輸送到接收方. 當程序關(guān)閉 Socket, 有可能這批數(shù)據(jù)還在網(wǎng)絡上傳輸, 還未到達接收方. 這里所說的 "未發(fā)送完的數(shù)據(jù)" 就是指這種還在網(wǎng)絡上傳輸, 未被接收方接收的數(shù)據(jù).

    ?

    ??? 例子 SimpleClient.java 與 SimpleServer.java 所示是一對簡單的客戶/服務器程序. SimpleClient 類發(fā)送一萬個字符給 SimpleServer, 然后調(diào)用Socket 的 close() 方法關(guān)閉 Socket.

    ?

    ??? SimpleServer 通過 ServerSocket 的 accept() 方法接受了 SimpleClient 的連接請求后,? 并不立即接收客戶發(fā)送的數(shù)據(jù), 而是睡眠 5 秒鐘后再接收數(shù)據(jù). 等到 SimpleServer 開始接收數(shù)據(jù)時, SimpleClient 有可能已經(jīng)執(zhí)行了 Socket 的close() 方法, 那么 SimpleServer 還能接收到 SimpleClient 發(fā)送的數(shù)據(jù)嗎?

    ?

    ??? SimpleClient.java 略..., SimpleServer.java 略......

    ?

    ??? SimpleClient.java中

    ??System.out.println("開始關(guān)閉 Socket");
    ??long begin = System.currentTimeMillis();
    ??socket.close();
    ??long end = System.currentTimeMillis();
    ??System.out.println("關(guān)閉Socket 所用的時間為:" + (end - begin) + "ms");

    ?

    ??? 下面分 3 種情況演示 SimpleClient 關(guān)閉 Socket 的行為.??

    ??? ⑴ 未設(shè)置 SO_LINGER 選項, 當 SimpleClient 執(zhí)行 Socket 的close() 方法時, 立即返回, SimpleClient 的打印結(jié)果如下:

    ?

    ? 開始關(guān)閉 Socket
    ??關(guān)閉Socket 所用的時間為:0ms

    ?

    ???? 等到 SimpleClient 結(jié)束運行, SimpleServer 可能才剛剛結(jié)束睡眠, 開始接收 SimpleClient 發(fā)送的數(shù)據(jù). 此時盡管 SimpleClient 已經(jīng)執(zhí)行了 Socket 的 close() 方法, 并且 SimpleClient 程序本身也運行結(jié)束了, 但從 SimpleServer 的打印結(jié)果可以看出, SimpleServer 仍然接收到了所有的數(shù)據(jù). 之所以出現(xiàn)這種情況, 是因為當 SimpleClient 執(zhí)行了 Socket 的 close() 方法后, 底層的 Socket 實際上并沒有真正關(guān)閉, 與 SimpleServer 的連接依然存在. 底層的 Socket 會存在一段時間, 直到發(fā)送完所有的數(shù)據(jù).

    ?

    ?????⑵ 設(shè)置SO_LINGER 選項, socket.setSoLinger(true, 0). 這次當 SimpleClient 執(zhí)行 Socket 的 close() 方法時, 會強行關(guān)閉底層的 Socket, 所有未發(fā)送完的數(shù)據(jù)丟失. SimpleClient 的打印結(jié)果如下:

    ?

    ? 開始關(guān)閉 Socket
    ??關(guān)閉Socket 所用的時間為:0ms

    ?

    ?????從打印結(jié)果看出, SimpleClient 執(zhí)行 Socket 的 close() 方法時, 也立即返回. 當 SimpleServer 結(jié)束睡眠, 開始接收 SimpleClient 發(fā)送的數(shù)據(jù)時,?由于 SimpleClient 已經(jīng)關(guān)閉底層 Socket, 斷開連接, 因此 SimpleServer 在讀數(shù)據(jù)時會拋出 SocketException:

    ?

    ?? ?????java.net.SocketException: Connection reset?????????????????????????????????????? ?

    ?

    ???? ⑶ 設(shè)置SO_LINGER 選項, socket.setSoLinger(true, 3600). 這次當 SimpleClient 執(zhí)行 Socket 的close() 方法時, 會進入阻塞狀態(tài), 知道等待了 3600 秒, 或者底層 Socket 已經(jīng)把所有未發(fā)送的剩余數(shù)據(jù)發(fā)送完畢, 才會從 close() 方法返回. SimpleClient 的打印結(jié)果如下:

    ?

    ? 開始關(guān)閉 Socket
    ??關(guān)閉Socket 所用的時間為:5648ms

    ?

    ?????當 SimpleServer 結(jié)束了 5 秒鐘的睡眠, 開始接收 SimpleClient 發(fā)送的數(shù)據(jù)時, SimpleClient 還在這些 Socket 的close() 方法, 并且處于阻塞狀態(tài). SimpleClient 與 SimpleServer 之間的連接依然存在, 因此 SimpleServer 能夠接收到 SimpleClient 發(fā)送的所有數(shù)據(jù).

    ?

    5.5 SO_RCVBUF 選項

    • 設(shè)置該選項: public void setReceiveBufferSize(int size) throws SocketException
    • 讀取該選項: public int getReceiveBufferSize() throws SocketException

    ??? ?SO_RCVBUF 表示 Socket 的用于輸入數(shù)據(jù)的緩沖區(qū)的大小. 一般說來, 傳輸大的連續(xù)的數(shù)據(jù)塊(基于HTTP 或 FTP 協(xié)議的通信) 可以使用較大的緩沖區(qū), 這可以減少傳輸數(shù)據(jù)的次數(shù), 提高傳輸數(shù)據(jù)的效率. 而對于交互頻繁且單次傳送數(shù)據(jù)量比較小的通信方式(Telnet 和 網(wǎng)絡游戲), 則應該采用小的緩沖區(qū), 確保小批量的數(shù)據(jù)能及時發(fā)送給對方. 這種設(shè)定緩沖區(qū)大小的原則也同樣適用于 Socket 的 SO_SNDBUF 選項.

    ?

    ????? 如果底層 Socket 不支持 SO_RCVBUF 選項, 那么 setReceiveBufferSize() 方法會拋出 SocketException.

    ?

    5.6 SO_SNDBUF 選項

    • 設(shè)置該選項: public void setSendBufferSize(int size) throws SocketException
    • 讀取該選項: public int getSendBufferSize() throws SocketException

    ???? SO_SNDBUF 表示 Socket 的用于輸出數(shù)據(jù)的緩沖區(qū)的大小. 如果底層 Socket 不支持 SO_SNDBUF 選項, setSendBufferSize() 方法會拋出 SocketException.

    ?

    5.7 SO_KEEPALIVE 選項

    • 設(shè)置該選項: public void setKeepAlive(boolean on) throws SocketException
    • 讀取該選項: public boolean getKeepAlive() throws SocketException?//原書中這個方法返回的類型是int

    ?? ?? 當 SO_KEEPALIVE?選項為 true 時, 表示底層的TCP 實現(xiàn)會監(jiān)視該連接是否有效. 當連接處于空閑狀態(tài)(連接的兩端沒有互相傳送數(shù)據(jù)) 超過了 2 小時時, 本地的TCP 實現(xiàn)會發(fā)送一個數(shù)據(jù)包給遠程的 Socket. 如果遠程Socket 沒有發(fā)回響應, TCP實現(xiàn)就會持續(xù)嘗試 11 分鐘, 直到接收到響應為止. 如果在 12 分鐘內(nèi)未收到響應, TCP 實現(xiàn)就會自動關(guān)閉本地Socket, 斷開連接. 在不同的網(wǎng)絡平臺上, TCP實現(xiàn)嘗試與遠程Socket 對話的時限有所差別.

    ?

    ????? SO_KEEPALIVE 選項的默認值為 false, 表示TCP 不會監(jiān)視連接是否有效, 不活動的客戶端可能會永遠存在下去, 而不會注意到服務器已經(jīng)崩潰.

    ?

    ????? 以下代碼把 SO_KEEPALIVE 選項設(shè)為 true:

    ?

    ??????? if(!socket.getKeepAlive()) socket.setKeepAlive(true);??????????????????????????????????????????????????????????????

    ?

    5.8 OOBINLINE 選項

    • 設(shè)置該選項: public void setOOBInline(boolean on) throws SocketException
    • 讀取該選項: public boolean getOOBInline() throws SocketException??//原書中這個方法返回的類型是int

    ???? 當 OOBINLINE 為 true 時, 表示支持發(fā)送一個字節(jié)的 TCP 緊急數(shù)據(jù). Socket 類的 sendUrgentData(int data) 方法用于發(fā)送一個字節(jié)的 TCP緊急數(shù)據(jù).

    ?

    ???? OOBINLINE 的默認值為 false, 在這種情況下, 當接收方收到緊急數(shù)據(jù)時不作任何處理, 直接將其丟棄. 如果用戶希望發(fā)送緊急數(shù)據(jù), 應該把 OOBINLINE 設(shè)為 true:

    ?

    ????????? socket.setOOBInline(true);?????????????????????????????????????????????????????????????

    ?

    ??????此時接收方會把接收到的緊急數(shù)據(jù)與普通數(shù)據(jù)放在同樣的隊列中. 值得注意的是, 除非使用一些更高層次的協(xié)議, 否則接收方處理緊急數(shù)據(jù)的能力有限, 當緊急數(shù)據(jù)到來時, 接收方不會得到任何通知, 因此接收方很難區(qū)分普通數(shù)據(jù)與緊急數(shù)據(jù), 只好按照同樣的方式處理它們.

    ?

    ?

    5.9 服務類型選項

    ?

    ??????當用戶通過郵局發(fā)送普通信、掛號信或快件時, 實際上是選擇了郵局提供的不同的服務.? 發(fā)送普通信的價格最低, 但發(fā)送速度慢, 并且可靠性沒有保證. 發(fā)送掛號信的價格稍高,? 但可靠性有保證. 發(fā)送快件的價格最高, 發(fā)送速度最快, 并且可靠性有保證.

    ?

    ????? 在 Internet 上傳輸數(shù)據(jù)也分為不同的服務類型, 它們有不同的定價. 用戶可以根據(jù)自己的需求, 選擇不同的服務類型. 例如, 發(fā)送視頻需要較高的帶寬, 快速到達目的地, 以保證接收方看到連續(xù)的畫面. 而發(fā)送電子郵件可以使用較低的帶寬, 延遲幾個小時到達目的地也沒有關(guān)系.

    ?

    ??????IP 規(guī)定了 4 種服務類型, 用來定性地描述服務的質(zhì)量.

    • 低成本: 發(fā)送成本低.
    • 高可靠性: 保證把數(shù)據(jù)可靠地送達目的地.
    • 最高吞吐量: 一次可以接收或發(fā)送大批量的數(shù)據(jù).
    • 最小延遲: 傳輸數(shù)據(jù)的速度快, 把數(shù)據(jù)快速送達目的地.

    ??????這 4?種服務類型還可以進行組合. 例如, 可以同時要求獲得高可靠性和最小延遲.

    ?

    ????? Socket 類中提供了設(shè)置和讀取服務類型的方法.

    • 設(shè)置服務類型: public void setTrafficClass(int trafficClass) throws SocketException
    • 讀取服務類型: public int getTrafficClass() throws SocketException

    ??????Socket?類用?4 個整數(shù)表示服務類型.

    • 低成本: 0x02 (二進制的倒數(shù)第二位為1)
    • 高可靠性: 0x04 (二進制的倒數(shù)第三位為1)
    • 最高吞吐量: 0x08 (二進制的倒數(shù)第四位為1)
    • 最小延遲: 0x10 (二進制的倒數(shù)第五位為1)

    ????? 例如,?以下代碼請求高可靠性傳輸服務:

    ??socket = new Socket(host, port);
    ??socket.setTrafficClass(0x04);

    ?

    ????? 再例如, 以下代碼請求高可靠性和最小延遲傳輸服務:

    socket.setTrafficClass(0x04|0x10);??????? //把 0x04 與 0x10 進行位或運算?????

    ?

    5.10?設(shè)定連接時間、延遲和帶寬的相對重要性

    ?

    ??????在 JDK 1.5 中, 還為 Socket 類提供了一個 setPerformancePreferences() ?方法:

    ??????? public void?setPerformancePreferences(int connectionTime, int latency, int bandwidth)????????????? ?

    ?

    ??????以上方法的 3 個參數(shù)表示網(wǎng)絡傳輸數(shù)據(jù)的 3 選指標.

    • 參數(shù) connectionTime: 表示用最少時間建立連接.
    • 參數(shù) latency: 表示最小延遲.
    • 參數(shù) bandwidth: 表示最高帶寬.

    ??????setPerformancePreferences() 方法用來設(shè)定這 3 項指標之間的相對重要性. 可以為這些參數(shù)賦予任意的整數(shù), 這些整數(shù)之間的相對大小就決定了相應參數(shù)的相對重要性.

    ?

    ??????例如, 如果參數(shù) connectionTime 為 2, 參數(shù) latency 為 1, 而參數(shù)bandwidth 為 3, 就表示最高帶寬最重要, 其次是最少連接時間, 最后是最小延遲.

    轉(zhuǎn)載于:https://www.cnblogs.com/balaamwe/archive/2012/02/02/2335902.html

    總結(jié)

    以上是生活随笔為你收集整理的java socket/Serversocket编程详解(中/英文)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 亚洲一区毛片 | 奇米影视一区 | 91豆花视频 | 特级淫片aaaaaaa级 | 三上悠亚中文字幕在线播放 | 先锋资源av网 | 99国产精品99久久久久久 | 中文字幕一区二区三区人妻 | 色又色 | 黄色一级大片在线免费看国产一 | 亚洲国产精品久久久久爰色欲 | 黄色一级片一级片 | 天天干网 | 国产二区视频在线观看 | av少妇 | 久久人人精 | 三区在线视频 | 狠狠干狠狠操视频 | 性欧美视频在线观看 | 欧美性啪啪 | 日本黄色片免费 | 色福利视频 | 少妇性生活视频 | 久久久高清视频 | 精品一区在线视频 | 欧美激情网站 | 69日本xxxxxxxxx30 在线波多野结衣 | 精品一区二区三区人妻 | 久久6精品 | 老外一级片| 波多野结衣中文字幕一区 | 明星双性精跪趴灌满h | www.精品久久 | 天天综合中文字幕 | 在线观看你懂的网址 | 91看片视频| 情五月| 黄色福利在线观看 | h片免费观看 | 色视频2| 少妇2做爰bd在线意大利堕落 | 欧美性受xxxxxx黑人xyx性爽 | 性xxxxxxxxx18欧美 | 国产老女人乱淫免费可以 | 爱情岛av| 香蕉久久夜色精品国产使用方法 | 日本理论片在线 | 污污网站在线播放 | 国内av在线播放 | 少妇免费毛片久久久久久久久 | 中文字幕一区二区三区人妻四季 | 欧美xxxx日本和非洲 | 欧美伦理片 | 深夜视频一区二区三区 | 91久色| 国产在线观看黄色 | 国产精品一区二区三区免费看 | 神马午夜51 | 日韩在线视频一区二区三区 | 欧美性猛交aaaa片黑人 | 伊人春色在线 | 四虎av影院 | 狠狠网站 | 人妻体内射精一区二区三区 | 午夜久久久久久噜噜噜噜 | 精品国产无码在线观看 | 亚洲熟妇av日韩熟妇在线 | 日本人妻一区二区三区 | 国产乱子伦视频一区二区三区 | 超碰成人在线免费观看 | 人人人人爽 | 久久久久久无码精品人妻一区二区 | 1024视频在线 | 精品一区二区三区久久 | 丁香婷婷视频 | 激情片| 美女扒开下面让男人捅 | 精品久久久影院 | 小辣椒福利视频导航 | 丝袜国产在线 | 国产精品无 | 最新色网址 | 久操久操 | 少妇裸体淫交视频免费看高清 | 一本大道熟女人妻中文字幕在线 | 色资源在线 | 久草网在线视频 | 中文字幕第四页 | 成人免费毛片日本片视频 | 毛片av在线观看 | 毛片成人网 | 欧美v日本 | 日韩簧片 | 国产精品亚洲五月天丁香 | 国产精品视频无码 | 精品久久成人 | 欧美成人一二三 | 天天天天色 | 少妇一级免费 |