Socket s = new Socket("192.168.218.2", 58100);
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String info = null;
while(!((info=br.readLine())==null)){
System.out.println(info);
}
以上是部分代码,主要是readLine这句,接收字符串的时候,最后一行接收不到,while之后的代码也没有执行,程序处于一个挂起的状态。
上网查了下资料,好像是说最后一行没有回车符,我在服务端加了回车符之后,还是跳不出循环。。。
解决:
readLine只有读取文件等的结尾才会是null
在网络上(都是阻塞模式),readLine是一直等待输入,
即使是对方什么也不输入,只是回车,readLine也不会返回null,所以无法跳出while循环。
在I/O阻塞模式下,你写的条件循环while((line = in.readLine()) != null)是不合理的。
两种方法解决:
(1)双方约定每次发送报文都报文前几个字符表示长度信息,如下
原始报文是:ASDF
发送的socket报文是:0004ASDF
其中0004表示报文长度,接收方先接收四位的长度,再接收余下的报文。
(2)双方约定一个特殊的标志是结束符,比如约定 ==END== 表示结束
代码修改为while(!"==END==".equals(line = in.readLine()))就继续等待接收
这个特殊的结束符需要双方发送报文结束必须再发送的。
第一种解决方法是最常用的。自己接触的几个项目都是此种方式。
附加第一种方法的用法:
byte[] msgHead = new byte[5];// 双方约定前五位表示报文长度
in.read(msgHead, 0, msgHead.length);// 首先读取报文长度信息
String msgLength = new String(msgHead, getEncoding());
int msgLengthInt = Integer.parseInt(msgLength);
byte[] msgBody = new byte[msgLengthInt];// new一个报文长度大小的字节数组
in.read(msgBody, 0, msgBody.length);// 读取报文信息
byte[] recMsg = new byte[msgHead.length + msgBody.length];// 如有需要合并报文长度和报文信息
System.arraycopy(msgHead, 0, recMsg, 0, msgHead.length);
System.arraycopy(msgBody, 0, recMsg, msgHead.length, msgBody.length);
第二种方式,要双方约定一个结束符才能工作,而且存在bug。
对于很多特殊字符或者字节等在传输中转换为String会失真,则双方无法正常通讯。
例如:
byte[] b1 = new byte[10];
for (int i = 0; i < 10; i++) {
b1[i] = (byte) (i - 5);
}
byte[] b2 = new String(b1).getBytes();
for (int i = 0; i < 10; i++) {
System.out.println(b1[i] + " <-> " + b2[i]);
}
输出结果显示byte[]在转换为String在转换为byte[]时候已经失真。
byte[] --> String --> byte[] 发生失真问题参见另一篇文章
http://blog.csdn.net/fl772333621/article/details/10162447