1. 程式人生 > >Java---網路程式設計(3)-TCP-互傳檔案和圖片

Java---網路程式設計(3)-TCP-互傳檔案和圖片

☆ TCP

建立連線,形成傳輸資料的通道。
在連線中進行大資料量傳輸
通過三次握手完成連線,是可靠協議
必須建立連線,效率會稍低

Socket 和
ServerSocket類

TCP傳輸

TCP Socket:IP地址和埠,套接字

Socket和ServerSocket
建立客戶端和伺服器端
建立連線後,通過Socket中的IO流進行資料的傳輸
關閉socket

同樣,客戶端與伺服器端是兩個獨立的應用程式。

TCP傳輸程式設計

☆基本思路(客戶端)

客戶端需要明確伺服器的ip地址以及埠,這樣才可以去試著建立連線,如果連線失敗,會出現異常。
連線成功,說明客戶端與服務端建立了通道,那麼通過IO流就可以進行資料的傳輸,而Socket物件已經提供了輸入流和輸出流物件,通過getInputStream(), getOutputStream()獲取即可。
與服務端通訊結束後,關閉Socket。

☆基本思路(伺服器端)

服務端需要明確它要處理的資料是從哪個埠進入的。
當有客戶端訪問時,要明確是哪個客戶端,可通過accept()獲取已連線的客戶端物件,並通過該物件與客戶端通過IO流進行資料傳輸。
當該客戶端訪問結束,關閉該客戶端。

基於TCP的Socket通訊流程

TCP傳輸程式設計程式碼:

☆客戶端

通過Socket建立物件並指定要連線的服務端主機以及埠。

Socket s = new Socket(“192.168.1.1”,9999);
OutputStream out = s.getOutputStream();
out.write(“hello”.getBytes
()); s.close();

☆伺服器端

建立服務端需要監聽一個埠

ServerSocket ss = new ServerSocket(9999);
Socket s = ss.accept ();
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int num = in.read(buf);
String str = new String(buf,0,num);
System.out.println(s.getInetAddress().toString()+”:”+str);
s.close();
ss.close
();

最簡單的TCP演示例項:

客戶端程式碼:

package cn.hncu.tcp;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 客戶端
 * @author 陳浩翔
 *
 * 2016-5-10
 */
public class MyClientSocket {

    public static void main(String[] args) {
        try {
            //因為是在自己本機上演示,IP就直接填寫本機10.30.7.95的了。
            //這個埠和IP都是伺服器端的(自己可以改的)
            Socket s = new Socket("10.30.7.95", 9999);
            //和伺服器進行三次握手,若失敗則出異常,否則返回和對方通訊的socket

            OutputStream os = s.getOutputStream();
            //傳送資料
            os.write("你好,伺服器!".getBytes());

            //接收伺服器端的反饋
            InputStream in = s.getInputStream();

            DataInputStream din = new DataInputStream(in);

            System.out.println(din.readUTF());

            s.close();
            din.close();

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

伺服器端程式碼:

package cn.hncu.tcp;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 伺服器端
 * @author 陳浩翔
 *
 * 2016-5-10
 */
public class MyServerSocket {

    public static void main(String[] args) {

        try {
            ServerSocket server = new ServerSocket(9999);
            while(true){

                System.out.println("準備接收一個數據...");
                Socket s = server.accept();//阻塞式方法
                System.out.println("接收了一個數據...");

                //讀--從客戶端讀資料
                InputStream in =  s.getInputStream();
                byte buf[] = new byte[1024];
                in.read(buf);
                System.out.println("read info: "+new String(buf));

                //寫--應答客戶端--向他寫資料
                OutputStream out = s.getOutputStream();
                DataOutputStream dout = new DataOutputStream(out);
                dout.writeUTF("你好,"+s.getInetAddress().getHostAddress()+"  ,你的資訊已收到。");
                dout.close();
                s.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

}

客戶端執行結果:

你好,10.30.7.95  ,你的資訊已收到。

伺服器端執行結果:

☆思考

  對於Web伺服器而言,當有多個客戶端同時訪問伺服器時,服務端又如何提供服務呢?

☆TCP傳輸最容易出現的問題

客戶端連線上服務端,兩端都在等待,沒有任何資料傳輸。
通過例程分析:
因為read方法或者readLine方法是阻塞式。
解決辦法:
自定義結束標記(必須定義傳輸檔案中沒有這個這個字串的,不然會出現接收資料不完整)
使用shutdownInput,shutdownOutput方法。

程式設計練習

☆上傳文字檔案

讀取一個本地文字檔案,將資料傳送到服務端,伺服器端對資料進行儲存。 儲存完畢後,給客戶端一個提示。

文字檔案傳送的客戶端

package cn.hncu.tcp.upload;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * 文字檔案傳送的客戶端
 * @author 陳浩翔
 *
 * 2016-5-10
 */
public class UploadTextClient {

    public static void main(String[] args) {

        try {
            Socket s = new Socket("", 10006);

            //思路:把本地檔案的資料讀取出來通過 s.getOutputStream()獲得的out物件傳送出去
            BufferedReader bf = new BufferedReader(new FileReader("tempfiles\\client.txt"));

            OutputStream out = s.getOutputStream();//這裡的輸出流 對應的是伺服器端的輸入流
            PrintWriter pw = new PrintWriter(out,true);//建議不要用BufferedWriter
            //!!!!!!!!!!!!!!!!!這個true不要忘了!---自動重新整理
            //現在大家寫網路傳輸檔案,一般是用PrintWriter

            String str=null;
            while((str=bf.readLine())!=null){
                pw.println(str);
            }

            //給伺服器傳送結束標記---上傳結束,要加結束標記,
            //否則伺服器在資料接收完畢時再呼叫read()或readLine()時會出異常
            //法1:pw.println("over#[email protected]#@$");//不能出現檔案中存在的結束關鍵字---搞特殊一點
            //法2---建議採用該種方式---由socket內部來指定結束標記
            s.shutdownOutput();
            bf.close();

            //接收伺服器端反饋

            InputStream in = s.getInputStream();
            DataInputStream din = new DataInputStream(in);
            System.out.println("server應答:"+din.readUTF());
            s.close();
            din.close();


        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }



    }

}

文字檔案接收的伺服器端

package cn.hncu.tcp.upload;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 文字檔案接收的伺服器端
 * @author 陳浩翔
 *
 * 2016-5-10
 */
public class UploadTextServer {

    public static void main(String[] args) {
        try {
            ServerSocket server = new ServerSocket(10006);

            Socket s = server.accept();
            System.out.println(s.getInetAddress().getHostAddress()+"...傳送訊息來");

            //讀取客戶端上傳過來的文字檔案
            //源 ---socket(位元組流)---額外:需要轉換成字元流  ,快取流
            InputStream in  = s.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(in));
            //目的 ---硬碟字元流 FileWriter---額外:列印流
            PrintWriter pw = new PrintWriter(new FileWriter("tempfiles\\server.txt"),true);
            String line = null;
            while((line=br.readLine())!=null){
//              if("over#[email protected]#@$".equals(line)){//自己定義的結束標誌
//              break;
//          }
                pw.println(line);
            }

            pw.close();

            //上傳成功,給客戶端一個提示資訊

            OutputStream out = s.getOutputStream();
            DataOutputStream dout = new DataOutputStream(out);
            dout.writeUTF("檔案上傳成功!");
            s.close();
            server.close();
            dout.close();


        } catch (IOException e) {
            e.printStackTrace();
        }




    }

}

測試通過!

☆上傳圖片檔案

客戶端需求:把一個圖片檔案傳送到服務端並讀取回饋資訊。要求判斷檔案是否存在及格式是否為jpg或gif並要求檔案小於2M。
服務端需求:接收客戶端傳送過來的圖片資料。進行儲存後,回饋一個 上傳成功字樣。支援多使用者的併發訪問。

圖片檔案的傳送-客戶端

package cn.hncu.tcp.upload;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

import javax.swing.JOptionPane;

/**
 * 圖片檔案的傳送-客戶端
 * @author 陳浩翔
 *
 * 2016-5-10
 */
public class UploadPicClient {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入圖片路徑:");
        String str = sc.next();

        File file = new File(str);
        if(!(file.exists()&& file.isFile())){
            JOptionPane.showMessageDialog(null, "檔案不存在!");
            return ;
        }

        if(!(file.getName().endsWith(".jpg")||file.getName().endsWith(".gif"))){
            JOptionPane.showMessageDialog(null, "檔案格式不對,副檔名必須是jpg或gif!");
            return ;
        }
        if( file.length()>=1024*1024*2){
            JOptionPane.showMessageDialog(null, "檔案過大,不應超過2M,請重新上傳!");
            return;
        }

        //上傳
        try {
            Socket s = new Socket("10.30.7.95", 10007);

            BufferedInputStream bin = new BufferedInputStream(new FileInputStream(str));

            OutputStream out = s.getOutputStream();

            byte buf[] = new byte[1024];
            int len=0;
            while((len=bin.read(buf))!=-1){
                out.write(buf, 0, len);
            }

            s.shutdownOutput();//告訴伺服器,檔案上傳完畢

            //讀取伺服器的回饋資訊
            InputStream in = s.getInputStream();
            byte buf2[] = new byte[1024];
            int len2 = in.read(buf2);
            System.out.println(new String(buf2, 0, len2));

            //關流
            out.close();
            bin.close();
            s.close();

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

圖片檔案接收-伺服器端

package cn.hncu.tcp.upload;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 圖片檔案接收-伺服器端
 * @author 陳浩翔
 *
 * 2016-5-10
 */
public class UploadPicServer {

    public static void main(String[] args) {

        try {
            ServerSocket server = new ServerSocket(10007);
            while(true){
                Socket s = server.accept();//阻塞方法
                //只負責和客戶端進行握手
                new Thread(new  UploadThread(s) ).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class UploadThread implements Runnable{
    private Socket s;
    public UploadThread(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {

        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+"...發來圖片");

        try {
            BufferedInputStream bin = new BufferedInputStream(s.getInputStream());

            File dir = new File("g:\\mypic");

            if(!dir.exists()){
                dir.mkdir();//資料夾不存在,建立mypic資料夾
            }

            int count=1;
            //我覺得這裡的字尾名,需要通過傳送方也發過來的
            File file = new File(dir, ip+".jpg");

            while(file.exists()){
                file = new File(dir,ip+"("+(count++) +")"+".jpg"); //帶號的檔名
            }

            FileOutputStream fout = new FileOutputStream(file);

            //從socket流中讀取資料,儲存到本地檔案。相當於對拷
            byte buf[] = new byte[1024];
            int len=0;
            while( (len=bin.read(buf))!=-1){
                fout.write(buf, 0, len);
            }
            //圖片接收完畢

            //向客戶端傳送回饋資訊
            OutputStream out = s.getOutputStream();
            out.write( "上傳成功".getBytes() );

            fout.close();
            s.close();

        } catch (IOException e) {
            e.printStackTrace();
        }



    }
}

有一個小bug。是服務端接收的,因為我把字尾名統一為jpg了,gif的圖片可以上傳,只是變成靜圖了(jpg)。可以通過改字尾名,再把這圖片改回去動圖。還有一種方法,在上傳的時候,把字尾名也上傳,再通過伺服器解析就可以解決這個問題。
因為時間問題,我就不寫了,這個很簡單的。
只是多傳送了一個字尾名過去而已。

我還是把那個字尾名的解決辦法寫了下:

在客戶端:修改的程式碼如下:

//上傳
        try {
            Socket s = new Socket("10.30.7.95", 10007);

            BufferedInputStream bin = new BufferedInputStream(new FileInputStream(str));

            //上傳檔案字尾###########增加的
            OutputStream out = s.getOutputStream();
            String fileName = file.getName();
            out.write(fileName.substring(fileName.length()-4, fileName.length()).getBytes());

            byte buf[] = new byte[1024];
            int len=0;
            while((len=bin.read(buf))!=-1){
                out.write(buf, 0, len);
            }

            s.shutdownOutput();//告訴伺服器,檔案上傳完畢

            //讀取伺服器的回饋資訊
            InputStream in = s.getInputStream();
            byte buf2[] = new byte[1024];
            int len2 = in.read(buf2);
            System.out.println(new String(buf2, 0, len2));

            //關流
            out.close();
            bin.close();
            s.close();

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

伺服器端:

@Override
    public void run() {

        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+"...發來圖片");

        try {


            BufferedInputStream bin = new BufferedInputStream(s.getInputStream());

            File dir = new File("g:\\mypic");

            if(!dir.exists()){
                dir.mkdir();//資料夾不存在,建立mypic資料夾
            }


            //讀取上傳過來的圖片字尾是什麼!#########
            char cbuf[] = new char[4];
            InputStreamReader insr = new InputStreamReader(bin);
            insr.read(cbuf);
            String str = new String(cbuf);

            int count=1;
            //我覺得這裡的字尾名,需要通過傳送方也發過來的
            File file = new File(dir, ip+str);

            while(file.exists()){
                file = new File(dir,ip+"("+(count++) +")"+str); //帶號的檔名
            }

            FileOutputStream fout = new FileOutputStream(file);

            //從socket流中讀取資料,儲存到本地檔案。相當於對拷
            byte buf[] = new byte[1024];
            int len=0;
            //#########必須有這一句
            bin.read(buf, 0, 8);
            while( (len=bin.read(buf))!=-1){
                fout.write(buf, 0, len);
            }
            //圖片接收完畢

            //向客戶端傳送回饋資訊
            OutputStream out = s.getOutputStream();
            out.write( "上傳成功".getBytes() );

            fout.close();
            s.close();

        } catch (IOException e) {
            e.printStackTrace();
        }



    }

好了,基本上就是這樣的,如果想要更好,做個圖形介面就好看了。自己動下手吧~~

相關推薦

Java---網路程式設計(3)-TCP-檔案圖片

☆ TCP 建立連線,形成傳輸資料的通道。 在連線中進行大資料量傳輸 通過三次握手完成連線,是可靠協議 必須建立連線,效率會稍低 Socket 和 ServerSocket類 TCP傳輸 TCP Socket:IP地址和埠,套接字 Sock

網路程式設計——3.TCP/UDP實現跨平臺檔案傳輸

一、實驗目的     在上次檔案傳輸的程式基礎上,利用循環面向連線、迴圈無連線方式完成linux和windows平臺的檔案傳輸,並完成客戶端、伺服器端程式碼的封裝。 二、實驗分析      1.使用TCP實現   在上次實驗基礎上,使用tcp_server.c的程式碼

網路程式設計3-TCP/UDP

4.2 Socket程式設計 基礎知識: 1.在windows/linux下都有一個ping命令,用來檢查對方主機是否連通。若請求超時:對方關機或離線;己方沒有連網;對方線上,但遮蔽了ping服務。 2.檢視自己的IP,windows:ipconfig;linux:ifconfig。

Java網路程式設計7.TCP網路程式設計之客戶端鍵盤錄入伺服器控制檯輸出

TCP網路程式設計之客戶端鍵盤錄入伺服器控制檯輸出 1、鍵盤錄入資料 BufferedReader br = new BufferedReader(new InputStreamReader(S

java網路程式設計基於TCP的多客戶端連線伺服器

package com.test.net; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.S

JAVA 網路程式設計UDP TCP

UDP協議   UDP是無連線通訊協議,即在資料傳輸時,資料的傳送端和接收端不建立邏輯連線。簡單來說,當一臺計算機向另外一臺計算機發送資料時,傳送端不會確認接收端是否存在,就會發出資料,同樣接收端在收到資料時,也不會向傳送端反饋是否收到資料UDP的交換過程如下圖所示。 優

java 網路程式設計(Socket) TCP/UDP 總結案例

網路程式設計:關注的是底層的資料傳輸 網頁程式設計:資料的展示 1、基本概念 一、網路:將不同的計算機連線在一起區域網 都會網路 網際網路 二、地址:Ip地址確定網路上的絕對的地址位置   房子的地址 三、埠號(相當於房門):區分計算機上的軟體 相當於房門兩個位元組

Java網路程式設計(一) TCP/IP,http,socket,長連線,短連線

TCP/IP  TCP/IP是個協議組,可分為三個層次:網路層、傳輸層和應用層。  在網路層有IP協議、ICMP協議、ARP協議、RARP協議和BOOTP協議。  在傳輸層中有TCP協議與UDP協議。  在應用層有:TCP包括FTP、HTTP、TELNET、SMTP等協議

Java 網路程式設計TCP協議

TCP協議 (伺服器端程先啟動,等待客戶端連線)   TCP協議是面向連線的通訊協議,即在傳輸資料前先在傳送端和接收端建立邏輯連線,然後再傳輸資料 保證傳輸資料的全性安,檔案資料不易丟失   在JDK中提供了兩個類用於實現TCP程式,一個是ServerSocket類,用於表示伺

JAVA網路程式設計 ——基於TCP的Socket程式設計(1)——實現伺服器端與客戶端的實時對話

第一篇文章,我先介紹以及記錄一下我所學的知識點。(總結了一下視訊老師講的東西)一,HTTP與Socket1.HTTP:超文字傳輸協議特點:客戶端傳送的請求需要伺服器端每次來響應,在請求結束之後主動釋放連線,從建立連線到關閉連線稱為“一次連線”,所以HTTP是“短連線”。2.S

JAVA網路程式設計TCP篇入門)

此次部落格主要以程式碼為主,其中包含了豐富的註釋 簡單的tcp 簡單介紹tcp是如何傳送資料,以及接受資料 程式碼一:客戶端 package com.net.tcp; import java.io.IOException; import java.io.Out

Linux網路程式設計Tcp/Udp socket檔案傳輸示例

本文所述示例程式是基於Linux平臺的socket網路程式設計,實現檔案傳輸功能。該示例是基於TCP流協議實現的socket網路檔案傳輸程式。採用C語言編寫。最終能夠實現傳輸任何格式檔案的檔案傳輸程式。 具體實現程式碼如下: /***********************

Java網路程式設計】:Netty實現OIONIO

承接上文:https://blog.csdn.net/hxcaifly/article/details/85274664 前言 單純地使用Java JDK來實現網路NIO是一件開發成本非常高的事情。然而,Netty 為它所有的傳輸實現提供了一個通用API,這使得這種

ueditor1.4.3 單獨上檔案以及圖片的使用配置

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%String contextPath = request.getContextP

JAVA 網路程式設計(簡單的傳送端接受端)

/* UDP 1,將資料及源和目的封裝成資料包中,不需要建立連線 2,每個資料報的大小在限制在64k 3,因為無連線,是不可靠協議的 4,不需要建立連線,速度快 TCP 1,建立連線,

java網路程式設計3TCP

使用TCP進行網路資料傳輸的時候,TCP會在需要傳輸資料的兩端建立兩個Socket(插座),並且在兩個Socket之間建立一條虛擬鏈路,然後這兩臺主機就可以進行通訊了。 下面是一個很簡單的例子。 Server類建立一個ServerSocket物件,用於監聽客戶端Socke

Java網路程式設計例子2_TCP檔案

注意:網路程式設計的正常步驟先跑服務端,再跑客戶端; 第一步先用eclipse執行server端; 第二步用命令列執行客戶端; 檢視結果: 把檔案copy出去改下字尾,發現檔案可以開啟 package cn.njit.internet.fileUploa

javaSE (四十)網路程式設計TCP傳輸、伺服器多執行緒、網路程式設計練習:反轉字串、上檔案

1、TCP傳輸: 1.客戶端 建立Socket連結服務端(指定ip地址,埠號),通過ip地址找到對應的伺服器 呼叫Socket的getInputStream和getOutputStream方法獲取和伺服器端相連的IO流 2.伺服器端 建立Se

java網路程式設計--socket上檔案

直接程式碼不多說! 服務端: package scoket.file.server; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; impo

java 網路程式設計——TCP 的三次握手四次揮手

文章目錄 TCP報頭 三次握手 未連線佇列 四次揮手 狀態詳解 在TCP/IP協議中,TCP協議提供可靠的連線服務,採用三次握手建立一個連線. TCP報頭 埠號:用來標識