明月松间照 清泉石上流


                                        ——— 兵临城下   猫科动物
posts - 70, comments - 137, trackbacks - 0, articles - 23
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

一个关于Java Socket的问题,大家看一下

Posted on 2006-04-29 17:05 兵临城下 阅读(5323) 评论(9)  编辑  收藏 所属分类: J2SE

一个关于Java Socket的问题,大家看一下:
我的目的是从client端发出一段字符串,server端接收后原样返回给客户端。
客户端:ConnClient  服务器端ConnSerer(完整源代码附在最后)

===client端===
建了一个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();
等待服务器端返回代码片段:
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端===
同样建了一个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);
}


问题来了:
1、如果按以上代码运行,server端可以收到client的信息,但client端却收不到返回的信息。为什么?
2、后来我把client端的clientout.close()注释掉后,一切正常,client端能收到server端返回的信息。这又为什么?
难道server端和client端用的是一个out流?为什么client端把out流关掉后(clientout.close()),server端就不能返回信息呢?

以我以前的理解,server端和client端建的两个输出流应该是独立的。不会因为我把client端的out流关掉后,server端out流就不能返回了?不会吧!呵呵!


还有一个问题:server端怎么判断client端数据已经发送完毕?
一开始,我用clientout.print("hello"),运行后,server端显示已经连接成功但一直侦听,没有收到信息,认为client端还没有发送完成。
后来,我改用clientout.println("hello"),运行后,一切正常,服务器端也收到信息(hello)。
从上看出server的地判定就是一个回车符,不知道这样认识对不对?大家指点!
经过我试验,如果client端print后,用clientout.close()也可以使server端接收到信息。但却不能返回信息。也就是我发现上面说述的问题来由。

以上几个问题,请大家和banq大哥多加指点!

源代码如下:
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();
 }
  }
}


评论

# re: 一个关于Java Socket的问题,大家看一下  回复  更多评论   

2006-05-02 17:45 by 兵临城下
经过几天的调试,初步有点心得,在我的blog上记录一下:
1、client端,clientout.close()语句表面上只是关闭了socket输出流,但从我的调试中发现,在关闭这个out流后,client就不能在取得socket,说明在关闭out流的同时,也隐式的关闭了socket。所以server端就无法返回数据了。解释我的第一和第二个问题。
2、关于server端判定client端是否信息发送完毕的信号问题。
从我几天的调试中,我总结出几点(可能还有其他的,请补充):
a、就是经常使用的out.println(out.print不行)
b、那就是关闭client端out流,out.close()。但这种方法却关闭了socket,显然不是大家所愿的。

# re: 一个关于Java Socket的问题,大家看一下  回复  更多评论   

2006-05-08 13:49 by 兵临城下
问题进行中……(实时纪录)
考虑到字节流的需要,在client端和server端都改用字节流DataInputStream和DataOutputStream,相应的输出方法使用out.write(byte[]) 。
问题一:此种输入输出流没有了out.println()方法,该怎么判定client端输出流的结束??
问题二:在client端,发送的信息的源分为两种,字符串和文件流。两种不同的输入流在server端接收判断结束时是否存在区别??

对于问题二,笔者有一些心得:
server端的接收代码段是:
byte[] sbyte = new byte[1024];
int len;
while((len = in.read(sbyte)) != -1) {
out.write(sbyte,0,len);
out.flush();
}

如果client端输入流为字符串,server端在接收完毕后,在while语句中不能正常跳出。而使用文件流时就可以跳出循环。

以上问题欢迎大家发表意见!

# re: 一个关于Java Socket的问题,大家看一下  回复  更多评论   

2006-05-08 21:12 by 兵临城下
更正一下,上面所说的文件流能顺利跳出循环不正确,其实不然。
实际上在client端传输完成后,server端while循环还是不能跳出,最后能够完整输出实际是在客户端强制关闭socket后,server端while才跳出循环的。
从以上我总结出,不管是字符流,还是文件流,都得附加一个标示符来标识client端传输的结束。

# re: 一个关于Java Socket的问题,大家看一下  回复  更多评论   

2006-05-12 12:19 by 兵临城下
又获益颇多啊!
再来说说这几天的心得:
关于这个socket,折腾了好几天了啊!
出现这个问题的初衷是:公司内想要实现java和C++的socket通讯。

关于这个java端(也就是client端)发送信息结束的判定问题总结如下:
如果server端也是java程序(C++我不是很了解),而且server端使用一个while循环读取数据时(类似于while((len = in.read(sbyte)) != -1) {}),即使client端发送完成,即while((len = inFile.read(bb)) != -1) {}循环语句跳出后,server端仍然在while语句中,不能正常跳出。因为server端认为你没有发送结束。
究其原因,我认为,因为在java socket中对于socket的input和output流结束,有一个socket方法来给出结束的标志:socket.shutdownOutput();socket.shutdownInput();

这两个方法为java socket判定client端发送结束的标志。

当然如果和我上述留言中所说的,使用特定设置的标志符当然是可以的。

# re: 一个关于Java Socket的问题,大家看一下[未登录]  回复  更多评论   

2009-02-28 22:11 by sunshine
如果通信协议用的是java默认的编码格式,客户端还是用BufferedReader.readline()方法,这个是以\r\n为界定符的。在你从socket产生bufferedReader的时候,PrintWriter clientout = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true)最后一个boolean标志是否在println()方法中自动调用outputstream.flush()把缓存的东西是否发送出去。否则还要自己再调用PrintWriter.flush()发送。而且这个println()后在你的数据后加上\r\n,用客户端的readline()正好可以读到你的数据,当然是去掉了\r\n.

如果你要使用自己的界定符,就不能使用BufferedReader,应该使用它的基类,在while(in.ready())循环中inputstream.read(),然后自己断开你的数据。这和串口的通信是一样。既然是输入流,当然收到是连续的字节数据,除非你制定一个界定符,否则系统怎么知道你发送完了?同时,还要注意发送字节的时候,两端的编码格式要一致。

# 回答得太好了  回复  更多评论   

2009-06-27 21:20 by 周小兵
哥们,你回答的太好了,这正是我遇到的问题,问题都和你一样的,我在看你的回答前,我已经测试过,找到了问题的原因,上网验证发现你回答的和我测试的一样。有缘多多交流啊,QQ:379172684。
顶!

# re: 一个关于Java Socket的问题,大家看一下  回复  更多评论   

2011-08-10 16:25 by careinlost
我遇到了相同的问题,
当我在客户端使用shutdownoutput时,服务端并未能完全获取全部数据就抛出异常了,尝试了client线程等待也不行。

有什么办法能够使客户端shutdownoutput前让服务端接收完数据,而不是在while(read)中等待?

# re: 一个关于Java Socket的问题,大家看一下  回复  更多评论   

2011-12-28 10:10 by Jawe
楼主V5,解决了困扰我一天的问题

# re: 一个关于Java Socket的问题,大家看一下  回复  更多评论   

2012-09-26 09:25 by 飞飞侠
看了半天,楼主还是没有解决问题啊

只有注册用户登录后才能发表评论。


网站导航: