为什么使用Socket传送文件时总是会丢失数据,请大神帮忙看一下!

axr1985lazy 2014-07-27 11:48:39
先上代码:

import java.io.*;
import java.net.*;
import java.util.*;
import java.text.*;

class PicClient{
public static void main(String[] args){
//创建本地Socket服务,并连接服务器。
String serverIP = null;
Socket so = null;
try{
serverIP = InetAddress.getLocalHost().getHostAddress();
so = new Socket(serverIP, 23235);
}
catch(UnknownHostException e1){
throw new RuntimeException("无法确定服务器IP地址!");
}
catch(IOException e2){
throw new RuntimeException("连接服务器失败!");
}
System.out.println("成功连接至"+serverIP+"服务器。");

//向服务器发送文件名。
File file = null;
OutputStream out = null;
DataOutputStream soDos = null;
try{
out = so.getOutputStream();
soDos = new DataOutputStream(out);
file = new File("D:\\java_samples\\23rd_day\\files\\7.jpg");

soDos.writeUTF(file.getName());
soDos.flush();
}
catch (IOException e){
throw new RuntimeException("获取本地Socket服务输出流失败,或者未与服务器连接!");
}

//发送文件
BufferedInputStream soBis = null;
BufferedOutputStream soBos = null;
try{
soBis = new BufferedInputStream(new FileInputStream(file));
soBos = new BufferedOutputStream(so.getOutputStream());
byte[] buf = new byte[1024*5];
int len = 0;

while((len = soBis.read(buf, 0, 1024*5)) != -1){
soBos.write(buf, 0, len);
}
}
catch (IOException e){
throw new RuntimeException("读取文件时发生异常,或者向Socket流中写入数据时出现异常");
}
finally{
try{
if(soBis != null)
soBis.close();
}
catch (IOException e){
throw new RuntimeException("文件读取流关闭失败!");
}
}

//关闭本地Socket写入流,并向服务器发送结束标记,便于停止接收循环
try{
so.shutdownOutput();
}
catch (IOException e){
throw new RuntimeException("关闭本地Socket服务写入流失败!");
}

//接受服务器发送的上传成功信息
DataInputStream soDis = null;
try{
soDis = new DataInputStream(so.getInputStream());

System.out.println(soDis.readUTF());
}
catch (IOException e){
throw new RuntimeException("获取本地Socket读取流失败,或者接受服务器信息失败!");
}

try{
so.close();
}
catch (IOException e){
throw new RuntimeException("关闭本地Socket服务失败!");
}
}
}

class PicServer{
public static void main(String[] args){

//创建服务器端ServerSocket服务,并与客户端连接,获取客户端Socket服务对象。
ServerSocket ss = null;
Socket so = null;
try{
ss = new ServerSocket(23235);
so = ss.accept();
System.out.println(so.getInetAddress().getLocalHost().getHostAddress()+" 成功连接本机。");
}
catch (UnknownHostException e1){
throw new RuntimeException("无法获取客户端IP地址!");
}
catch(IOException e2){
throw new RuntimeException("创建服务器ServerSocket服务失败,或者未能接收客户端Socket服务对象!");
}

//接收客户端发送的文件名,并添加时间创建该文件。
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String time = sdf.format(date);
InputStream in = null;
DataInputStream dis = null;
File file = null;
try{
in = so.getInputStream();
dis = new DataInputStream(in);
String fileName = dis.readUTF();
System.out.println(fileName);
file = new File("D:\\java_samples\\23rd_day\\files", time+"_"+fileName);
if(!file.exists())
file.createNewFile();
}
catch (IOException e){
throw new RuntimeException("获取客户端Socket读取流失败,或者文件创建失败!");
}

//接收文件
BufferedInputStream soBis = null;
BufferedOutputStream bos = null;
byte[] buf = new byte[1024*5];
int len = 0;
try{
soBis = new BufferedInputStream(so.getInputStream());
bos = new BufferedOutputStream(new FileOutputStream(file));
while((len = soBis.read(buf, 0, 1024*5)) != -1){
bos.write(buf, 0, len);
}
}
catch (IOException e){
throw new RuntimeException("客户端Socket服务读取流读取数据失败,或者文件数据写入失败!");
}
finally{
try{
if(bos != null)
bos.close();
}
catch (IOException e){
throw new RuntimeException("文件写入流关闭失败!!");
}
}

//向客户端发送上传成功信息。
OutputStream out = null;
DataOutputStream soDos = null;
try{
out = so.getOutputStream();
soDos = new DataOutputStream(out);
soDos.writeUTF("上传成功!");
soDos.flush();
}
catch (IOException e){
throw new RuntimeException("获取客户端Socket写入流失败!");
}

//关闭所有资源
try{
so.close();
ss.close();
}
catch (IOException e){
throw new RuntimeException("客户端Socket服务关闭失败,或者服务器ServerSocket服务关闭失败!");
}
}
}


刚学Java不久,写的一个练习代码,模拟客户端享服务端上传图片。
每次用这段代码进行传输,服务端收到的文件总是比源文件小几kb,调试了很久,也在论坛搜索过,按照人家的方法修改,还是会出现数据丢失的现象,希望大家帮忙解决一下,最好能说一下原因,小弟在此跪谢!
...全文
353 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
sca4441479 2014-07-29
  • 打赏
  • 举报
回复
引用 4 楼 axr1985lazy 的回复:
write完后flush就行,没必要放在finally里,一般finally是放流关闭/资源释放 等必要操作的。
非常感谢,问题确实解决了。通过这个问题说明我对带缓冲的输入输出流理解的还是不够。 我想再问一下: 1.调用write方法将数据写入流以后,flush的作用是不是,将流中的数据确实发送给服务端的读取流,并清空缓冲(字节数组)? 2.我遇到的现象是,每次图片都少3kb,也就是最后一小块无法显示,但是图片其他部分是可以正常显示的,我是不是可以理解为最后一部分数据还在流中,因为为没有刷新所以没能确实发送给服务端的读取流?同时,即使不调用flush方法,而是每次调用write方就会发送流中的数据,并清空缓存,然后再写入下1kb的数据? 拜托大神再帮帮小弟!!![quote] 1,是的 2,出于性能和效率考虑,缓冲区可能会将一部分数据保留在缓冲区,先不发送过去,等到下次调用write方法,之前的缓存的数据可能就发出去,本次的数据继续保留在缓冲区。flush方法强制将本次数据从缓冲区发送出去,刷新清空缓冲区。
axr1985lazy 2014-07-29
  • 打赏
  • 举报
回复
引用 5 楼 sca4441479 的回复:
[quote=引用 4 楼 axr1985lazy 的回复:] write完后flush就行,没必要放在finally里,一般finally是放流关闭/资源释放 等必要操作的。
非常感谢,问题确实解决了。通过这个问题说明我对带缓冲的输入输出流理解的还是不够。 我想再问一下: 1.调用write方法将数据写入流以后,flush的作用是不是,将流中的数据确实发送给服务端的读取流,并清空缓冲(字节数组)? 2.我遇到的现象是,每次图片都少3kb,也就是最后一小块无法显示,但是图片其他部分是可以正常显示的,我是不是可以理解为最后一部分数据还在流中,因为为没有刷新所以没能确实发送给服务端的读取流?同时,即使不调用flush方法,而是每次调用write方就会发送流中的数据,并清空缓存,然后再写入下1kb的数据? 拜托大神再帮帮小弟!!!
引用
1,是的 2,出于性能和效率考虑,缓冲区可能会将一部分数据保留在缓冲区,先不发送过去,等到下次调用write方法,之前的缓存的数据可能就发出去,本次的数据继续保留在缓冲区。flush方法强制将本次数据从缓冲区发送出去,刷新清空缓冲区。
感谢大神非常耐心的解答和帮助,把分加满,虽然不多,聊表心意~
血饮 2014-07-28
  • 打赏
  • 举报
回复
引用 1 楼 sca4441479 的回复:
50行位置,把文件写到流后flush刷新一下。
就这个问你我也问一下,应该是bos调用write 写法后flush还是应该在finally代码块 flush??
sca4441479 2014-07-28
  • 打赏
  • 举报
回复
50行位置,把文件写到流后flush刷新一下。
axr1985lazy 2014-07-28
  • 打赏
  • 举报
回复
引用 3 楼 sca4441479 的回复:
write完后flush就行,没必要放在finally里,一般finally是放流关闭/资源释放 等必要操作的。
非常感谢,问题确实解决了。通过这个问题说明我对带缓冲的输入输出流理解的还是不够。 我想再问一下: 1.调用write方法将数据写入流以后,flush的作用是不是,将流中的数据确实发送给服务端的读取流,并清空缓冲(字节数组)? 2.我遇到的现象是,每次图片都少3kb,也就是最后一小块无法显示,但是图片其他部分是可以正常显示的,我是不是可以理解为最后一部分数据还在流中,因为为没有刷新所以没能确实发送给服务端的读取流?同时,即使不调用flush方法,而是每次调用write方就会发送流中的数据,并清空缓存,然后再写入下1kb的数据? 拜托大神再帮帮小弟!!!
sca4441479 2014-07-28
  • 打赏
  • 举报
回复
write完后flush就行,没必要放在finally里,一般finally是放流关闭/资源释放 等必要操作的。

62,614

社区成员

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

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