刚刚项目使用到socket进行数据的传送,其中数据的读取问题着实
费了老大的劲,以此分享希望能让有缘人少走弯路。
new Thread() {
@Override
public void run() {
try {
mSocket = new Socket(SERVICEADD, DST_PORT);
//设置socket读取数据流的超时时间
mSocket.setSoTimeout(5000);
mSocket.setTcpNoDelay(true);
//设置客户端close()方法起作用时延时30s关闭socket
mSocket.setSoLinger(true, 30);
mSocket.setSendBufferSize(4096);
//防止服务器端无效时,客户端长时间处于连接状态
mSocket.setKeepAlive(true);
OutputStream ou = mSocket.getOutputStream();
//向服务器发送要查询的数据
ou.write(queryContent.getBytes());
ou.flush();
//读取发来服务器信息
BufferedReader br = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
List<QueryDatas> queryDatases = QueryFomart.formatSocketString(br);
EventBus.getDefault().post(queryDatases);
br.close();
mSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
对于使用readLine读取数据的一个问题就是,无法走到while后面去,究其原因:
1.误以为readLine()是读取到没有数据时就返回null(因为其它read方法当读到没有数据时返回-1),而实际上readLine()是一个阻塞函数,当没有数据读取时,就一直会阻塞在那,而不是返回null;因为readLine()阻塞后,System.out.println(message)这句根本就不会执行到,所以在接收端就不会有东西输出。要想执行到System.out.println(message),一个办法是发送完数据后就关掉流,这样readLine()结束阻塞状态,而能够得到正确的结果,但显然不能传一行就关一次数据流;另外一个办法是把System.out.println(message)放到while循环体内就可以。
2.readLine()只有在数据流发生异常或者另一端被close()掉时,才会返回null值。
3.如果不指定buffer大小,则readLine()使用的buffer有8192个字符。在达到buffer大小之前,只有遇到”/r”、”/n”、”/r/n”才会返回。
小结,使用readLine()一定要注意:
1、读入的数据要注意有/r或/n或/r/n
2、没有数据时会阻塞,在数据流异常或断开时才会返回null
3、使用socket之类的数据流时,要避免使用readLine(),以免为了等待一个换行/回车符而一直阻塞
4、或者是服务器端在发送完数据就进行关闭