Java如何利用Socket傳輸信息或文件
本文中的是使用TCP協(xié)議進(jìn)行文件傳輸
Socket
套接字(socket)是一個(gè)抽象層,應(yīng)用程序可以通過它發(fā)送或接收數(shù)據(jù),可對其進(jìn)行像對文件一樣的打開、讀寫和關(guān)閉等操作。
套接字允許應(yīng)用程序?qū)/O插入到網(wǎng)絡(luò)中,并與網(wǎng)絡(luò)中的其他應(yīng)用程序進(jìn)行通信。網(wǎng)絡(luò)套接字是IP地址與端口的組合。
信息與文件傳輸使用C/S(Client/Server)。
步驟
- 1、啟動(dòng)服務(wù)端,等待客戶端連接。
- 2、啟動(dòng)客戶端連接服務(wù)端。
- 3、傳輸數(shù)據(jù)。
- 4、關(guān)閉客戶端。
- 5、關(guān)閉服務(wù)端。
代碼
首先啟動(dòng)服務(wù)端
package priv.zb.socket;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class FileServer {
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
ServerSocket server = null;
Socket socket = null;
//向外界暴露一個(gè)端口9999的服務(wù),默認(rèn)IP為本機(jī)IP:127.0.0.1
server = new ServerSocket(9999);
//返回一個(gè)Socket對象
socket = server.accept();
/**
*
* 啟動(dòng)服務(wù)端之后,會(huì)在 server.accept(); 方法處等待客戶端的
* 連接,當(dāng)啟動(dòng)客戶端連接上服務(wù)端之后走過此方法運(yùn)行后面的代碼。
*/
System.out.println("接收到客戶端的連接");
//服務(wù)端向客戶端發(fā)送消息 通過OutputStream
//發(fā)出信息使用輸出流OutputStream,接收信息使用輸入咯InputStream
OutputStream output = socket.getOutputStream();
//傳輸字符串
// byte[] bs = new byte[100];
// output.write("Hello".getBytes());
//傳輸文件
String filePath = "存放文件路徑";
File file = new File(filePath );
byte[] fileBytes = new byte[100]; //定義文件每次發(fā)送大小
//讀入到內(nèi)存中,new 一個(gè)inputStream即可
//文件較大,不能一次性發(fā)送完畢,因此需要循環(huán)操作
InputStream fileIn = new FileInputStream(file);
int len = -1;
while((len = fileIn.read(fileBytes)) != -1) {
output.write(fileBytes, 0, len);
}
//接受客戶端消息
// InputStream in = socket.getInputStream();
// in.read(bs);
// System.out.println("Server接收到信息:" + new String(bs));
System.out.println("發(fā)送成功");
output.close();
fileIn.close();
}
}之后啟動(dòng)客戶端
package priv.zb.socket;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class FileClient {
@SuppressWarnings("resource")
public static void main(String[] args) throws UnknownHostException, IOException {
//建立連接
//客戶端訪問服務(wù)端發(fā)布的服務(wù)
Socket socket = new Socket("192.168.0.108",9999);
//通過InputStream接收信息
InputStream input = socket.getInputStream();
byte[] fileBytes = new byte[100];
File file = new File("E:\\JAVA\\Java SE\\srcCopy.zip");
OutputStream output = new FileOutputStream(file);
int len = -1;
while( (len = input.read(fileBytes)) != -1) {
output.write(fileBytes, 0, len);
}
//客戶端接收到信息返回一個(gè)標(biāo)識(shí)
// byte[] bs = new byte[100];
// input.read(bs);
// System.out.println("Client 接收到消息:" + new String(bs));
//客戶端向服務(wù)端發(fā)送一個(gè)消息
// OutputStream output = socket.getOutputStream();
// output.write("World".getBytes());
System.out.println("接收成功??!");
output.close();
input.close();
}
}這個(gè)代碼在客戶端連接一次之后,服務(wù)端便會(huì)主動(dòng)關(guān)閉。
但是在實(shí)際的使用中一般不會(huì)只使用一次服務(wù)端,將會(huì)不斷地重復(fù)連接服務(wù)端這一過程。
因此使用while(true)死循環(huán)來保持服務(wù)端的始終開啟,利用多線程來解決這一問題。
優(yōu)化
使用多線程是在服務(wù)端
服務(wù)端
package priv.zb.socket.runable;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class FileServer {
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
//向外界暴露一個(gè)端口9999的服務(wù),默認(rèn)IP為本機(jī)IP:127.0.0.1
ServerSocket server = new ServerSocket(9999);
while(true) {
Socket socket = server.accept();
//使用構(gòu)造方法傳入一個(gè)Socket對象與下載線程保持關(guān)聯(lián)
new Thread(new MyDownload(socket)).start();
//下載線程
/*
* MyDownload download = new MyDownload(socket);
* //Runnable變?yōu)門hered對象
* new Thread(download).start();
*/
}
}
}下載線程:MyDownload.java
package priv.zb.socket.runable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class MyDownload implements Runnable {
//Mydownload.java與Server之間使用Socket對象聯(lián)系
private Socket socket;
public MyDownload(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//返回一個(gè)Socket對象
OutputStream output =null;
InputStream fileIn = null;
try {
System.out.println("接收到客戶端的連接");
//服務(wù)端向客戶端發(fā)送消息 通過OutputStream
File file = new File("E:\\JAVA\\Java SE\\src.zip");
byte[] fileBytes = new byte[100]; //定義文件每次發(fā)送大小
//讀入到內(nèi)存中,new 一個(gè)inputStream即可
//文件較大,不能一次性發(fā)送完畢,因此需要循環(huán)操作
fileIn = new FileInputStream(file);
int len = -1;
output = socket.getOutputStream();
while((len = fileIn.read(fileBytes)) != -1) {
output.write(fileBytes, 0, len);
}
System.out.println("發(fā)送成功");
} catch (IOException e1) {
e1.printStackTrace();
} finally {
try {
if(output != null) output.close();
if(fileIn != null) fileIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}之后即可多次傳輸信息不關(guān)閉服務(wù)端。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)注冊登錄與郵箱發(fā)送賬號(hào)驗(yàn)證激活功能
這篇文章主要介紹了Java實(shí)現(xiàn)注冊登錄與郵箱發(fā)送賬號(hào)驗(yàn)證激活功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-12-12
springboot項(xiàng)目連接不上nacos配置,報(bào)‘url‘異常問題
這篇文章主要介紹了springboot項(xiàng)目連接不上nacos配置,報(bào)‘url‘異常問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
將SpringBoot的Jar注冊成Windows服務(wù)的實(shí)現(xiàn)方法
當(dāng)前項(xiàng)目有個(gè)地圖編輯器,后端用的是SpringBoot框架,外網(wǎng)剛好有一臺(tái)空閑的Windows服務(wù)器就直接拿來用了,將Java程序部署成Windows服務(wù)可以用WinSW (Windows Service Wrapper)來實(shí)現(xiàn),文中有詳細(xì)的操作步驟,需要的朋友可以參考下2023-11-11
使用spring+maven不同環(huán)境讀取配置方式
這篇文章主要介紹了使用spring+maven不同環(huán)境讀取配置方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
java實(shí)現(xiàn)釘釘機(jī)器人消息推送的示例代碼
這篇文章主要介紹了java實(shí)現(xiàn)釘釘機(jī)器人消息推送的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
Java使用Filter實(shí)現(xiàn)登錄驗(yàn)證
本文主要介紹了Java使用Filter實(shí)現(xiàn)登錄驗(yàn)證,Filter類似于門衛(wèi),你在進(jìn)入之前門衛(wèi)需要盤查你,身份合法進(jìn)入,身份不合法攔截,感興趣的可以了解一下2023-11-11

