Java如何通過(guò)Socket同時(shí)發(fā)送文本和文件
這幾天在自學(xué)Socket網(wǎng)絡(luò)編程時(shí)突然要用到文件和文本同時(shí)傳輸?shù)椒?wù)器,
但是在網(wǎng)上找了半天頁(yè)找不到具體的結(jié)局辦法,最后在不斷琢磨之下終于解決了這個(gè)問(wèn)題,
在傳輸數(shù)據(jù)時(shí)使用的是Java中的ObjectInputStream 和 ObjectOutputStream對(duì)象流,
這個(gè)流可以封裝復(fù)雜的數(shù)據(jù)在網(wǎng)絡(luò)中進(jìn)行傳輸,
發(fā)送涉及到的類需要實(shí)現(xiàn)Serializable接口,是一個(gè)標(biāo)志接口,用于序列化的,沒(méi)有任何的方法需要實(shí)現(xiàn)。
廢話不多說(shuō),直接上代碼
第一種方案
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)聽(tīng)9999端口,等待客戶端連接,如果沒(méi)有連接,將會(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)文章
JSR303校驗(yàn)前端傳遞的數(shù)據(jù)方式
這篇文章主要介紹了JSR303校驗(yàn)前端傳遞的數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
Java多態(tài)中動(dòng)態(tài)綁定原理解析
這篇文章主要介紹了Java多態(tài)中動(dòng)態(tài)綁定原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
Java向上轉(zhuǎn)型與向下轉(zhuǎn)型超詳細(xì)圖解
我們?cè)贘ava編程中經(jīng)常碰到類型轉(zhuǎn)換,對(duì)象類型轉(zhuǎn)換主要包括向上轉(zhuǎn)型和向下轉(zhuǎn)型,這篇文章主要介紹了Java向上轉(zhuǎn)型與向下轉(zhuǎn)型的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-04-04
Netty分布式高性能工具類FastThreadLocal和Recycler分析
這篇文章主要為大家介紹了Netty分布式高性能工具類FastThreadLocal和Recycler分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
spring security集成cas實(shí)現(xiàn)單點(diǎn)登錄過(guò)程
這篇文章主要介紹了spring security集成cas實(shí)現(xiàn)單點(diǎn)登錄過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02
Idea Project文件目錄不見(jiàn)了,只剩External Libraries和imi文件的解決
這篇文章主要介紹了Idea Project文件目錄不見(jiàn)了,只剩External Libraries和imi文件的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
Springboot整合Netty自定義協(xié)議實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了Springboot整合Netty自定義協(xié)議實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11

