日期:2014-05-20  浏览次数:20777 次

问一个关于SocketInputStream的问题
在java中,InputStream 的 read() ,read(byte [] bs), read(byte [] bs, offset, length)方法在读到流结尾的时候,会返回-1

我们在读取数据的时候,会这么干:
Java code

byte [] bs = new byte[1024];
int i=0;
while((i=ins.read(bs))!=-1)
Log.debug("Client Read: " + i+" >> " ,bs);



现在从Socket中读取,遇到了一点问题,
服务器的socket数据早就写完了,可客户端上的read(byte [] b)就是不返回 -1,一直塞着
目前是用超时来解决了

可是老用超时会影响性能呀,为什么不会返回-1呢?API文档中可明明是写着的
难道服务器端发送的数据有问题?

服务器发送代码:
Java code
byte [] bs=t

这段代码应该不会有问题吧


输出流的结束标记是什么?难道还要手动发一个结束标记?才能让SocketInputStream返回-1


伙计们,不用提它建议,比如服务器发送的时候,加上数据长度...


我现在只是想知道为什么不能返回 -1,我的做法错在哪?
钻个牛角尖



------解决方案--------------------
服务端没有将输出流做关闭操作,所以,客户端无法感应到,是否已经是流的末尾.
楼主在服务端flush之后,close掉输出流,客户端读取时就会返回-1了.
------解决方案--------------------
探讨
TCP长连接在退出之前是不能关闭流的

------解决方案--------------------
数据读完之后关闭服务器断口的流
客服端就会返回-1
------解决方案--------------------
服务器端 Socket 发完数据后把输出流关掉 Socket.shutdownOutput();
------解决方案--------------------
tcp中发完数据后,主动关闭流,就会被感知到然后返回-1
------解决方案--------------------
探讨
tcp中发完数据后,主动关闭流,就会被感知到然后返回-1

------解决方案--------------------
ous.close()是必须的。
------解决方案--------------------
流结束,并不代表连接结束,如果只传送一次,你关掉可以,如果是持续性的,你还能关掉Socket吗?,
例如批量发送文件,发送开始的时间,最好设置一个标志位,一个文件发送结束的时间,改变这个标志位,
接收方根据标志位,来决定是继续接收,还是接收完毕,开始接收下一个文件.
------解决方案--------------------
探讨
流结束,并不代表连接结束,如果只传送一次,你关掉可以,如果是持续性的,你还能关掉Socket吗?,
例如批量发送文件,发送开始的时间,最好设置一个标志位,一个文件发送结束的时间,改变这个标志位,
接收方根据标志位,来决定是继续接收,还是接收完毕,开始接收下一个文件.

------解决方案--------------------
你去看看这个方法

setSoTimeOut();

你看了就知道他干啥用的....
------解决方案--------------------
兄弟,你用PrintWriter吧,这样readline()多好,
------解决方案--------------------
加条语句
ous.close();
引用数据读完之后关闭服务器断口的流
客服端就会返回-1

------解决方案--------------------
不明白版主说的Socket是长连接是什么意思.
Java当中的Socket类,其实是使用TCP协议进行传输的.TCP是可靠的一种传输协议.

如果版主想用TCP协议,并且,服务端和客户端,在没有信息进行传输的时候,也不断开连接,一般情况下,客户端会在Socket超时之前,想服务端发送一个用于维持连接的信息包,来维持连接.但是TCP协议,并不是指长连接.我们每天上网浏览网页,其实,也是以TCP协议为基本的传输协议的.只是,这个是短连接的形式,每次浏览器向服务器提交一个请求,服务短应答请求,然后断开连接.

在应用TCP协议,并且是长连接传输信息的情况下.通常会再封装一层协议的.但,观察版主的收发内容,并没有涉及这一层,所以,我这里并不知道是长连接.

首先,我们要明确一点,发送方如果不将输出流进行关闭,接收方就会认为输入流没有结束,直到超时.
其次,我们判断一个信息是否已经完全的读取完毕,除了使用输入流结束这种办法,还可以自行封装一层协议,用于信息的交互.
当然,我们也可以采用Http那样的交互方式进行信息的传递,但是,它是短连接的.

下面我来说一下,TCP长连接传输数据的一般做法.
一般情况下,我们会在TCP的基础上再封装一层协议,用户长连接的传输.协议的信息包,也分包头和包体两个部分.
包体,主要就是我们要传输的信息.(维持连接的信息包,包体可为空)
包头,一般分为三个部分.第一部分是信息包的长度(长度一般是指整个信息包的长度);第二部分是包体信息的类型(在这里指出是否是维持连接包);第三部分是信息包的序列号,一般情况下,这个序列号要确保在传输过程中唯一标识该信息包.
如果为了安全起见,还可以在包体后添加包尾,包尾数据用于对包体数据的验证)

这样,通信双方就可以根据包长来判断一次接收的操作是否结束了.