Java如何通過Socket同時(shí)發(fā)送文本和文件
這幾天在自學(xué)Socket網(wǎng)絡(luò)編程時(shí)突然要用到文件和文本同時(shí)傳輸?shù)椒?wù)器,
但是在網(wǎng)上找了半天頁找不到具體的結(jié)局辦法,最后在不斷琢磨之下終于解決了這個(gè)問題,
在傳輸數(shù)據(jù)時(shí)使用的是Java中的ObjectInputStream
和 ObjectOutputStream
對(duì)象流,
這個(gè)流可以封裝復(fù)雜的數(shù)據(jù)在網(wǎng)絡(luò)中進(jìn)行傳輸,
發(fā)送涉及到的類需要實(shí)現(xiàn)Serializable
接口,是一個(gè)標(biāo)志接口,用于序列化的,沒有任何的方法需要實(shí)現(xiàn)。
廢話不多說,直接上代碼
第一種方案
Student類,用于封裝數(shù)據(jù)進(jìn)行傳輸和解析
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輸出流進(jìn)行轉(zhuǎn)換 ObjectOutputStream oos =new ObjectOutputStream(os); // 將對(duì)象輸出流發(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端口,等待客戶端連接,如果沒有連接,將會(huì)一直阻塞 Socket accept = serverSocket.accept(); // 獲得數(shù)據(jù)輸入流, InputStream is = accept.getInputStream(); // 對(duì)數(shù)據(jù)輸入流進(jìn)行轉(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é)果
第二種方案
不需要封裝類,也不需要實(shí)現(xiàn)Serializable
接口
服務(wù)端
public class ServerSocketDome1 { public static void main(String[] args) { try { ServerSocket serverSocket = new ServerSocket(9999); Socket socket = serverSocket.accept(); // 對(duì)象流 ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); // 讀取文件名 String str = ois.readUTF(); System.out.println("文件名:"+str); // 讀取文件大小 long l = ois.readLong(); System.out.println("文件大小為:"+l); // 這是使用的是緩沖流,避免了文件大時(shí)內(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é)果
兩種方案中明顯是方案二要簡(jiǎn)便些,但是各有個(gè)的優(yōu)點(diǎn):
方案一中發(fā)送的數(shù)據(jù)需要封裝,解析時(shí)候方便(可以將ByteArrayOutputStream換成BufferedInputStream
)如果是多個(gè)文件,對(duì)Student類中的屬性進(jìn)行一下變更,就能夠?qū)崿F(xiàn)
第二種方案中需要使用Gson數(shù)據(jù)封裝之后發(fā)送和解析,對(duì)于負(fù)雜的數(shù)據(jù)時(shí)還是要進(jìn)行封裝之后才能發(fā)送,否則服務(wù)器不好解析。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java獲取兩個(gè)集合List的交集、補(bǔ)集、并集(相加)和差集(相減)的不同方式
這篇文章主要給大家介紹了關(guān)于Java獲取兩個(gè)集合List的交集、補(bǔ)集、并集(相加)和差集(相減)的不同方式,在一般操作中對(duì)于list集合取交集、差集、并集,比較簡(jiǎn)單,需要的朋友可以參考下2023-08-08springboot實(shí)現(xiàn)執(zhí)行sql語句打印到控制臺(tái)
這篇文章主要介紹了springboot實(shí)現(xiàn)執(zhí)行sql語句打印到控制臺(tái)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06jxl 導(dǎo)出數(shù)據(jù)到excel的實(shí)例講解
下面小編就為大家分享一篇jxl 導(dǎo)出數(shù)據(jù)到excel的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12java中ThreadPoolExecutor常識(shí)匯總
這篇文章主要介紹了java中ThreadPoolExecutor常識(shí)匯總,線程池技術(shù)在并發(fā)時(shí)經(jīng)常會(huì)使用到,java中的線程池的使用是通過調(diào)用ThreadPoolExecutor來實(shí)現(xiàn)的,需要的朋友可以參考下2019-06-06詳解在Spring中如何自動(dòng)創(chuàng)建代理
這篇文章主要介紹了詳解在Spring中如何自動(dòng)創(chuàng)建代理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07SpringBoot整合Ldap的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot整合Ldap的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11