最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Java完成Socket文件傳輸方式

 更新時間:2023年09月28日 16:29:13   作者:牛言牛語  
這篇文章主要介紹了使用Java完成Socket文件傳輸方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

Java完成Socket文件傳輸

TCP協(xié)議的Socket文件傳輸

分別使用三個類(TCPFileUpload_Server服務(wù)器端、TCPFileUpload_Client客戶端、StreamUtils工具類)完成圖片的傳輸。

同樣先運行服務(wù)器端文件,再運行客戶端文件

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 服務(wù)器端
 */
public class TCPFileUpload_Server {
    public static void main(String[] args) throws Exception {
        //思路
        //在本機 的8888端口監(jiān)聽, 等待連接
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服務(wù)器端,監(jiān)聽8888端口,等待連接");
        //當沒有客戶端連接8888端口時,程序會 阻塞, 等待連接
        //如果有客戶端連接,則會返回Socket對象,程序繼續(xù)
        Socket socket = serverSocket.accept();
        //通過socket.getInputStream() 讀取客戶端寫入到數(shù)據(jù)通道的數(shù)據(jù), 并轉(zhuǎn)換成字節(jié)數(shù)組
        BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
        //寫入指定路徑
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("src\\G.jpg"));
        bufferedOutputStream.write(bytes);
        //關(guān)閉IO流
        bufferedOutputStream.close();
        //向客戶端回復(fù)收到圖片
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bufferedWriter.write("收到圖片!");
        bufferedWriter.flush();
        socket.shutdownOutput();
        //關(guān)閉所有流
        bufferedWriter.close();
        bufferedInputStream.close();
        socket.close();
        serverSocket.close();
    }
}
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
 * 客戶端
 */
public class TCPFileUpload_Client {
    public static void main(String[] args) throws Exception {
        //連接服務(wù)端 (ip , 端口)
        //解讀:連接本機的 8888端口, 如果連接成功,返回Socket對象
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
        System.out.println("客戶端 連接端口:" + socket.getPort());
        //創(chuàng)建讀取磁盤文件IO流
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("src/P.jpg"));
        //獲取字節(jié)數(shù)組
        byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
        //通過Socket獲取到輸出流,將bytes發(fā)送到服務(wù)端
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
        bufferedOutputStream.write(bytes);
        //關(guān)閉流對象,socket,刷新,添加終止符
        bufferedInputStream.close();
        bufferedOutputStream.flush();
        socket.shutdownOutput();
        //接受回復(fù)消息
        //此處可調(diào)用Utils的方法
//        String s = "";
//        while ((s = bufferedReader.readLine()) != null)
//            System.out.println(s);
        System.out.println(StreamUtils.streamToString(socket.getInputStream()));
        //關(guān)閉所有流
        bufferedOutputStream.close(); //socket的包裝流不要過早關(guān)閉
        socket.close();
    }
}
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
 * 此類用于演示關(guān)于流的讀寫方法
 */
public class StreamUtils {
    /**
     * 功能:將輸入流轉(zhuǎn)換成byte[]
     *
     * @param is 輸入流
     * @return byte數(shù)組
     * @throws Exception IO流異常
     */
    public static byte[] streamToByteArray(InputStream is) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();//創(chuàng)建輸出流對象
        byte[] b = new byte[1024];
        int len;
        while ((len = is.read(b)) != -1) {
            bos.write(b, 0, len);
        }
        byte[] array = bos.toByteArray();
        bos.close();
        return array;
    }
    /**
     * 功能:將InputStream轉(zhuǎn)換成String
     *
     * @param is 輸入流
     * @return 字符串
     * @throws Exception IO流異常
     */
    public static String streamToString(InputStream is) throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder builder = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) { //當讀取到 null時,就表示結(jié)束
            builder.append(line + "\r\n");
        }
        return builder.toString();
    }
}

Java Socket數(shù)據(jù)傳輸基礎(chǔ)以及優(yōu)化

學(xué)到Java的TCP的Socket傳輸數(shù)據(jù)有些錯誤和心得在此記下

UDP和TCP

UDP:無連接通信協(xié)議,數(shù)據(jù)的發(fā)送端和接收端不用構(gòu)建邏輯連接(發(fā)送時發(fā)送端無需確認接收端的存在,接收端無需返回相映給發(fā)送端)

  • UDP協(xié)議資源消耗小,通信效率高,通常用于音頻、視頻接收和普通數(shù)據(jù)的傳輸
  • 但是又因為UDP面向無連接性,不能保證數(shù)據(jù)的完整性,因此在傳輸重要數(shù)據(jù)的時候不推薦使用UDP協(xié)議

TCP:在發(fā)送數(shù)據(jù)的準備階段,客戶端與服務(wù)器之間的三次交互,以保證連接的可靠性

  • 第一次握手:客戶端向服務(wù)器發(fā)出連接請求
  • 第二次握手:服務(wù)器通知客戶端收到了連接請求
  • 第三次握手:客戶端再次向服務(wù)器發(fā)送確認信息,確認連接
  • TCP的傳輸安全性高于UDP,下載文件和瀏覽網(wǎng)頁等使用的都是TCP

TCP的socket通信

  • 一種情況:客戶端發(fā)送信息和接收信息需要輸入輸出流兩個流,同理服務(wù)器也是這樣,為了避免生成許許多多的流對象,所以可以利用socket中自帶的輸入輸出流進行數(shù)據(jù)交互

Socket使用方法

1.客戶端構(gòu)造函數(shù)

 Socket socket = new Socket(ip,port); 

注解: 因為TCP是邏輯連接式的傳輸,所以客戶端需要得知服務(wù)器的ip和端口

使用getOutputStream() 方法獲得輸出流

OutputStream cos = socket.getOutputStream();
cos.write("你好服務(wù)器".getBytes());  

注解:write使用字節(jié)輸入輸出,需要經(jīng)過 字符–字節(jié)–字符的轉(zhuǎn)換,轉(zhuǎn)換的方法 getBytes() , new String(buf,0,len) ,如果想要直接輸出可以使用打印流 printStream

使用getInputStream方法獲得輸入流

InputStream cis = socket.getInputStream()
//設(shè)置一個緩沖數(shù)組 temp數(shù)組大小大于所接收的數(shù)據(jù)量
byte[] temp = new byte[1024];
int len = cis.read(temp);
//將所接守的字節(jié)轉(zhuǎn)換為字符串 這里使用 temp.toString()會有亂碼
System.out.println(new String(temp,0,len));

注意最后要釋放資源

socket.close();

2.服務(wù)器

服務(wù)器首先要創(chuàng)建ServerSocket設(shè)置端口號

ServerSocket server = new ServerSocket(port:8888);

注解:注意當編寫循環(huán)響應(yīng)時server的定義需要在while(true)循環(huán)之外,不然會顯示端口被占用的情況

Exception in thread "main" java.net.BindException: Address already in use: NET_Bind

然后使用accept()方法返回Socket對象

Socket socket = server.accept();

accept() 方法具有阻塞作用,后面的實例會提到

通過accept()獲得socket對象后,后面的操作方式與客戶端的socket其實是一致的了

//獲得流對象
InputStream sis = socket.getInputStream();
OutputStream sos = socket.getOutputStream();
//打印從客戶端獲得的數(shù)據(jù)
byte[] temp = new btye[1024];
sis.read(temp);
System.out.println(new String(temp));
//對客戶端發(fā)出返回信息
sos.write("你也好,客戶端".getBytes());

注意最后要釋放資源

socket.close();
server.close();

總的應(yīng)用代碼,圖片傳輸

客戶端

import java.io.*;
import java.net.*;
public class TCPClient {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("C:\\Users\\子陌\\Pictures\\1.jpg");
        Socket socket = new Socket("192.168.1.8",8888);
        OutputStream cos = socket.getOutputStream();
        InputStream cis = socket.getInputStream();
        int len =0;
        byte[] bytes = new byte[1024];
        while((len = fis.read(bytes))!=-1){
            cos.write(bytes,0,len);
        }
        socket.shutdownOutput();
        byte[] bytes1 = new byte[1024];
        int len1=0;
        len1 =cis.read(bytes1);
        System.out.println(new String(bytes1));
        socket.close();
        fis.close();
    }
}

服務(wù)器

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
public class TCPSever {
    public static void main(String[] args) throws IOException {
        //這里ServerSocket要放到外面
        ServerSocket server = new ServerSocket(8888);
        while(true) { 
            new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try{
                            //先把accept響應(yīng)放到前面
                            Socket socket = server.accept();
                            String fileName = "itcast" + System.currentTimeMillis() + new Random().nextInt();
                            File file = new File("D:\\TCPUpLoad");
                            if (!file.exists()) {
                                file.mkdirs();
                            }
                            FileOutputStream fos = new FileOutputStream(file + "\\" + fileName + ".jpg");//這里file既是File類也可以當作路徑名稱
                            //FileOutPutStream 會自動生成空文件
                            InputStream sis = socket.getInputStream();
                            OutputStream sos = socket.getOutputStream();
                            int len = 0;
                            byte[] bytes = new byte[1024];
                            while ((len = sis.read(bytes)) != -1) {
                                fos.write(bytes, 0, len);
                            }
                            sos.write("已經(jīng)收到".getBytes());
                            socket.close();
                            fos.close();
                            //重點:要將資源全部釋放,不然會占用線程或者端口
                        }catch(IOException e)
                        {
                            System.out.println(e);
                        }
                    }
                }).start();
        }
        //server.close();
    }
}

代碼中需要注意的點

1.服務(wù)器ServerSocket需要放到while外部,while的目的是能夠隨時響應(yīng)客戶端的請求

2.fileName 使用了

String fileName = "itcast" + System.currentTimeMillis() + new Random().nextInt(9999); 

這也就是為什么從網(wǎng)上下載的圖片有一大堆數(shù)字名字的原因

3.利用了多線程重寫Runnable中的 run 方法,運用了匿名內(nèi)部類,大大提高了服務(wù)器的響應(yīng)速度

4.這里涉及之前提到的一個容易出bug的問題,server.accept() 的阻塞作用,因為會服務(wù)器會不斷的while循環(huán)就會開啟很多線程,如果

FileOutStream fos = new FileOutStream(...) 

運行先于server.accept(),就會每產(chǎn)生一個線程就創(chuàng)建一個空文件 我就是犯了這個錯誤導(dǎo)致電腦多了幾萬個帶.jpg的空文件

5.服務(wù)器和客戶端要同時運作時需要知道自己的ip地址,可以在運行的 cmd 中 輸入 ipconfig 進行查詢

6.Runnable 中的 run 方法并不能自動拋出異常,只能手動 try catch 詳見上方代碼

7.還有一個阻塞問題就是,當客戶端讀取結(jié)束后傳輸給服務(wù)器,但是服務(wù)器并不知道讀取結(jié)束就會導(dǎo)致客戶端和服務(wù)器的同時阻塞,這時需要 Socket 中的 shutdownOutput() 方法告訴服務(wù)器已經(jīng)讀取完畢

 while((len = fis.read(bytes))!=-1)
       {
            cos.write(bytes,0,len);
        }
        socket.shutdownOutput();

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java中 instanceof 的用法詳細介紹

    Java中 instanceof 的用法詳細介紹

    在 Java 中,instanceof 是一個二元運算符(類型比較操作符),用于檢查一個對象是否是某個特定類、接口的實例,或者是否是其子類的實例,這篇文章主要介紹了Java中 instanceof 的用法詳細介紹,需要的朋友可以參考下
    2025-05-05
  • springmvc的文件保存方法詳解

    springmvc的文件保存方法詳解

    這篇文章主要介紹了springmvc的文件保存方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友可以參考下
    2019-09-09
  • Spring Boot中的日志log原理與自定義日志格式

    Spring Boot中的日志log原理與自定義日志格式

    這篇文章主要介紹了Spring Boot中的日志log原理與自定義日志格式,本文將介紹一種日志追蹤的方式,來全鏈路追蹤請求的處理,并設(shè)置相應(yīng)的格式,輸出更加直觀、易處理的日志,需要的朋友可以參考下
    2026-02-02
  • Spring實戰(zhàn)之Bean的作用域request用法分析

    Spring實戰(zhàn)之Bean的作用域request用法分析

    這篇文章主要介紹了Spring實戰(zhàn)之Bean的作用域request用法,結(jié)合實例形式分析了spring中Bean的request作用域相關(guān)使用技巧與操作注意事項,需要的朋友可以參考下
    2019-11-11
  • idea導(dǎo)入gradle項目時遇到的坑及解決

    idea導(dǎo)入gradle項目時遇到的坑及解決

    這篇文章主要介紹了idea導(dǎo)入gradle項目時遇到的坑及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • 初始JAVA模塊化開發(fā)的超詳細步驟(適合菜鳥)

    初始JAVA模塊化開發(fā)的超詳細步驟(適合菜鳥)

    這篇文章主要介紹了初始JAVA模塊化開發(fā)的超詳細步驟,詳細解釋了模塊描述符的職責、模塊路徑的概念以及如何使用命令行運行模塊化Java程序,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2025-03-03
  • 詳解SpringBoot整合MyBatis詳細教程

    詳解SpringBoot整合MyBatis詳細教程

    這篇文章主要介紹了詳解SpringBoot整合MyBatis詳細教程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧
    2020-10-10
  • 關(guān)于Mysql的四種存儲引擎

    關(guān)于Mysql的四種存儲引擎

    這篇文章主要介紹了關(guān)于Mysql的四種存儲引擎,MySql的核心就是存儲引擎,不同的存儲引擎提供不同的存儲機制、索引技巧、鎖定水平等功能,使用不同的存儲引擎,還可以 獲得特定的功能,需要的朋友可以參考下
    2023-05-05
  • Java中Thread類基本用法詳解

    Java中Thread類基本用法詳解

    Java中的Thread類是用于創(chuàng)建和管理線程的類,Thread類提供了許多方法來管理線程,包括啟動線程、中斷線程、暫停線程等,下面這篇文章主要給大家介紹了關(guān)于Java中Thread類基本用法的相關(guān)資料,需要的朋友可以參考下
    2023-06-06
  • IntelliJ IDEA 關(guān)閉多余項目的操作方法

    IntelliJ IDEA 關(guān)閉多余項目的操作方法

    這篇文章主要介紹了IntelliJ IDEA 關(guān)閉多余項目的操作方法,本文給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04

最新評論

大邑县| 西宁市| 高州市| 高雄县| 正蓝旗| 永济市| 新沂市| 永和县| 南澳县| 宁陵县| 弋阳县| 四川省| 乐陵市| 金阳县| 衡东县| 庆元县| 凤凰县| 滨州市| 孝义市| 宜君县| 桑日县| 湟源县| 南丰县| 周口市| 大安市| 叶城县| 肥西县| 米脂县| 忻城县| 盘山县| 望谟县| 岳池县| 青龙| 嘉鱼县| 武川县| 聂拉木县| 隆昌县| 河西区| 沙坪坝区| 苏尼特左旗| 云安县|