java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java通过Socket同时发送文本和文件

Java如何通过Socket同时发送文本和文件

作者:闲不下来的菜鸟

这篇文章主要介绍了Java如何通过Socket同时发送文本和文件问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

这几天在自学Socket网络编程时突然要用到文件和文本同时传输到服务器,

但是在网上找了半天页找不到具体的结局办法,最后在不断琢磨之下终于解决了这个问题,

在传输数据时使用的是Java中的ObjectInputStream ObjectOutputStream对象流,

这个流可以封装复杂的数据在网络中进行传输,

发送涉及到的类需要实现Serializable接口,是一个标志接口,用于序列化的,没有任何的方法需要实现。

废话不多说,直接上代码

第一种方案

Student类,用于封装数据进行传输和解析

public class Student implements Serializable {
    private String username;
    private String sex;
    private byte[] file;
    private String filename;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public byte[] getFile() {
        return file;
    }

    public void setFile(byte[] file) {
        this.file = file;
    }

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

    @Override
    public String toString() {
        return "Student{" +
                "username='" + username + '\'' +
                ", sex='" + sex + '\'' +
                ", filename='" + filename + '\'' +
                '}';
    }
}

客户端

public class ClientSocket {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",9999);
//        获得Socket输出字节流
        OutputStream os = socket.getOutputStream();
        Student student = new Student();
        student.setUsername("765652244");
        student.setSex("男");
//        获取文件地址
        File file = new File("C:\\Users\\网络杀手\\Desktop\\image\\soft\\bg.png");
//        将文件名保存到Student中
        student.setFilename(file.getName());
//        获得文件字节输入流
        FileInputStream fis = new FileInputStream(file);
//        将文件字节流保存至字节输出缓冲流
        ByteArrayOutputStream bos = new ByteArrayOutputStream(fis.available());
        byte[] b = new byte[1024];
        int len = -1;
        while((len = fis.read(b)) != -1) {
            bos.write(b, 0, len);
        }
//        将得到的文件字节转换为字节数组
        student.setFile(bos.toByteArray());
//        将socket输出流进行转换
        ObjectOutputStream oos =new ObjectOutputStream(os);
//        将对象输出流发送到服务器
        oos.writeObject(student);
        fis.close();
        bos.close();
        oos.flush();
        oos.close();
        System.out.println("发送成功");
    }
}

服务器

public class ServerSocketDome {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ServerSocket serverSocket = new ServerSocket(9999);
//        监听9999端口,等待客户端连接,如果没有连接,将会一直阻塞
        Socket accept = serverSocket.accept();
//        获得数据输入流,
        InputStream is = accept.getInputStream();
//        对数据输入流进行转换
        ObjectInputStream ois = new ObjectInputStream(is);
//        将获得的数据转换为Studen类
        Student o = (Student)ois.readObject();
        System.out.println("用户名:"+o.getUsername()+"\n"+"性别:"+o.getSex());
        System.out.println("文件名:"+o.getFilename());
//        将获得的文件保存至磁盘中
        File file = new File("D:\\"+o.getFilename());
//        获得输出流,准备将内存中的数据写到磁盘
        FileOutputStream fos = new FileOutputStream(file);
//        将Student类中或的文件字节写入磁盘
        fos.write(o.getFile());
        fos.close();
        serverSocket.close();
        accept.close();
        is.close();
        ois.close();
        System.out.println("保存成功,文件名是:"+o.getFilename()+"\n存在在:"+file+"目录下");
    }
}

结果

第二种方案

不需要封装类,也不需要实现Serializable接口

服务端

public class ServerSocketDome1 {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(9999);
            Socket socket = serverSocket.accept();
//            对象流
            ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//            读取文件名
            String str = ois.readUTF();
            System.out.println("文件名:"+str);
//            读取文件大小
            long l = ois.readLong();
            System.out.println("文件大小为:"+l);
//            这是使用的是缓冲流,避免了文件大时内存溢出
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("D:\\"+str)));
            byte[] buffer = new byte[1024*1024];
            int len = -1 ;
            while ((len=ois.read(buffer))!=-1){
                bos.write(buffer,0,len);
            }
            ois.close();
            bos.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端

public class Client1 {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1",9999);
            OutputStream os = socket.getOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(os);
            File file = new File("C:\\Users\\网络杀手\\Desktop\\image\\soft\\bg.png");
            FileInputStream fis = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fis);
//            写入文件名
            oos.writeUTF(file.getName());
//            获得文件大小
            oos.writeLong(file.length());
            byte[] buffer = new byte[1024*1024];
            int len =-1;
            while ((len=bis.read(buffer))!=-1){
                oos.write(buffer,0,len);
            }
            oos.flush();
            os.close();
            oos.close();
            fis.close();
            bis.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

结果

两种方案中明显是方案二要简便些,但是各有个的优点:

方案一中发送的数据需要封装,解析时候方便(可以将ByteArrayOutputStream换成BufferedInputStream)如果是多个文件,对Student类中的属性进行一下变更,就能够实现

第二种方案中需要使用Gson数据封装之后发送和解析,对于负杂的数据时还是要进行封装之后才能发送,否则服务器不好解析。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文