如何使用socket进行java网络编程(五)
本篇记录:
1、再谈readLine()方法
2、什么是真正的长连接
最近又参与了一个socket的项目,又遇到了老生常谈的readLine()问题:对方通过其vb程序向我方socketServer程序发送报文,后天日志查看有read超时的异常。
关于line=readLine()方法,其为一个阻塞方法,遇到\r 、\n、\r\n时会返回此时为止读到的数据,作为“一行”赋值给line变量。而之后除非超时或者发送端关闭输出流,readLine()才会返回null,代表读取结束。也就是说如果不是超时或关闭流,那么readLine()读取完所有行之后仍然会一直阻塞。
下面代码为客户端的发送代码,红字为关键,正是其确保服务器端的readLine()方法结束阻塞。
Socket clientSocket = new Socket(address, port); LOGGER.debug("网络" + address + ":" + port + "初始化已经完成,服务端已连接!"); PrintWriter writer = new PrintWriter(clientSocket.getOutputStream()); try { // 向clientSocket中写入报文 Integer length = msg.toString().length(); String lengthStr = length.toString(); while (lengthStr.length() < 5) { lengthStr = "0" + lengthStr; } System.out.println(lengthStr + msg); writer.println(lengthStr + msg); writer.flush(); clientSocket.shutdownOutput(); LOGGER.debug("上送信息:" + lengthStr + msg); //等待回复 InputStream is = clientSocket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String str = br.readLine(); LOGGER.debug("读取返回信息:" + str); System.out.println(str); if (StringUtils.isNotEmpty(str) && str.startsWith("1|")) { isSucc = true; } clientSocket.shutdownInput(); } catch (Exception ex) { LOGGER.error("上送报文异常", ex); System.out.println(ex.getMessage()); isSucc = false; return isSucc; } finally { writer.close(); }
在C、VC、VB中也是一样的,因为网络通信底层是相通的:
最后,上述技术方案中实际上是使用TCP socket实现的一种短连接通信:客户端打开socket连接,然后发送报文,关闭输出流,接受服务端返回报文,关闭输入流,关闭连接; 服务端收到客户端socket连接,使用输入流接收上送的报文,处理,使用输出流向客户端发送返回报文。
那么真正的长连接是怎样的呢? 首先,长连接在于不是上述这种打开-发送-接收-返回-关闭的方式,而是在一段长时间内保持连接而不关闭,或者在连接空闲时超时关闭的时候,通过心跳检测机制,发现超时关闭而重新建立连接。与短连接相比,减少了打开-关闭连接的开销。