问一个关于SocketInputStream的问题

laoxing521 2008-06-20 11:51:51
在java中,InputStream 的 read() ,read(byte [] bs), read(byte [] bs, offset, length)方法在读到流结尾的时候,会返回-1

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

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文档中可明明是写着的
难道服务器端发送的数据有问题?

服务器发送代码:
byte [] bs= "0123456789abcde".getBytes();
Log.debug("Server Writer: ",bs);
ous.write(bs);
ous.flush();

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


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


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


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

...全文
1093 30 打赏 收藏 转发到动态 举报
写回复
用AI写文章
30 条回复
切换为时间正序
请发表友善的回复…
发表回复
liu734197637 2012-08-06
  • 打赏
  • 举报
回复
遇到过了,正在求解中
rocket_2008 2008-07-03
  • 打赏
  • 举报
回复
所有的贴子看完了,我觉得本质的一些问题还没有解决掉.
可以看http://topic.csdn.net/u/20080626/09/18db2301-f672-4ec8-aaa8-bf8c75489893.html
SUN公司就是因为这样的结束流的方式不好处理,才让我们用包装流来解决.
我们用字节流来读取数据的时候,就因为返回不了-1这种情况需要做很多的判断,首先一点,连接是不能是短连接.
这样的问题有时候讨论可以看着是多余的,我其实不这么看,但有人告诉我他是这样的看法,既然是readLine()方法,就不必用read()方法.
但是原理我们还是要知道.
流的结束如果不是文件的话是不以-1结尾的,所以不可能返回-1,所以当没有关闭连接时或没有调用shutdownInput()方法时是一直阻塞的.
我想过用什么办法从服务端写一个-1过来,但是事实告诉我这种方法是很行不通的.
有两种方案来结束流:
1\让客服端自己来判断流是束结束(根据读取的信息)
2\从服务端告诉客服端一个信息
在第一种方法中,有一个问题(或者说我们自己制造的一个问题):
byte [] by = new byte[1024];
while((num = in.read(by)) != -1){
if(num < by.length){//当读取的数据的长度小于by的长度时,认为读到了末尾了.
//do something
break;
}
}

这里的问题是我们能不能判断出数据的长度刚好了by数组长度的倍数的情况呢.
为是解决这个办法,应可能的用包装流来读写,好处是速度快,方便.
laoxing521 2008-06-27
  • 打赏
  • 举报
回复
结帐
hmsuccess 2008-06-20
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 laoxing521 的回复:]
TCP长连接在退出之前是不能关闭流的
[/Quote]
那这就跟tcp有关系了,tcp在断开连接前(FIN标记),c/s双方是协商好的
同时SocketInputStream还没返回-1,是因为你的client端的流对象还没结束
laoxing521 2008-06-20
  • 打赏
  • 举报
回复
TCP长连接在退出之前是不能关闭流的
冰思雨 2008-06-20
  • 打赏
  • 举报
回复
服务端没有将输出流做关闭操作,所以,客户端无法感应到,是否已经是流的末尾.
楼主在服务端flush之后,close掉输出流,客户端读取时就会返回-1了.
npuhetao 2008-06-20
  • 打赏
  • 举报
回复
分好多,帮顶...
[Quote=引用 1 楼 java2000_net_test 的回复:]
此回复为自动发出,仅用于显示而已,并无任何其他特殊作用
楼主截止到2008-06-20 11:51:52的汇总数据:
注册日期:2003-9-23
上次登录:2008-6-20
发帖数:8 发帖分:786
结贴数:5 结贴分:486
结贴率:62.50% 结分率:61.83%
楼主加油
[/Quote]
Bestkiller 2008-06-20
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 Bestkiller 的回复:]
服务器的socket数据早就写完了,可客户端上的read(byte [] b)就是不返回 -1,一直塞着
---------------------------------------------------------------------------------------
数据是写完了。但连接还建立着啊。LZ可在服务器端调用close操作。这样你客户端就会返回-1。


[/Quote]
应该返回的是0
Bestkiller 2008-06-20
  • 打赏
  • 举报
回复
服务器的socket数据早就写完了,可客户端上的read(byte [] b)就是不返回 -1,一直塞着
---------------------------------------------------------------------------------------
数据是写完了。但连接还建立着啊。LZ可在服务器端调用close操作。这样你客户端就会返回-1。

Bestkiller 2008-06-20
  • 打赏
  • 举报
回复
LZ这样理解不对。
read返回-1是作为判断socket流关闭的标志。即如果双方之间的连接中断。
默认使用socket输入流都是阻塞形式。
不过可以使用如下方式来实现无阻塞的读取数据:
BufferedInputStream bis = new BufferedInputStream(client.getInputStream()) //其中client为socket客户端对象
int num = bis.available(); ////返回不受阻塞可读取的输入流的字符数

if (num == 0){ //表示输入流中没有可读取的数据
//do something
}else{//输入流有数据,其中num表示有多少字节的数据
byte buf[]=new byte[num];
int i= bis.read(buf);
}
laoxing521 2008-06-20
  • 打赏
  • 举报
回复
回19楼:

TCP长连接,短连接是指

基于TCP协议的连接

长连接:指通信双方连接建立后不再关闭,在通信正常情况下一直保持连通状态,双方在收发数据时不再重新建立连接. 有点像打电话,你一句我一句,不用挂断
短连接:指通信双方每次通信时建立连接,通信结束后关闭连接。有点像发短信。
hmsuccess 2008-06-20
  • 打赏
  • 举报
回复
在长连接时,通讯协议中报文长度信息是必不可小的,我认为协议中有报文长度一段,最初的出发点就在这里。 如果发送方不说明报文长度,那么接收方在收完数据后就只能阻塞直到超时。这样对性能影响是非常大的
这也跟timeout有相当大的关系,
laoxing521 2008-06-20
  • 打赏
  • 举报
回复
说说俺现在的理解:

在长连接中,对方的输出流不close掉,那么己方的输入流是返回不了-1的

为了解决这个问题,对方在发送报文的时候就会在一个约定段上加上报文长度。己方在收到报文后,根据报文中说明报文长度的,读取指定的字节数
读完之后,若发送方还有数据过来,就不理它了或者当做下一个报文来处理

如果己方还未读足报文中说明的字节数量对方就没发了,那么己方就继续等待,在指定时间之后还没有读足数据,就报超时

报文长度加上报文中的数据格式定义等信息,就成了通讯协议


小结:
在长连接时,通讯协议中报文长度信息是必不可小的,我认为协议中有报文长度一段,最初的出发点就在这里。
如果发送方不说明报文长度,那么接收方在收完数据后就只能阻塞直到超时。这样对性能影响是非常大的

KOOK_OKKO 2008-06-20
  • 打赏
  • 举报
回复
可不可以考虑把timeout设置的短一点
冰思雨 2008-06-20
  • 打赏
  • 举报
回复
不明白版主说的Socket是长连接是什么意思.
Java当中的Socket类,其实是使用TCP协议进行传输的.TCP是可靠的一种传输协议.

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

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

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

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

这样,通信双方就可以根据包长来判断一次接收的操作是否结束了.
zhizhuo89 2008-06-20
  • 打赏
  • 举报
回复
加条语句
ous.close();
[Quote]数据读完之后关闭服务器断口的流
客服端就会返回-1[/Quote]
nec_3366 2008-06-20
  • 打赏
  • 举报
回复
nec_3366 2008-06-20
  • 打赏
  • 举报
回复
laoxing521 2008-06-20
  • 打赏
  • 举报
回复
呵呵

3楼讲的没错,但是TCP长连接,输出流是不能关闭的

11楼讲的更深入一些,流结束了,并不表示连接结束. 可是流关闭了,那连接也就跟着关闭了,所以,眼前的问题也可以说是怎样让流结束而连接不关闭
输入流的读取没有返回-1,就是因为没有读到结束标记嘛

13楼呢,呵呵,现在就是用超时来解决问题的,但这不是根本之法,老用超时,对性能影响太大

14楼的兄弟,readline方法是读取一行数据,在回车换行为结束标记,它是字符流,并非字节流



对这些底层的东东,研究很少

看了以上各位的高见,看来不把输出流close掉,那输入流中是返回不了-1的了罗?

cpoysy 2008-06-20
  • 打赏
  • 举报
回复
兄弟,你用PrintWriter吧,这样readline()多好,
加载更多回复(8)
Java远程监控系统设计及功能介绍 Java Java远程监控系统是一个C/S系统,分为服务器端和客户端两部分。服务端与客户端 建 立远程连接,可以抓取客户端的图像,还可以进行远程操作。要实现Java远程监控 系统, 主要是通过以下几个功能设计实现。 Socket 1.Socket,ServerSocket Socket位于java.net.包中,是网络通信重要的类,Socket中文称它为套接 字,ServerSocket 构造一对通信套接字方法如下 ServerSocketsr=newServerSocket(port); Socketsc=newSocket("ip",port); 其中ServerSocket的accpet方法十分重要,当一个服务套接字建立之后它一直阻塞 等待一 个套接字的请求,直到建立连接。 套接字=ip+port;一个套接字是由一个一个ip地址和一个端口组成的,在网络通信 中的底层实现也的确如此,要一个进程通信就必须为之制定工作端口,在连接端口之后 才能在该 端口上通信. 2.InputStream,OutputStream 当一个套接字连接成功后就可以获得基于这个套接字的输入输出流,一切数据的发 送和接受 都离不开输出输入流,我们可以通过流封装的方法选择你要输入或者输出的数据类 型. Robot java的Robot对象可以完成屏幕图像截取操作,控制鼠标,键盘。Robotrobot=newR obot(); Bufferedlmageimage=robot.createScreenCapture(rect); UDP 网络传输选用TIP/IP协议组中的UDP,UD物供的是无连接的传送方式。 主控端和被控端通过UDR!行指令交互 /*-主控端向被控端发送指令-*/ Stringcommand=...;//指令 InetAddressinet=...;//被控端地址 intport=...;//端口 bytesp[]=command.getBytes(); DatagramPacketpacket=newDatagramPacket(sp,sp.length(),inet,port); DatagramSocketsd=newDatagramSocket(); sd.send(packet); /*-被控端接收指令-*/ DatagramSocketstockUDP=...; DatagramPacketpacket=...; stockUDP.receive(packet); Stringmessage=newString(packet.getData(),0,packet.getLength());// 得到指令 本程序中用到的指令 publicstaticfinalStringCommand_Connection="connection";//建 立连接 publicstaticfinalStringCommand_Disconnection= "disconnection";//断开连接 publicstaticfinalStringCommand_Screen="screen";//显示被控端屏 ,rt- 帚 publicstaticfinalStringCommand_Control="control";//建立控制套接 JPEG JPEG勺压缩和解码,可以大大优化传输过程中的带宽占用,提高程序运行效率 /*-被控端开启图像传送线程-*/ Socketsocket=...; OutputStreamout=socket.getOutputStream(); BufferedImageimage; JPEGImageEncoderencoder=JPEGCodec.createJPEGEncoder(out); //JPEG图像的压缩 publicvoidrun(){ while(true){ image=...;//获取屏幕图像 encoder.encode(image);//发送图像给主控端 Thread.sleep(Environment.IMAGE_GETTIME);//图像采集时间隔 ) /*-主控端图像接收线程-*/ JPEGImageDecoderde= JPEGCodec.createJPEGDecoder(socket.getInputStream()); //JPEG图像的解码 BufferedImageimage=null; publicvoidrun(){ while(true){ image=de.decodeAsBufferedImage(); if(image!=null){ /*显示图像*/ ) ) ) /*-图像显示-*/ publicclassContr

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧