欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

Java完成Socket文件傳輸

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

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

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

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 服務(wù)器端
 */
public class TCPFileUpload_Server {
    public static void main(String[] args) throws Exception {
        //思路
        //在本機(jī) 的8888端口監(jiān)聽, 等待連接
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服務(wù)器端,監(jiān)聽8888端口,等待連接");
        //當(dāng)沒有客戶端連接8888端口時(shí),程序會(huì) 阻塞, 等待連接
        //如果有客戶端連接,則會(huì)返回Socket對(duì)象,程序繼續(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 , 端口)
        //解讀:連接本機(jī)的 8888端口, 如果連接成功,返回Socket對(duì)象
        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)閉流對(duì)象,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)建輸出流對(duì)象
        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) { //當(dāng)讀取到 null時(shí),就表示結(jié)束
            builder.append(line + "\r\n");
        }
        return builder.toString();
    }
}

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

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

UDP和TCP

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

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

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

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

TCP的socket通信

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

Socket使用方法

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

 Socket socket = new Socket(ip,port); 

注解: 因?yàn)門CP是邏輯連接式的傳輸,所以客戶端需要得知服務(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è)置一個(gè)緩沖數(shù)組 temp數(shù)組大小大于所接收的數(shù)據(jù)量
byte[] temp = new byte[1024];
int len = cis.read(temp);
//將所接守的字節(jié)轉(zhuǎn)換為字符串 這里使用 temp.toString()會(huì)有亂碼
System.out.println(new String(temp,0,len));

注意最后要釋放資源

socket.close();

2.服務(wù)器

服務(wù)器首先要?jiǎng)?chuàng)建ServerSocket設(shè)置端口號(hào)

ServerSocket server = new ServerSocket(port:8888);

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

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

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

Socket socket = server.accept();

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

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

//獲得流對(duì)象
InputStream sis = socket.getInputStream();
OutputStream sos = socket.getOutputStream();
//打印從客戶端獲得的數(shù)據(jù)
byte[] temp = new btye[1024];
sis.read(temp);
System.out.println(new String(temp));
//對(duì)客戶端發(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{
                            //先把a(bǔ)ccept響應(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類也可以當(dāng)作路徑名稱
                            //FileOutPutStream 會(huì)自動(dòng)生成空文件
                            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();
                            //重點(diǎn):要將資源全部釋放,不然會(huì)占用線程或者端口
                        }catch(IOException e)
                        {
                            System.out.println(e);
                        }
                    }
                }).start();
        }
        //server.close();
    }
}

代碼中需要注意的點(diǎn)

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

2.fileName 使用了

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

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

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

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

FileOutStream fos = new FileOutStream(...) 

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

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

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

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

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

總結(jié)

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

相關(guān)文章

  • java實(shí)現(xiàn)ATM機(jī)系統(tǒng)(2.0版)

    java實(shí)現(xiàn)ATM機(jī)系統(tǒng)(2.0版)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)ATM機(jī)系統(tǒng)2.0版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • 使用Springboot打成jar包thymeleaf的問題

    使用Springboot打成jar包thymeleaf的問題

    這篇文章主要介紹了使用Springboot打成jar包thymeleaf的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Spring Security基于HttpRequest配置權(quán)限示例詳解

    Spring Security基于HttpRequest配置權(quán)限示例詳解

    這篇文章主要介紹了Spring Security基于HttpRequest配置權(quán)限示例詳解,我們?cè)谂渲弥信渲玫膗rl被封裝成RequestMatcher,而hasRole被封裝成AuthorityAuthorizationManager,本文結(jié)合示例代碼講解的非常詳細(xì),需要的朋友可以參考下
    2024-03-03
  • Java中Double除保留后小數(shù)位的幾種方法(小結(jié))

    Java中Double除保留后小數(shù)位的幾種方法(小結(jié))

    這篇文章主要介紹了Java中Double保留后小數(shù)位的幾種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • Java文件操作之IO流 File類的使用詳解

    Java文件操作之IO流 File類的使用詳解

    在java中提供有對(duì)于文件操作系統(tǒng)的支持,這個(gè)支持在java.io.File類中進(jìn)行了定義,也就是說在整個(gè)java.io包中File類是唯一一個(gè)與文件本身操作有關(guān)的類(創(chuàng)建,刪除,重命名)有關(guān)的類,而如果想要進(jìn)行File類的操作,我們需要提供有完整的路徑支持,而后可以調(diào)用相應(yīng)的方法進(jìn)行處理
    2021-09-09
  • gRPC中interceptor攔截器的使用教程

    gRPC中interceptor攔截器的使用教程

    gRPC中的interceptor攔截器分為客戶端攔截器和服務(wù)端攔截器,分別是在客戶端和服務(wù)端的請(qǐng)求被發(fā)送出去之前進(jìn)行處理的邏輯,下面就跟隨小編一起學(xué)習(xí)一下interceptor攔截器的具體使用吧
    2023-08-08
  • springboot配置http跳轉(zhuǎn)https的過程

    springboot配置http跳轉(zhuǎn)https的過程

    SSL是為網(wǎng)絡(luò)通信提供安全以及保證數(shù)據(jù)完整性的的一種安全協(xié)議,SSL在網(wǎng)絡(luò)傳輸層對(duì)網(wǎng)絡(luò)連接進(jìn)行加密,這篇文章主要介紹了springboot配置http跳轉(zhuǎn)https的過程,需要的朋友可以參考下
    2023-04-04
  • 幾道java循環(huán)練習(xí)題(適合新人)

    幾道java循環(huán)練習(xí)題(適合新人)

    這篇文章主要給大家介紹了幾道java循環(huán)練習(xí)題,非常適合剛?cè)腴T的java新人,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Java生成隨機(jī)數(shù)的2種示例方法代碼

    Java生成隨機(jī)數(shù)的2種示例方法代碼

    在Java中,生成隨機(jī)數(shù)有兩種方法。1是使用Random類。2是使用Math類中的random方法。看下面的例子使用吧
    2013-11-11
  • 詳解OpenCV For Java環(huán)境搭建與功能演示

    詳解OpenCV For Java環(huán)境搭建與功能演示

    這篇文章主要介紹了x詳解OpenCV For Java環(huán)境搭建與功能演示,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04

最新評(píng)論