Java如何通過Socket同時發(fā)送文本和文件
這幾天在自學(xué)Socket網(wǎng)絡(luò)編程時突然要用到文件和文本同時傳輸?shù)椒?wù)器,
但是在網(wǎng)上找了半天頁找不到具體的結(jié)局辦法,最后在不斷琢磨之下終于解決了這個問題,
在傳輸數(shù)據(jù)時使用的是Java中的ObjectInputStream
和 ObjectOutputStream
對象流,
這個流可以封裝復(fù)雜的數(shù)據(jù)在網(wǎng)絡(luò)中進行傳輸,
發(fā)送涉及到的類需要實現(xiàn)Serializable
接口,是一個標(biāo)志接口,用于序列化的,沒有任何的方法需要實現(xiàn)。
廢話不多說,直接上代碼
第一種方案
Student類,用于封裝數(shù)據(jù)進行傳輸和解析
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輸出字節(jié)流 OutputStream os = socket.getOutputStream(); Student student = new Student(); student.setUsername("765652244"); student.setSex("男"); // 獲取文件地址 File file = new File("C:\\Users\\網(wǎng)絡(luò)殺手\\Desktop\\image\\soft\\bg.png"); // 將文件名保存到Student中 student.setFilename(file.getName()); // 獲得文件字節(jié)輸入流 FileInputStream fis = new FileInputStream(file); // 將文件字節(jié)流保存至字節(jié)輸出緩沖流 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); } // 將得到的文件字節(jié)轉(zhuǎn)換為字節(jié)數(shù)組 student.setFile(bos.toByteArray()); // 將socket輸出流進行轉(zhuǎn)換 ObjectOutputStream oos =new ObjectOutputStream(os); // 將對象輸出流發(fā)送到服務(wù)器 oos.writeObject(student); fis.close(); bos.close(); oos.flush(); oos.close(); System.out.println("發(fā)送成功"); } }
服務(wù)器
public class ServerSocketDome { public static void main(String[] args) throws IOException, ClassNotFoundException { ServerSocket serverSocket = new ServerSocket(9999); // 監(jiān)聽9999端口,等待客戶端連接,如果沒有連接,將會一直阻塞 Socket accept = serverSocket.accept(); // 獲得數(shù)據(jù)輸入流, InputStream is = accept.getInputStream(); // 對數(shù)據(jù)輸入流進行轉(zhuǎn)換 ObjectInputStream ois = new ObjectInputStream(is); // 將獲得的數(shù)據(jù)轉(zhuǎn)換為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()); // 獲得輸出流,準(zhǔn)備將內(nèi)存中的數(shù)據(jù)寫到磁盤 FileOutputStream fos = new FileOutputStream(file); // 將Student類中或的文件字節(jié)寫入磁盤 fos.write(o.getFile()); fos.close(); serverSocket.close(); accept.close(); is.close(); ois.close(); System.out.println("保存成功,文件名是:"+o.getFilename()+"\n存在在:"+file+"目錄下"); } }
結(jié)果
第二種方案
不需要封裝類,也不需要實現(xiàn)Serializable
接口
服務(wù)端
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); // 這是使用的是緩沖流,避免了文件大時內(nèi)存溢出 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\\網(wǎng)絡(luò)殺手\\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(); } } }
結(jié)果
兩種方案中明顯是方案二要簡便些,但是各有個的優(yōu)點:
方案一中發(fā)送的數(shù)據(jù)需要封裝,解析時候方便(可以將ByteArrayOutputStream換成BufferedInputStream
)如果是多個文件,對Student類中的屬性進行一下變更,就能夠?qū)崿F(xiàn)
第二種方案中需要使用Gson數(shù)據(jù)封裝之后發(fā)送和解析,對于負(fù)雜的數(shù)據(jù)時還是要進行封裝之后才能發(fā)送,否則服務(wù)器不好解析。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java獲取兩個集合List的交集、補集、并集(相加)和差集(相減)的不同方式
這篇文章主要給大家介紹了關(guān)于Java獲取兩個集合List的交集、補集、并集(相加)和差集(相減)的不同方式,在一般操作中對于list集合取交集、差集、并集,比較簡單,需要的朋友可以參考下2023-08-08springboot實現(xiàn)執(zhí)行sql語句打印到控制臺
這篇文章主要介紹了springboot實現(xiàn)執(zhí)行sql語句打印到控制臺的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06jxl 導(dǎo)出數(shù)據(jù)到excel的實例講解
下面小編就為大家分享一篇jxl 導(dǎo)出數(shù)據(jù)到excel的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12