-------------------------------------------- 流结束,并不代表连接结束,如果只传送一次,你关掉可以,如果是持续性的,你还能关掉Socket吗?, 例如批量发送文件,发送开始的时间,最好设置一个标志位,一个文件发送结束的时间,改变这个标志位, 接收方根据标志位,来决定是继续接收,还是接收完毕,开始接收下一个文件. ------------------------------------- 不明白版主说的Socket是长连接是什么意思. Java当中的Socket类,其实是使用TCP协议进行传输的.TCP是可靠的一种传输协议.
如果版主想用TCP协议,并且,服务端和客户端,在没有信息进行传输的时候,也不断开连接,一般情况下,客户端会在Socket超时之前,想服务端发送一个用于维持连接的信息包,来维持连接.但是TCP协议,并不是指长连接.我们每天上网浏览网页,其实,也是以TCP协议为基本的传输协议的.只是,这个是短连接的形式,每次浏览器向服务器提交一个请求,服务短应答请求,然后断开连接.
在应用TCP协议,并且是长连接传输信息的情况下.通常会再封装一层协议的.但,观察版主的收发内容,并没有涉及这一层,所以,我这里并不知道是长连接.
首先,我们要明确一点,发送方如果不将输出流进行关闭,接收方就会认为输入流没有结束,直到超时. 其次,我们判断一个信息是否已经完全的读取完毕,除了使用输入流结束这种办法,还可以自行封装一层协议,用于信息的交互. 当然,我们也可以采用Http那样的交互方式进行信息的传递,但是,它是短连接的.
下面我来说一下,TCP长连接传输数据的一般做法. 一般情况下,我们会在TCP的基础上再封装一层协议,用户长连接的传输.协议的信息包,也分包头和包体两个部分. 包体,主要就是我们要传输的信息.(维持连接的信息包,包体可为空) 包头,一般分为三个部分.第一部分是信息包的长度(长度一般是指整个信息包的长度);第二部分是包体信息的类型(在这里指出是否是维持连接包);第三部分是信息包的序列号,一般情况下,这个序列号要确保在传输过程中唯一标识该信息包. 如果为了安全起见,还可以在包体后添加包尾,包尾数据用于对包体数据的验证)
这样,通信双方就可以根据包长来判断一次接收的操作是否结束了. -----------------------------------
//---------------------------输入流读取线程----------------------------- class printInputThread extends Thread { public void run() { //只有该线程读取该流. InputStream in = CommandExecutor.in; StringBuilder inputStr = new StringBuilder(); char ch;
try { while (!isInterrupted()) { //可读取的字节数 int canReadCount = in.available(); System.out.println("read available:"+canReadCount); if(canReadCount>0){ for(int i=0;i<canReadCount;i++){ inputStr.append((char)in.read()); } // 追加到结果区域 System.out.println("read available:"+inputStr.toString()); Start.mainFrame.appendResultText(inputStr.toString()); inputStr.delete(0, inputStr.length()); } //读取一个字节,无数据则阻塞 ch = (char)in.read(); inputStr.append(ch); System.out.println("read one:"+ch); } } catch (IOException e) { //执行exit命令时,连接会被断开,报SocketException:Connection reset //点“断开连接”按钮,中断该线程时,执行in.read()时,有可能流已经被关闭,报socket closed //点“断开连接”按钮,中断该线程时,in.read()方法被中断时,抛出InterruptedIOException异常 //如果正在执行in.available(),而流已经被关闭,报java.io.IOException: Stream closed //不能保证该线程的中断会在tc.disconnect()之前执行,即不能保证它在流关闭前被中断。 //干脆,SocketException也不抓了,也不详细区分异常类型,一律作为断开连接处理。 //断开tc的连接,切换界面状态 Start.mainFrame.disconnect();
//输出LOG以备查看 e.printStackTrace(); } System.out.println("printInputThread ended."); } }
这是我写的一段代码,问题是无法知道执行单次命令的返回信息在哪里结束。
一次的返回信息,in.read()可能要阻塞一两次才能完全读完。
它阻塞了,也不能代表这次数据就读完了。
头疼……
还是得找个返回信息结束标识字符才行……
|