明月松間照 清泉石上流


                                                  ——— 兵臨城下   貓科動(dòng)物
          posts - 70, comments - 137, trackbacks - 0, articles - 23
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          一個(gè)關(guān)于Java Socket的問(wèn)題,大家看一下:
          我的目的是從client端發(fā)出一段字符串,server端接收后原樣返回給客戶端。
          客戶端:ConnClient? 服務(wù)器端ConnSerer(完整源代碼附在最后)

          ===client端===
          建了一個(gè)out流和in流:
          BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
          ??
          PrintWriter Clientout = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);

          向server端輸出:clientOut.println("hello");? clientout.close();
          等待服務(wù)器端返回代碼片段:
          StringBuffer sbuf = new StringBuffer();
          char[] buff = new char[10];
          ??
          int iLen = in.read(buff);
          ??
          while (iLen>0) {?
          ?? sbuf.append(buff,0,iLen);
          ?? if (sbuf.toString().trim().equals("hello")){
          ?????? System.out.println(sbuf.toString());
          ??????? break;
          ?? }
          ??? iLen = in.read(buff);
          }

          ?


          ===server端===
          同樣建了一個(gè)in流和out流
          BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
          ??
          PrintWriter Serverout = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);

          接收client端信息和原樣返回信息:
          StringBuffer sbuf = new StringBuffer();
          ????
          char[] buff = new char[10];
          int iLen = in.read(buff);
          ?????????
          while(iLen>0){?
          ?sbuf.append(buff,0,iLen);
          ?if (sbuf.toString().trim().equals("hello")){
          ?
          ?System.out.println("Echoing: " + sbuf.toString());
          ?serverout.println(sbuf.toString());?????? //此處為server端輸出流,返回給client端
          ?break;
          ??????? }

          ?iLen = in.read(buff);
          }


          問(wèn)題來(lái)了:
          1、如果按以上代碼運(yùn)行,server端可以收到client的信息,但client端卻收不到返回的信息。為什么?
          2、后來(lái)我把client端的clientout.close()注釋掉后,一切正常,client端能收到server端返回的信息。這又為什么?
          難道server端和client端用的是一個(gè)out流?為什么client端把out流關(guān)掉后(clientout.close()),server端就不能返回信息呢?

          以我以前的理解,server端和client端建的兩個(gè)輸出流應(yīng)該是獨(dú)立的。不會(huì)因?yàn)槲野裞lient端的out流關(guān)掉后,server端out流就不能返回了?不會(huì)吧!呵呵!


          還有一個(gè)問(wèn)題:server端怎么判斷client端數(shù)據(jù)已經(jīng)發(fā)送完畢?
          一開(kāi)始,我用clientout.print("hello"),運(yùn)行后,server端顯示已經(jīng)連接成功但一直偵聽(tīng),沒(méi)有收到信息,認(rèn)為client端還沒(méi)有發(fā)送完成。
          后來(lái),我改用clientout.println("hello"),運(yùn)行后,一切正常,服務(wù)器端也收到信息(hello)。
          從上看出server的地判定就是一個(gè)回車(chē)符,不知道這樣認(rèn)識(shí)對(duì)不對(duì)?大家指點(diǎn)!
          經(jīng)過(guò)我試驗(yàn),如果client端print后,用clientout.close()也可以使server端接收到信息。但卻不能返回信息。也就是我發(fā)現(xiàn)上面說(shuō)述的問(wèn)題來(lái)由。

          以上幾個(gè)問(wèn)題,請(qǐng)大家和banq大哥多加指點(diǎn)!

          源代碼如下:
          client端:
          package com.socket;

          import java.net.*;
          import java.io.*;

          public class ConnClient {
          ? public static void main(String[] args) throws IOException {

          ?InetAddress addr = InetAddress.getByName(null);
          ?
          ?System.out.println("addr = " + addr);
          ?
          ?Socket socket = new Socket(addr, 8080);
          ?//socket.setSoTimeout(5000);
          ?
          ?try {
          ?? System.out.println("socket = " + socket);
          ?? BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
          ??
          ?? PrintWriter clientout = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
          ??
          ?? String strSend = "hello";
          ??
          ? ?
          ?? clientout.println(strSend);
          ?? //clientout.println("\r\n");
          ?? //clientout.println();
          ?? //clientout.close();
          ?? StringBuffer sbuf = new StringBuffer();
          ??
          ?char[] buff = new char[10];
          ??
          ?int iLen = in.read(buff);
          ??
          ?while (iLen>0) {?
          ??sbuf.append(buff,0,iLen);
          ??if (sbuf.toString().trim().equals(strSend)){
          ???System.out.println(sbuf.toString());
          ????? break;
          ???? }
          ?? iLen = in.read(buff);
          ?}
          ?
          ?}catch(Exception e){
          ??e.printStackTrace();
          ?} finally {
          ?? System.out.println("closing...");
          ?? socket.close();
          ?}
          ?
          }
          }


          server端代碼:
          package com.socket;
          import java.io.*;
          import java.net.*;

          public class ConnServer {?
          ?
          ? public static final int PORT = 8080;
          ? public static void main(String[] args) throws IOException {

          ?ServerSocket s = new ServerSocket(PORT);
          ?System.out.println("Started: " + s);
          ?try {
          ?? Socket socket = s.accept();
          ?? try {
          ?System.out.println("Connection accepted: "+ socket);
          ?BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

          ?PrintWriter serverout = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
          ??
          ????? StringBuffer sbuf = new StringBuffer();
          ???????
          ?char[] buff = new char[10];
          ?iLen = in.read(buff);
          ?????????
          ?while(iLen>0){?
          ?sbuf.append(buff,0,iLen);
          ?if(sbuf.toString().trim().equals("hello")){
          ?
          ?System.out.println("Echoing: " + sbuf.toString());
          ?serverout.println(sbuf.toString());
          ??????? }
          ?????????? iLen = in.read(buff);
          }??
          ?? }catch(Exception e) { e.printStackTrace();}
          ??? finally {
          ???System.out.println("closing...");
          ???
          ???socket.close();
          ?? }
          ?
          ?} finally {
          ?? s.close();
          ?}
          ? }
          }


          評(píng)論

          # re: 一個(gè)關(guān)于Java Socket的問(wèn)題,大家看一下  回復(fù)  更多評(píng)論   

          2006-05-02 17:45 by 兵臨城下
          經(jīng)過(guò)幾天的調(diào)試,初步有點(diǎn)心得,在我的blog上記錄一下:
          1、client端,clientout.close()語(yǔ)句表面上只是關(guān)閉了socket輸出流,但從我的調(diào)試中發(fā)現(xiàn),在關(guān)閉這個(gè)out流后,client就不能在取得socket,說(shuō)明在關(guān)閉out流的同時(shí),也隱式的關(guān)閉了socket。所以server端就無(wú)法返回?cái)?shù)據(jù)了。解釋我的第一和第二個(gè)問(wèn)題。
          2、關(guān)于server端判定client端是否信息發(fā)送完畢的信號(hào)問(wèn)題。
          從我?guī)滋斓恼{(diào)試中,我總結(jié)出幾點(diǎn)(可能還有其他的,請(qǐng)補(bǔ)充):
          a、就是經(jīng)常使用的out.println(out.print不行)
          b、那就是關(guān)閉client端out流,out.close()。但這種方法卻關(guān)閉了socket,顯然不是大家所愿的。

          # re: 一個(gè)關(guān)于Java Socket的問(wèn)題,大家看一下  回復(fù)  更多評(píng)論   

          2006-05-08 13:49 by 兵臨城下
          問(wèn)題進(jìn)行中……(實(shí)時(shí)紀(jì)錄)
          考慮到字節(jié)流的需要,在client端和server端都改用字節(jié)流DataInputStream和DataOutputStream,相應(yīng)的輸出方法使用out.write(byte[]) 。
          問(wèn)題一:此種輸入輸出流沒(méi)有了out.println()方法,該怎么判定client端輸出流的結(jié)束??
          問(wèn)題二:在client端,發(fā)送的信息的源分為兩種,字符串和文件流。兩種不同的輸入流在server端接收判斷結(jié)束時(shí)是否存在區(qū)別??

          對(duì)于問(wèn)題二,筆者有一些心得:
          server端的接收代碼段是:
          byte[] sbyte = new byte[1024];
          int len;
          while((len = in.read(sbyte)) != -1) {
          out.write(sbyte,0,len);
          out.flush();
          }

          如果client端輸入流為字符串,server端在接收完畢后,在while語(yǔ)句中不能正常跳出。而使用文件流時(shí)就可以跳出循環(huán)。

          以上問(wèn)題歡迎大家發(fā)表意見(jiàn)!

          # re: 一個(gè)關(guān)于Java Socket的問(wèn)題,大家看一下  回復(fù)  更多評(píng)論   

          2006-05-08 21:12 by 兵臨城下
          更正一下,上面所說(shuō)的文件流能順利跳出循環(huán)不正確,其實(shí)不然。
          實(shí)際上在client端傳輸完成后,server端while循環(huán)還是不能跳出,最后能夠完整輸出實(shí)際是在客戶端強(qiáng)制關(guān)閉socket后,server端while才跳出循環(huán)的。
          從以上我總結(jié)出,不管是字符流,還是文件流,都得附加一個(gè)標(biāo)示符來(lái)標(biāo)識(shí)client端傳輸?shù)慕Y(jié)束。

          # re: 一個(gè)關(guān)于Java Socket的問(wèn)題,大家看一下  回復(fù)  更多評(píng)論   

          2006-05-12 12:19 by 兵臨城下
          又獲益頗多啊!
          再來(lái)說(shuō)說(shuō)這幾天的心得:
          關(guān)于這個(gè)socket,折騰了好幾天了啊!
          出現(xiàn)這個(gè)問(wèn)題的初衷是:公司內(nèi)想要實(shí)現(xiàn)java和C++的socket通訊。

          關(guān)于這個(gè)java端(也就是client端)發(fā)送信息結(jié)束的判定問(wèn)題總結(jié)如下:
          如果server端也是java程序(C++我不是很了解),而且server端使用一個(gè)while循環(huán)讀取數(shù)據(jù)時(shí)(類(lèi)似于while((len = in.read(sbyte)) != -1) {}),即使client端發(fā)送完成,即while((len = inFile.read(bb)) != -1) {}循環(huán)語(yǔ)句跳出后,server端仍然在while語(yǔ)句中,不能正常跳出。因?yàn)閟erver端認(rèn)為你沒(méi)有發(fā)送結(jié)束。
          究其原因,我認(rèn)為,因?yàn)樵趈ava socket中對(duì)于socket的input和output流結(jié)束,有一個(gè)socket方法來(lái)給出結(jié)束的標(biāo)志:socket.shutdownOutput();socket.shutdownInput();

          這兩個(gè)方法為java socket判定client端發(fā)送結(jié)束的標(biāo)志。

          當(dāng)然如果和我上述留言中所說(shuō)的,使用特定設(shè)置的標(biāo)志符當(dāng)然是可以的。

          # re: 一個(gè)關(guān)于Java Socket的問(wèn)題,大家看一下[未登錄](méi)  回復(fù)  更多評(píng)論   

          2009-02-28 22:11 by sunshine
          如果通信協(xié)議用的是java默認(rèn)的編碼格式,客戶端還是用BufferedReader.readline()方法,這個(gè)是以\r\n為界定符的。在你從socket產(chǎn)生bufferedReader的時(shí)候,PrintWriter clientout = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true)最后一個(gè)boolean標(biāo)志是否在println()方法中自動(dòng)調(diào)用outputstream.flush()把緩存的東西是否發(fā)送出去。否則還要自己再調(diào)用PrintWriter.flush()發(fā)送。而且這個(gè)println()后在你的數(shù)據(jù)后加上\r\n,用客戶端的readline()正好可以讀到你的數(shù)據(jù),當(dāng)然是去掉了\r\n.

          如果你要使用自己的界定符,就不能使用BufferedReader,應(yīng)該使用它的基類(lèi),在while(in.ready())循環(huán)中inputstream.read(),然后自己斷開(kāi)你的數(shù)據(jù)。這和串口的通信是一樣。既然是輸入流,當(dāng)然收到是連續(xù)的字節(jié)數(shù)據(jù),除非你制定一個(gè)界定符,否則系統(tǒng)怎么知道你發(fā)送完了?同時(shí),還要注意發(fā)送字節(jié)的時(shí)候,兩端的編碼格式要一致。

          # 回答得太好了  回復(fù)  更多評(píng)論   

          2009-06-27 21:20 by 周小兵
          哥們,你回答的太好了,這正是我遇到的問(wèn)題,問(wèn)題都和你一樣的,我在看你的回答前,我已經(jīng)測(cè)試過(guò),找到了問(wèn)題的原因,上網(wǎng)驗(yàn)證發(fā)現(xiàn)你回答的和我測(cè)試的一樣。有緣多多交流啊,QQ:379172684。
          頂!

          # re: 一個(gè)關(guān)于Java Socket的問(wèn)題,大家看一下  回復(fù)  更多評(píng)論   

          2011-08-10 16:25 by careinlost
          我遇到了相同的問(wèn)題,
          當(dāng)我在客戶端使用shutdownoutput時(shí),服務(wù)端并未能完全獲取全部數(shù)據(jù)就拋出異常了,嘗試了client線程等待也不行。

          有什么辦法能夠使客戶端shutdownoutput前讓服務(wù)端接收完數(shù)據(jù),而不是在while(read)中等待?

          # re: 一個(gè)關(guān)于Java Socket的問(wèn)題,大家看一下  回復(fù)  更多評(píng)論   

          2011-12-28 10:10 by Jawe
          樓主V5,解決了困擾我一天的問(wèn)題

          # re: 一個(gè)關(guān)于Java Socket的問(wèn)題,大家看一下  回復(fù)  更多評(píng)論   

          2012-09-26 09:25 by 飛飛俠
          看了半天,樓主還是沒(méi)有解決問(wèn)題啊
          主站蜘蛛池模板: 施秉县| 伊宁市| 隆化县| 寿阳县| 浏阳市| 乐业县| 济南市| 安陆市| 利津县| 沭阳县| 游戏| 三穗县| 兴国县| 鄂尔多斯市| 彩票| 蒙山县| 六安市| 斗六市| 江西省| 静海县| 兰考县| 赤峰市| 浦城县| 通江县| 贵德县| 牙克石市| 连江县| 纳雍县| 金沙县| 彩票| 运城市| 陵水| 松江区| 长沙县| 洪雅县| 湖南省| 泰宁县| 阿城市| 德化县| 宁国市| 临漳县|