Java 文件传输 (TCP、UDP)
生活随笔
收集整理的這篇文章主要介紹了
Java 文件传输 (TCP、UDP)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
TCP:面向連接、傳輸可靠(保證數(shù)據(jù)正確性,保證數(shù)據(jù)順序)、用于傳輸大量數(shù)據(jù)(流模式)、速度慢,建立連接需要開銷較多(時(shí)間,系統(tǒng)資源)。
UDP:面向非連接、傳輸不可靠、用于傳輸少量數(shù)據(jù)(數(shù)據(jù)包模式)、速度快
TCP
(客戶端)
package TCP;import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.util.Scanner;public class TCP_File_Client {public static void main(String[] args) { // Scanner scan = null;InputStream in = null;Socket socket = null;try {/*** 1.掃描控制臺(tái)接收文件路徑名* 創(chuàng)建一個(gè)file引用,指向一個(gè)新的File對(duì)象,并給文件賦予地址*/// System.out.println("請(qǐng)輸入要傳輸文件的路徑:"); // scan = new Scanner(System.in); // String path = scan.nextLine();File file = new File("D:\\test.txt");/*** 2.判斷文件是文本文件而不是文件夾并且路徑存在* exists():判斷文件是否存在* isFile():判斷是不是文件*/if(file.exists() && file.isFile()) {System.out.println("開始傳輸----->");/*** 3.創(chuàng)建文件輸入流,發(fā)送文件* 將文件輸入的內(nèi)容都放在file里面*/in = new FileInputStream(file);/*** Socket 這個(gè)類實(shí)現(xiàn)客戶端套接字(也稱為“套接字”)。套接字是兩臺(tái)機(jī)器間通信的端點(diǎn)。** 4.創(chuàng)建客戶端套接字*/socket = new Socket();//InetSocketAddress Inets = new InetSocketAddress("127.0.0.1", 12345);/*** 5.連接TCP服務(wù)器* 確定服務(wù)端的IP和端口號(hào)*///socket.connect(new InetSocketAddress("9f9fw7dm.dongtaiyuming.net", 14667));socket.connect(new InetSocketAddress("127.0.0.1", 8899));/*** 6.獲取到客戶端的輸出流* OutputStream getOutputStream()* 返回此套接字的輸出流。*/OutputStream out = socket.getOutputStream();/*** 7.向服務(wù)器發(fā)送文件* 自己定義了一個(gè)協(xié)議來(lái)解決粘包現(xiàn)象,獲取文件名* 7.1.我們先將文件中的內(nèi)容讀取出來(lái),放到file里面* 7.2.先讀文件名 file.getName()* 7.3.將文件名轉(zhuǎn)換成字節(jié) file.getName().getBytes()* 7.4.獲取文件名的字節(jié)的長(zhǎng)度 file.getName().getBytes().length* 7.5.再在文件名長(zhǎng)度的后面加上 \r\n 作為標(biāo)識(shí)符*/// 向服務(wù)器發(fā)送[文件名字節(jié)長(zhǎng)度 \r\n]out.write((file.getName().getBytes().length + "\r\n").getBytes());// 向服務(wù)器發(fā)送[文件名字節(jié)]out.write(file.getName().getBytes());// 向服務(wù)器發(fā)送[文件字節(jié)長(zhǎng)度\r\n]out.write((file.length() + "\r\n").getBytes());// 向服務(wù)器發(fā)送[文件字節(jié)內(nèi)容]byte[] data = new byte[1024];int i = 0;/*while((i = in.read(data)) != -1) {out.write(data, 0, i);}*/int length = 0;long progress = 0;while((length = in.read(data, 0, data.length)) != -1) {out.write(data, 0, length);out.flush();progress += length;System.out.print("| " + (100*progress/file.length()) + "% |");}System.out.println(" ");}else {System.out.println("文件不存在或者一個(gè)文件~~");}} catch (Exception e) {e.printStackTrace();}finally {/*** 關(guān)閉Scanner,文件輸入流,套接字* 套接字裝飾了輸出流,所以不用關(guān)閉輸出流*/ // if(scan != null) { // scan.close(); // }try {if(in != null) {in.close();}} catch (IOException e) {e.printStackTrace();}finally {// 強(qiáng)制將輸入流置為空in = null;}try {if(socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}finally {// 強(qiáng)制釋放socketsocket = null;}}System.out.println("文件傳輸完畢");} }服務(wù)端:
package TCP;import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket;public class TCP_File_Server {public static void main(String[] args) throws Exception {/*** 創(chuàng)建服務(wù)端套接字*/ServerSocket ss = new ServerSocket();/*** 綁定指定端口*/ss.bind(new InetSocketAddress(8899));System.out.println("------開始接收文件-------");/*** 監(jiān)聽并接受客戶端socket連接,并返回一個(gè)socket*//*** 持續(xù)接收客戶端發(fā)來(lái)的信息,并交給線程處理*/while(true) {Socket socket = ss.accept();new Thread(new UpLoad(socket)).start();}} }class UpLoad implements Runnable{private Socket socket = null;public UpLoad(Socket socket) {this.socket = socket;}@Overridepublic void run() {OutputStream out = null;try {// 創(chuàng)建文件輸入流,接收客戶端的socket中的文件流InputStream in = socket.getInputStream();/*** 獲取文件名長(zhǎng)度* 文件格式:文件名長(zhǎng)度(數(shù)字)\r\文件名\r\n文件內(nèi)容\r\n* 獲取文件名 - 讀到第一個(gè)回車換行之前 截取出文件名的長(zhǎng)度 接著讀取這個(gè)長(zhǎng)度的字節(jié) 就是文件名* 讀取數(shù)據(jù) 直到遇到第一個(gè)回車換行* 每次從流中讀取一個(gè)字節(jié) 轉(zhuǎn)成字符串 拼到line上 只要line還不是\r\n結(jié)尾 就重復(fù)這個(gè)過程*/String line1 = "";byte[] by1 = new byte[1];while(!line1.endsWith("\r\n")) {in.read(by1);String str = new String(by1);line1 += str;}/*** 1.讀到長(zhǎng)度,去掉\r\n就是文件名字的長(zhǎng)度* 2.parseInt():作用是將可分析的字符串轉(zhuǎn)化為整數(shù)。* 3.substring():返回一個(gè)新字符串,它是此字符串的一個(gè)子字符串。*/int len1 = Integer.parseInt(line1.substring(0, line1.length() - 2));/*** 1.讀取文件名* 2.先創(chuàng)建一個(gè)長(zhǎng)度和文件名長(zhǎng)度相等的字節(jié)數(shù)組,用來(lái)存放文件名* 3.read(data):從輸入流中讀取一定數(shù)量的字節(jié),并將其存儲(chǔ)在緩沖區(qū)數(shù)組 data 中* data數(shù)組有多大,就在in輸入流里面讀取多少內(nèi)容,并將內(nèi)容存放在data數(shù)組里面*/byte[] data = new byte[len1];in.read(data);String fileName = new String(data);// 獲取文件內(nèi)容字節(jié)長(zhǎng)度String line2 = "";byte[] by2 = new byte[1];while(!line2.endsWith("\r\n")) {in.read(by2);String str = new String(by2);line2 += str;}int len2 = Integer.parseInt(line2.substring(0, line2.length() - 2));// 創(chuàng)建輸文件出流,指定文件輸出地址String path = "D://copy//" + fileName;out = new FileOutputStream(path);// 獲取文件內(nèi)容字節(jié)// 流對(duì)接byte[] by3 = new byte[len2];in.read(by3);out.write(by3);System.out.println("接受到來(lái)自"+socket.getInetAddress().getHostAddress()+"上傳的文件"+path);} catch (IOException e) {e.printStackTrace();}finally {// 關(guān)閉資源// 關(guān)閉輸出流try {if(out != null) {out.close();}} catch (IOException e) {e.printStackTrace();}finally {out = null;}// 關(guān)閉sockettry {if(socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}finally {socket = null;}}} }UDP
(客戶端)
package upd;import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.net.Socket;public class FileTransferClient extends Socket {private static final String SERVER_IP = "127.0.0.1"; // 服務(wù)端IPprivate static final int SERVER_PORT = 8899; // 服務(wù)端端口private Socket client;private FileInputStream fis;private DataOutputStream dos;/*** 構(gòu)造函數(shù)<br/>* 與服務(wù)器建立連接* @throws Exception*/public FileTransferClient() throws Exception {super(SERVER_IP, SERVER_PORT);this.client = this;System.out.println("Cliect[port:" + client.getLocalPort() + "] 成功連接服務(wù)端");}/*** 向服務(wù)端傳輸文件* @throws Exception*/public void sendFile() throws Exception {try {File file = new File("D:\\test.xlsx");if(file.exists()) {fis = new FileInputStream(file);dos = new DataOutputStream(client.getOutputStream());// 文件名和長(zhǎng)度dos.writeUTF(file.getName());dos.flush();dos.writeLong(file.length());dos.flush();// 開始傳輸文件System.out.println("======== 開始傳輸文件 ========");byte[] bytes = new byte[1024];int length = 0;long progress = 0;while((length = fis.read(bytes, 0, bytes.length)) != -1) {dos.write(bytes, 0, length);dos.flush();progress += length;System.out.print("| " + (100*progress/file.length()) + "% |");}System.out.println();System.out.println("======== 文件傳輸成功 ========");dos.close();}} catch (Exception e) {e.printStackTrace();} finally {if(fis != null)fis.close();if(dos != null)dos.close();client.close();}}/*** 入口* @param args*/public static void main(String[] args) {try {FileTransferClient client = new FileTransferClient(); // 啟動(dòng)客戶端連接client.sendFile(); // 傳輸文件} catch (Exception e) {e.printStackTrace();}} } 服務(wù)端: package upd; import java.io.DataInputStream; import java.io.File; import java.io.FileOutputStream; import java.math.RoundingMode; import java.net.ServerSocket; import java.net.Socket; import java.text.DecimalFormat;/*** 文件傳輸Server端<br>* 功能說(shuō)明:** @author 大智若愚的小懂* @Date 2016年09月01日* @version 1.0*/ public class FileTransferServer extends ServerSocket {private static final int SERVER_PORT = 8899; // 服務(wù)端端口private static DecimalFormat df = null;static {// 設(shè)置數(shù)字格式,保留一位有效小數(shù)df = new DecimalFormat("#0.0");df.setRoundingMode(RoundingMode.HALF_UP);df.setMinimumFractionDigits(1);df.setMaximumFractionDigits(1);}public FileTransferServer() throws Exception {super(SERVER_PORT);}/*** 使用線程處理每個(gè)客戶端傳輸?shù)奈募? @throws Exception*/public void load() throws Exception {System.out.println("服務(wù)端已啟動(dòng),等待接收文件......");while (true) {// server嘗試接收其他Socket的連接請(qǐng)求,server的accept方法是阻塞式的Socket socket = this.accept();/*** 我們的服務(wù)端處理客戶端的連接請(qǐng)求是同步進(jìn)行的, 每次接收到來(lái)自客戶端的連接請(qǐng)求后,* 都要先跟當(dāng)前的客戶端通信完之后才能再處理下一個(gè)連接請(qǐng)求。 這在并發(fā)比較多的情況下會(huì)嚴(yán)重影響程序的性能,* 為此,我們可以把它改為如下這種異步處理與客戶端通信的方式*/// 每接收到一個(gè)Socket就建立一個(gè)新的線程來(lái)處理它new Thread(new Task(socket)).start();}}/*** 處理客戶端傳輸過來(lái)的文件線程類*/class Task implements Runnable {private Socket socket;private DataInputStream dis;private FileOutputStream fos;public Task(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {dis = new DataInputStream(socket.getInputStream());// 文件名和長(zhǎng)度String fileName = dis.readUTF();long fileLength = dis.readLong();File directory = new File("D:\\copy");if(!directory.exists()) {directory.mkdir();}File file = new File(directory.getAbsolutePath() + File.separatorChar + fileName);fos = new FileOutputStream(file);// 開始接收文件byte[] bytes = new byte[1024];int length = 0;while((length = dis.read(bytes, 0, bytes.length)) != -1) {fos.write(bytes, 0, length);fos.flush();}System.out.println("======== 文件接收成功 [File Name:" + fileName + "] [Size:" + getFormatFileSize(fileLength) + "] ========");} catch (Exception e) {e.printStackTrace();} finally {try {if(fos != null)fos.close();if(dis != null)dis.close();socket.close();} catch (Exception e) {}}}}/*** 格式化文件大小* @param length* @return*/private String getFormatFileSize(long length) {double size = ((double) length) / (1 << 30);if(size >= 1) {return df.format(size) + "GB";}size = ((double) length) / (1 << 20);if(size >= 1) {return df.format(size) + "MB";}size = ((double) length) / (1 << 10);if(size >= 1) {return df.format(size) + "KB";}return length + "B";}/*** 入口* @param args*/public static void main(String[] args) {try {FileTransferServer server = new FileTransferServer(); // 啟動(dòng)服務(wù)端server.load();} catch (Exception e) {e.printStackTrace();}} }傳輸時(shí)先啟動(dòng)服務(wù)端?
總結(jié)
以上是生活随笔為你收集整理的Java 文件传输 (TCP、UDP)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简述现代计算机系统如何进行多级划分,现代
- 下一篇: 各种Windows版本下载