這個地方有問題,第一,你必須寫入newLine,要不會造成阻塞;第二,你必須先flush后才能讀服務器;第三,你從控制臺輸入應該有個結(jié)束標志,要不你在while里面把bw關閉了,你還怎么循環(huán)
成都創(chuàng)新互聯(lián)主要從事成都網(wǎng)站制作、成都網(wǎng)站設計、外貿(mào)營銷網(wǎng)站建設、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務太仆寺,10年網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:13518219792
客戶端這個地方重寫一下,
while(true) {
temp=br.readLine();
if(temp.equals("over")){
break;
}
bw.write(temp);
bw.newLine();//如果沒有,使用readLine則會造成莫名等待
bw.flush();
}
不一定改全了,你先試試這些改動,如有問題再找
你好:Socket s = new Socket("localhost", 6660);//14行
這個的話,你的沒通, 去黑窗口輸入 tenlet 127.0.0.1 6660;看看是否有結(jié)果輸出,再就是你別用localhost了,換成實際的127.0.0.1的地址,
二 用于獲得和設置Socket選項的getter和setter方法
Socket選擇可以指定Socket類發(fā)送和接受數(shù)據(jù)的方式 在JDK *** 有 個Socket選擇可以設置 這 個選項都定義在 SocketOptions接口中 定義如下
public?final?static?int?TCP_NODELAY?=? x ;??? public?final?static?int?SO_REUSEADDR?=? x ;??? public?final?static?int?SO_LINGER?=? x ;????public?final?static?int?SO_TIMEOUT?=? x ;????public?final?static?int?SO_SNDBUF?=? x ;????public?final?static?int?SO_RCVBUF?=? x ;????public?final?static?int?SO_KEEPALIVE?=? x ;????public?final?static?int?SO_OOBINLINE?=? x ;
有趣的是 這 個選項除了第一個沒在SO前綴外 其他 個選項都以SO作為前綴 其實這個SO就是Socket Option的縮寫 因此 在Java中約定所有以SO為前綴的常量都表示Socket選項 當然 也有例外 如TCP_NODELAY 在Socket類中為每一個選項提供了一對get和set方法 分別用來獲得和設置這些選項
TCP_NODELAY
public?boolean?getTcpNoDelay()?throws?SocketExceptionpublic?void?setTcpNoDelay(boolean?on)?throws?SocketException
在默認情況下 客戶端向服務器發(fā)送數(shù)據(jù)時 會根據(jù)數(shù)據(jù)包的大小決定是否立即發(fā)送 當數(shù)據(jù)包中的數(shù)據(jù)很少時 如只有 個字節(jié) 而數(shù)據(jù)包的頭卻有幾十個字節(jié)(IP頭+TCP頭)時 系統(tǒng)會在發(fā)送之前先將較小的包合并到軟大的包后 一起將數(shù)據(jù)發(fā)送出去 在發(fā)送下一個數(shù)據(jù)包時 系統(tǒng)會等待服務器對前一個數(shù)據(jù)包的響應 當收到服務器的響應后 再發(fā)送下一個數(shù)據(jù)包 這就是所謂的Nagle算法 在默認情況下 Nagle算法是開啟的
這種算法雖然可以有效地改善網(wǎng)絡傳輸?shù)男?但對于網(wǎng)絡速度比較慢 而且對實現(xiàn)性的要求比較高的情況下(如游戲 Telnet等) 使用這種方式傳輸數(shù)據(jù)會使得客戶端有明顯的停頓現(xiàn)象 因此 最好的解決方案就是需要Nagle算法時就使用它 不需要時就關閉它 而使用setTcpToDelay正好可以滿足這個需求 當使用setTcpNoDelay(true)將Nagle算法關閉后 客戶端每發(fā)送一次數(shù)據(jù) 無論數(shù)據(jù)包的大小都會將這些數(shù)據(jù)發(fā)送出去
SO_REUSEADDR
public?boolean?getReuseAddress()?throws?SocketException???????????public?void?setReuseAddress(boolean?on)?throws?SocketException
通過這個選項 可以使多個Socket對象綁定在同一個端口上 其實這樣做并沒有多大意義 但當使用close方法關閉Socket連接后 Socket對象所綁定的端口并不一定馬上釋放 系統(tǒng)有時在Socket連接關閉才會再確認一下是否有因為延遲面未到達的數(shù)據(jù)包 這完全是在底層處理的 也就是說對用戶是透明的 因此 在使用Socket類時完全不會感覺到
這種處理機制對于隨機綁定端口的Socket對象沒有什么影響 但對于綁定在固定端口的Socket對象就可能會拋出 Address already in use JVM_Bind 例外 因此 使用這個選項可以避免個例外的發(fā)生
package mynet;import? *;import?java io *;public?class Test{????public?static?void?main(String[]?args)????{????????Socket?socket ?=?new?Socket();????????Socket?socket ?=?new?Socket();????????try????????{????????????socket setReuseAddress(true);????????????socket bind(new?InetSocketAddress( ? ));????????????System out println( socket getReuseAddress(): ????????????????????+?socket getReuseAddress());????????????socket bind(new?InetSocketAddress( ? ));????????}????????catch?(Exception?e)????????{????????????System out println( error: ?+?e getMessage());????????????try????????????{????????????????socket setReuseAddress(true);????????????????socket bind(new?InetSocketAddress( ? ));????????????????System out println( socket getReuseAddress(): ????????????????????????+?socket getReuseAddress());????????????????System out println( 端口 第二次綁定成功! );????????????}????????????catch?(Exception?e )????????????{????????????????System out println(e getMessage());????????????}????????}????}}
上面的代碼的運行結(jié)果如下
socket getReuseAddress():trueerror:Address?already?in?use:?JVM_Bindsocket getReuseAddress():true端口 第二次綁定成功!
使用SO_REUSEADDR選項時有兩點需要注意
必須在調(diào)用bind方法之前使用setReuseAddress方法來打開SO_REUSEADDR選項 因此 要想使用SO_REUSEADDR選項 就不能通過Socket類的構(gòu)造方法來綁定端口
必須將綁定同一個端口的所有的Socket對象的SO_REUSEADDR選項都打開才能起作用 如在例程 中 socket 和socket 都使用了setReuseAddress方法打開了各自的SO_REUSEADDR選項
SO_LINGER
public?int?getSoLinger()?throws?SocketExceptionpublic?void?setSoLinger(boolean?on ?int?linger)?throws?SocketException
這個Socket選項可以影響close方法的行為 在默認情況下 當調(diào)用close方法后 將立即返回 如果這時仍然有未被送出的數(shù)據(jù)包 那么這些數(shù)據(jù)包將被丟棄 如果將linger參數(shù)設為一個正整數(shù)n時(n的值最大是 ) 在調(diào)用close方法后 將最多被阻塞n秒 在這n秒內(nèi) 系統(tǒng)將盡量將未送出的數(shù)據(jù)包發(fā)送出去 如果超過了n秒 如果還有未發(fā)送的數(shù)據(jù)包 這些數(shù)據(jù)包將全部被丟棄 而close方法會立即返回 如果將linger設為 和關閉SO_LINGER選項的作用是一樣的
如果底層的Socket實現(xiàn)不支持SO_LINGER都會拋出SocketException例外 當給linger參數(shù)傳遞負數(shù)值時 setSoLinger還會拋出一個IllegalArgumentException例外 可以通過getSoLinger方法得到延遲關閉的時間 如果返回 則表明SO_LINGER是關閉的 例如 下面的代碼將延遲關閉的時間設為 分鐘
if(socket getSoLinger()?==? )?socket setSoLinger(true ? );
SO_TIMEOUT
public?int?getSoTimeout()?throws?SocketExceptionpublic?void?setSoTimeout(int?timeout)?throws?SocketException
這個Socket選項在前面已經(jīng)討論過 可以通過這個選項來設置讀取數(shù)據(jù)超時 當輸入流的read方法被阻塞時 如果設置timeout(timeout的單位是毫秒) 那么系統(tǒng)在等待了timeout毫秒后會拋出一個InterruptedIOException例外 在拋出例外后 輸入流并未關閉 你可以繼續(xù)通過read方法讀取數(shù)據(jù)
如果將timeout設為 就意味著read將會無限等待下去 直到服務端程序關閉這個Socket 這也是timeout的默認值 如下面的語句將讀取數(shù)據(jù)超時設為 秒
socket setSoTimeout( ?*? );
當?shù)讓拥腟ocket實現(xiàn)不支持SO_TIMEOUT選項時 這兩個方法將拋出SocketException例外 不能將timeout設為負數(shù) 否則setSoTimeout方法將拋出IllegalArgumentException例外
SO_SNDBUF
public?int?getSendBufferSize()?throws?SocketExceptionpublic?void?setSendBufferSize(int?size)?throws?SocketException
在默認情況下 輸出流的發(fā)送緩沖區(qū)是 個字節(jié)( K) 這個值是Java所建議的輸出緩沖區(qū)的大小 如果這個默認值不能滿足要求 可以用setSendBufferSize方法來重新設置緩沖區(qū)的大小 但最好不要將輸出緩沖區(qū)設得太小 否則會導致傳輸數(shù)據(jù)過于頻繁 從而降低網(wǎng)絡傳輸?shù)男?/p>
如果底層的Socket實現(xiàn)不支持SO_SENDBUF選項 這兩個方法將會拋出SocketException例外 必須將size設為正整數(shù) 否則setSendBufferedSize方法將拋出IllegalArgumentException例外
SO_RCVBUF
public?int?getReceiveBufferSize()?throws?SocketExceptionpublic?void?setReceiveBufferSize(int?size)?throws?SocketException
在默認情況下 輸入流的接收緩沖區(qū)是 個字節(jié)( K) 這個值是Java所建議的輸入緩沖區(qū)的大小 如果這個默認值不能滿足要求 可以用setReceiveBufferSize方法來重新設置緩沖區(qū)的大小 但最好不要將輸入緩沖區(qū)設得太小 否則會導致傳輸數(shù)據(jù)過于頻繁 從而降低網(wǎng)絡傳輸?shù)男?/p>
如果底層的Socket實現(xiàn)不支持SO_RCVBUF選項 這兩個方法將會拋出SocketException例外 必須將size設為正整數(shù) 否則setReceiveBufferSize方法將拋出IllegalArgumentException例外
SO_KEEPALIVE
public?boolean?getKeepAlive()?throws?SocketExceptionpublic?void?setKeepAlive(boolean?on)?throws?SocketException
如果將這個Socket選項打開 客戶端Socket每隔段的時間(大約兩個小時)就會利用空閑的連接向服務器發(fā)送一個數(shù)據(jù)包 這個數(shù)據(jù)包并沒有其它的作用 只是為了檢測一下服務器是否仍處于活動狀態(tài) 如果服務器未響應這個數(shù)據(jù)包 在大約 分鐘后 客戶端Socket再發(fā)送一個數(shù)據(jù)包 如果在 分鐘內(nèi) 服務器還沒響應 那么客戶端Socket將關閉 如果將Socket選項關閉 客戶端Socket在服務器無效的情況下可能會長時間不會關閉 SO_KEEPALIVE選項在默認情況下是關閉的 可以使用如下的語句將這個SO_KEEPALIVE選項打開
socket setKeepAlive(true);
SO_OOBINLINE
public?boolean?getOOBInline()?throws?SocketException?public?void?setOOBInline(boolean?on)?throws?SocketException
如果這個Socket選項打開 可以通過Socket類的sendUrgentData方法向服務器發(fā)送一個單字節(jié)的數(shù)據(jù) 這個單字節(jié)數(shù)據(jù)并不經(jīng)過輸出緩沖區(qū) 而是立即發(fā)出 雖然在客戶端并不是使用OutputStream向服務器發(fā)送數(shù)據(jù) 但在服務端程序中這個單字節(jié)的數(shù)據(jù)是和其它的普通數(shù)據(jù)混在一起的 因此 在服務端程序中并不知道由客戶端發(fā)過來的數(shù)據(jù)是由OutputStream還是由sendUrgentData發(fā)過來的 下面是sendUrgentData方法的聲明
public?void?sendUrgentData(int?data)?throws?IOException
雖然sendUrgentData的參數(shù)data是int類型 但只有這個int類型的低字節(jié)被發(fā)送 其它的三個字節(jié)被忽略 下面的代碼演示了如何使用SO_OOBINLINE選項來發(fā)送單字節(jié)數(shù)據(jù)
package mynet;import? *;import?java io *;class Server{????public?static?void?main(String[]?args)?throws?Exception????{????????ServerSocket?serverSocket?=?new?ServerSocket( );????????System out println( 服務器已經(jīng)啟動 端口號 );????????while?(true)????????{????????????Socket?socket?=?serverSocket accept();????????????socket setOOBInline(true);????????????InputStream?in?=?socket getInputStream();????????????InputStreamReader?inReader?=?new?InputStreamReader(in);????????????BufferedReader?bReader?=?new?BufferedReader(inReader);????????????System out println(bReader readLine());????????????System out println(bReader readLine());????????????socket close();????????}????}}public?class Client{????public?static?void?main(String[]?args)?throws?Exception????{????????Socket?socket?=?new?Socket( ? );????????socket setOOBInline(true);????????OutputStream?out?=?socket getOutputStream();????????OutputStreamWriter?outWriter?=?new?OutputStreamWriter(out);????????outWriter write( );??????????????//?向服務器發(fā)送字符 C ????????outWriter write( hello?world\r\n );????????socket sendUrgentData( );????????//?向服務器發(fā)送字符 A ????????socket sendUrgentData( );????????//?向服務器發(fā)送字符 B ????????outWriter flush();????????socket sendUrgentData( );???????//?向服務器發(fā)送漢字 中 ????????socket sendUrgentData( );????????socket sendUrgentData( );???????//?向服務器發(fā)送漢字 國 ????????socket sendUrgentData( );????????socket close();????}}
由于運行上面的代碼需要一個服務器類 因此 在加了一個類名為Server的服務器類 關于服務端套接字的使用方法將會在后面的文章中詳細討論 在類Server類中只使用了ServerSocket類的accept方法接收客戶端的請求 并從客戶端傳來的數(shù)據(jù)中讀取兩行字符串 并顯示在控制臺上
測試
由于本例使用了 因Server和Client類必須在同一臺機器上運行
運行Server
java?mynet Server
運行Client
java?mynet Client
在服務端控制臺的輸出結(jié)果
服務器已經(jīng)啟動 端口號 ABChello?world中國
在ClienT類中使用了sendUrgentData方法向服務器發(fā)送了字符 A ( )和 B ( ) 但發(fā)送 B 時實際發(fā)送的是 由于sendUrgentData只發(fā)送整型數(shù)的低字節(jié) 因此 實際發(fā)送的是 十進制整型 的二進制形式如圖 所示
圖 ? 十進制整型 的二進制形式
從圖 可以看出 雖然 分布在了兩個字節(jié)上 但它的低字節(jié)仍然是
在Client類中使用flush將緩沖區(qū)中的數(shù)據(jù)發(fā)送到服務器 我們可以從輸出結(jié)果發(fā)現(xiàn)一個問題 在Client類中先后向服務器發(fā)送了 C hello world r n A B 而在服務端程序的控制臺上顯示的卻是ABChello world 這種現(xiàn)象說明使用sendUrgentData方法發(fā)送數(shù)據(jù)后 系統(tǒng)會立即將這些數(shù)據(jù)發(fā)送出去 而使用write發(fā)送數(shù)據(jù) 必須要使用flush方法才會真正發(fā)送數(shù)據(jù)
在Client類中向服務器發(fā)送 中國 字符串 由于 中 是由 和 兩個字節(jié)組成的 而 國 是由 和 兩個字節(jié)組成的 因此 可分別發(fā)送這四個字節(jié)來傳送 中國 字符串
lishixinzhi/Article/program/Java/hx/201311/26387
網(wǎng)站題目:java網(wǎng)絡編程代碼 java nio網(wǎng)絡編程
本文地址:http://muchs.cn/article26/doggdjg.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、網(wǎng)站營銷、網(wǎng)頁設計公司、品牌網(wǎng)站制作、企業(yè)網(wǎng)站制作、響應式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)