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数据封装之后发送和解析,对于负杂的数据时还是要进行封装之后才能发送,否则服务器不好解析。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。