用socket写了一个客户端向服务端传送文件的小程序,但是传送过去的文件总是比客户端原来的文件小一些,导致传送过去的文件都不能用,请问这个会是什么原因导致的呢,这个是不是就是传送中丢包的情况呢

解决方案 »

  1.   

    哈哈,又是楼主啊,还在弄socket传送文件的程序啊,帮你顶把
      

  2.   

    客户端代码:package com.ydz.client.socket;import java.io.*;
    import java.net.*;public class SocketClient { public static void main(String[] args)
    {
    Socket s = null;
    try{
    File file = new File("F://java文档资料//api//html_zh_CN.zip");
    //FileInputStream fis = new FileInputStream(file);
    DataInputStream fis = new DataInputStream(new FileInputStream(file));
    long fileSize = fis.available();
    String fileName = file.getName();
    s = new Socket("127.0.0.1", 10000);
    System.out.println("已经连接上服务器");
    DataOutputStream os = new DataOutputStream(s.getOutputStream());
    PrintWriter pw = new PrintWriter(os, true);
    pw.println(fileSize);
    pw.println(fileName);
    //os = new BufferedOutputStream(os);
    byte[] buffer = new byte[1024];

    int len = 0;
    while((len = fis.read(buffer, 0, 1024)) != -1){
    os.write(buffer, 0, len);
    os.flush();
    }
    os.close();
    fis.close();
    s.close();
    } catch (IOException e){
    e.printStackTrace();
    } finally {
    try{
    if(s != null)
    s.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    }服务端代码:package com.ydz.server.socket;import java.io.*;
    import java.net.*;import com.ydz.server.thread.inceptfile.InceptFileThread;public class SocketServer { public void start()
    {
    try{
    ServerSocket ss = new ServerSocket(10000);
    System.out.println("等待客户端连接");
    int i = 1;
    while(true){
    Socket s = ss.accept();
    System.out.println("第"+String.valueOf(i)+"客户端连接进来了");
    InceptFileThread ifThread = new InceptFileThread(s, i);
    ifThread.start();
    i++;
    }
    } catch (IOException e){
    e.printStackTrace();
    }
    }

    public static void main(String[] args)
    {
    SocketServer ss = new SocketServer();
    ss.start();
    }
    }
    服务端线程代码:package com.ydz.server.thread.inceptfile;import java.io.*;
    import java.net.Socket;public class InceptFileThread extends Thread { private Socket s;
    private int fileNumber;

    public InceptFileThread(Socket s, int fileNumber){
    this.s = s;
    this.fileNumber = fileNumber;
    }

    public void run(){
    try{
    DataInputStream is = new DataInputStream(s.getInputStream());
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    System.out.println("第"+String.valueOf(fileNumber)+"个文件开始上传");
    String fileSizeStr = br.readLine();
    System.out.println("文件长度"+fileSizeStr);
    String fileName = br.readLine();
    System.out.println("文件名称"+fileName);
    StringBuilder filePath = new StringBuilder();
    filePath.append("E://主服务器//file")
    .append(fileNumber);
    File fileCatalog = new File(filePath.toString());
    if(!fileCatalog.exists())
    fileCatalog.mkdirs();
    filePath.append("//").append(fileName);
    File file = new File(filePath.toString());
    //FileOutputStream fos = new FileOutputStream(file);
    DataOutputStream fos = new DataOutputStream(new FileOutputStream(file));
    byte[] buffer = new byte[1024];
    System.out.println("开始接收文件");
    int len = 0;
    while((len = is.read(buffer, 0, 1024)) != -1){
    fos.write(buffer, 0, len);
    fos.flush();
    }
    is.close();
    fos.close();
    System.out.println("文件"+fileNumber+"上传完毕");
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
      

  3.   

    byte[] buffer = new byte[1024*5];
    数组改大点试试
      

  4.   

    1).将SocketClient类中的以下几行代码注释掉 PrintWriter pw = new PrintWriter(os, true);
     pw.println(fileSize);
     pw.println(fileName);
    2).将InceptFileThread类中以下几行代码注释掉String fileSizeStr = br.readLine();
    System.out.println("文件长度"+fileSizeStr);
    String fileName = br.readLine();
    System.out.println("文件名称"+fileName);
    3).将InceptFileThread其他用到文件名的地方自己再做相应调整即可!
      

  5.   

    用有缓冲功能的bufferoutputstream试一下把,应该不会是大小的问题嘿嘿,帮你顶。
      

  6.   

    用有缓冲功能的bufferoutputstream试一下把,应该不会是大小的问题嘿嘿,帮你顶。
      

  7.   

    感谢你一直关注我的帖子,不过BufferedOutputStream我已经试过了,真的不好用,效果和数组小的时候是一样的,把数组设大了可以正常。
      

  8.   

    呵呵,楼主,不好意思,昨天没有看帖子。
    你所说的“丢失数据的问题”:
    字符流的话一般用于读取字符、数字类型的文本,
    而字节流的话一般用于读取图片、还有就是你说的rar文件那些,所以上一个帖子的发送rar的时候会出现文件不完整那些,我想应该也是这原因吧。
    现在这个帖子,我刚刚试了一下,你改一下就可以了://服务端
    package test2;import java.io.*;
    import java.net.*;
    public class SocketServer {    public void start()
        {
            try{
                ServerSocket ss = new ServerSocket(10000);
                System.out.println("等待客户端连接");
                int i = 1;
                while(true){
                    Socket s = ss.accept();
                    System.out.println("第"+String.valueOf(i)+"客户端连接进来了");
                    InceptFileThread ifThread = new InceptFileThread(s, i);
                    ifThread.start();
                    i++;
                }
            } catch (IOException e){
                e.printStackTrace();
            }
        }
        
        public static void main(String[] args)
        {
            SocketServer ss = new SocketServer();
            ss.start();
        }
    }class InceptFileThread extends Thread {    private Socket s;
        private int fileNumber;
        
        public InceptFileThread(Socket s, int fileNumber){
            this.s = s;
            this.fileNumber = fileNumber;
        }
        
        public void run(){
            try{
                DataInputStream is = new DataInputStream(s.getInputStream());
                //BufferedReader br = new BufferedReader(new InputStreamReader(is));
                System.out.println("第"+String.valueOf(fileNumber)+"个文件开始上传");
                String fileName = is.readUTF();//.readLine();
                System.out.println("文件名称"+fileName);
                String fileSizeStr = is.readUTF();//.readLine();
                System.out.println("文件长度"+fileSizeStr);
                StringBuilder filePath = new StringBuilder();
                filePath.append("c://file")
                        .append(fileNumber);
                File fileCatalog = new File(filePath.toString());
                if(!fileCatalog.exists())
                    fileCatalog.mkdirs();
                filePath.append("//").append(fileName);
                File file = new File(filePath.toString());
                //FileOutputStream fos = new FileOutputStream(file);
                DataOutputStream fos = new DataOutputStream(new FileOutputStream(file));
                byte[] buffer = new byte[1024];
                System.out.println("开始接收文件");
                int len = 0;
                while((len = is.read(buffer,0,1024)) != -1){
                    fos.write(buffer,0,1024);
                    fos.flush();
                }
                is.close();
                fos.close();
                System.out.println("文件"+fileNumber+"上传完毕");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //客户端
    package test2;import java.io.*;
    import java.net.*;public class SocketClient {    public static void main(String[] args)
        {
            Socket s = null;
            try{
                File file = new File("c:/src.zip");
                //FileInputStream fis = new FileInputStream(file);
                DataInputStream fis = new DataInputStream(new FileInputStream(file));
                long fileSize = fis.available();
                String fileName = file.getName();
                s = new Socket("127.0.0.1", 10000);
                System.out.println("已经连接上服务器");
                DataOutputStream os = new DataOutputStream(s.getOutputStream());
                os.writeUTF(fileName);
                os.flush();
                os.writeUTF(String.valueOf(fileSize));
                os.flush();
    //            PrintWriter pw = new PrintWriter(os, true);
    //            pw.println(fileSize);
    //            pw.flush();
    //            pw.println(fileName);
    //            pw.flush();
                //os = new BufferedOutputStream(os);
                byte[] buffer = new byte[1024];
                
                int len = 0;
                while((len = fis.read(buffer,0,1024)) != -1){
                    os.write(buffer,0,1024);
                    os.flush();
                }
                os.close();
                fis.close();
                s.close();
            } catch (IOException e){
                e.printStackTrace();
            } finally {
                try{
                    if(s != null)
                        s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
      

  9.   

    long fileSize = fis.available();  你为什么不用file.length()
      

  10.   

    问题出在BufferedReader的readLine上,当调用readLine时,BufferedReader在第一次会试图把自己的buffer读满,默认size是8192个字节,以后每次调用readLine时,如果buffer没有耗尽的话,继续从buffer来读。这样分析一下就可以知道为啥lz说“传送过去的文件总是比客户端原来的文件小”。当开始读取文件名和文件大小时,实际上BufferedReader已经读了8192个字节了,然后以后每次用DataInputStream读时,其实已经是从8193开始读的,那么bytes【文件名+文件大小】至8192间的字节是没有被DataInputStream读取的,也就是少了8192-bytes【文件名+文件大小】这么多字节。
    至于为什么修改byte[] buffer = new byte[1024*5];可以我没有想明白
    请教了一下,应该是用DataStream的read/writeUTF来实现你要传的字符串。如下:
    /**
     * desc:
     *     XXX<br>
     * ----------------------------------------------------------------------------
     * ver.            date           who           what
     * ----------------------------------------------------------------------------
     * 0.0.1           2010-5-24      leisore       add
     * ----------------------------------------------------------------------------
     */
    package cn.leisore.daily._2010_05_24;import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.net.Socket;/**
     * DataTrans
     * 
     * @author leisore
     * @since version 0.0.1
     */
    public class SocketClient {    public static void main(String[] args) {
            Socket s = null;
            try {
                File file = new File("c:/jndi-1_4_2-tutorial.zip");
                // FileInputStream fis = new FileInputStream(file);
                DataInputStream fis = new DataInputStream(new FileInputStream(file));
                long fileSize = fis.available();
                String fileName = file.getName();
                s = new Socket("127.0.0.1", 10002);
                System.out.println("已经连接上服务器");
                DataOutputStream os = new DataOutputStream(s.getOutputStream());
                os.writeUTF(String.valueOf(fileSize));
                os.writeUTF(fileName);
                // os = new BufferedOutputStream(os);
                byte[] buffer = new byte[1024];            int count = 0;
                int len = 0;
                while ((len = fis.read(buffer, 0, 1024)) != -1) {
                    os.write(buffer, 0, len);
                    os.flush();
                }
                os.close();
                fis.close();
                s.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (s != null)
                        s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * desc:
     *     XXX<br>
     * ----------------------------------------------------------------------------
     * ver.            date           who           what
     * ----------------------------------------------------------------------------
     * 0.0.1           2010-5-24      leisore       add
     * ----------------------------------------------------------------------------
     */
    package cn.leisore.daily._2010_05_24;import java.io.DataInputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;/**
     * SocketServer
     * 
     * @author leisore
     * @since version 0.0.1
     */
    public class SocketServer {
        public void start() {
            try {
                ServerSocket ss = new ServerSocket(10002);
                // System.out.println("等待客户端连接");
                int i = 1;
                while (true) {
                    Socket s = ss.accept();
                    // System.out.println("第" + String.valueOf(i) + "客户端连接进来了");
                    InceptFileThread ifThread = new InceptFileThread(s, i);
                    ifThread.start();
                    i++;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }    public static void main(String[] args) {
            SocketServer ss = new SocketServer();
            ss.start();
        }
    }class InceptFileThread extends Thread {    private Socket s;
        private int fileNumber;    public InceptFileThread(Socket s, int fileNumber) {
            this.s = s;
            this.fileNumber = fileNumber;
        }    public void run() {
            try {            DataInputStream dis = new DataInputStream(s.getInputStream());
                System.out.println("第" + String.valueOf(fileNumber) + "个文件开始上传");
                String fileSizeStr = dis.readUTF();
                System.out.println("文件长度" + fileSizeStr);
                String fileName = dis.readUTF();
                System.out.println("文件名称" + fileName);
                StringBuilder filePath = new StringBuilder();
                filePath.append("E:/").append(fileNumber);
                File fileCatalog = new File(filePath.toString());
                if (!fileCatalog.exists())
                    fileCatalog.mkdirs();
                filePath.append("//").append(fileName);
                File file = new File(filePath.toString());
                FileOutputStream fos = new FileOutputStream(file);
                byte[] buffer = new byte[1024];
                System.out.println("开始接收文件");            int len = 0;
                int count = 0;
                while ((len = dis.read(buffer, 0, 1024)) != -1) {
                    fos.write(buffer, 0, len);
                    fos.flush();
                }
                fos.close();
                System.out.println("文件" + fileNumber + "上传完毕");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }应该是好使的。
      

  11.   

    liuzhengkang  leisore
    感谢二位朋友的关注,问题应该就在这里了,leisore朋友分析的很有道理,但是现在我还有一点不明白,为什么我以前的写法中,把byte数组的长度改大(我改成了1M个字节的长度),为什么就能上传完整的文件呢,按照leisore朋友的分析,就是改到多大也应该是不对的,而且我测试中,如果btye数组长度是1024时,测试上传的所有文件大小都是差1024*16个字节的。
      

  12.   


    按照leisore朋友的分析,确实把数据丢失在那了一部分,但是按照我以前的写法,把byte数组长度调大,确实也可以正常接收文件了,就是不明白这个地方到底是为什么。
      

  13.   

    与byte数组长度的大小没关系啊,你按照我上面的程序跑了吗?不管上传的文件有多大都没问题啊。
      

  14.   

    自己来写通讯框架,太麻烦了,使用apache mina,通信层自己就不用管了,专心写好你的业务逻辑就行了
      

  15.   

    客户端代码:
    Java code
    File file = new File("F://java文档资料//api//html_zh_CN.zip");
                //FileInputStream fis = new FileInputStream(file);
                DataInputStream fis = new DataInputStream(new FileInputStream(file));
                long fileSize = fis.available();
                String fileName = file.getName();
                s = new Socket("127.0.0.1", 10000);
                System.out.println("已经连接上服务器");
                DataOutputStream os = new DataOutputStream(s.getOutputStream());
                PrintWriter pw = new PrintWriter(os, true);
    ============================================================================================
    你传的文件是 rar,即二进制文件你用的输出是XXXWriter,Writer是用来写文本的,即字符流,这么做必然丢数据。你把传输的文件换成文本文件应该就没问题了,要么把XXXWriter换成操作字节的输出者。
      

  16.   

    选用的类有问题。
    楼主要弄清楚,到底是要传输文件,还是要传输文件的内容。
    如果只传输文件的内容,就要杜绝文件大小等信息的传输。
    Socket通信,底层采用TCP协议,不会出现丢包现象。ObjectOutputStream,这个类,是用来传输可序列化的对象,File对象不可被序列化吧 ?如果楼主非要将文件的名称和大小传输到对方,那就要自己定义一个简单点的协议。
    (或者说,传输数据的数据格式)然后,收发双方遵照协议,即可。楼主的程序,有两大败笔。
    首先,数据的发送方式,前后不一致。
          前面两个数据以对象的形式进行发送,后面的文件内容,采用二进制byte数组形式发送。
          根据编程理念来将,可以通篇使用ObjectOutputStream发送信息,byte数组也可以看作可序列化的对象。
    其次,数据的接收方面,在数据格式 前后不一致的情况下 前者采用的缓冲区进行处理。
          这是一个致命的错误。为什么呢 ?
          前面读入的数据,从缓冲区里面读取。后面的数据没有从同一缓冲区里面读取。
          会造成缓冲区里面会驻留一些缓冲数据无法被程序读取出来。