Java基礎---網絡編程

1、網絡模型:OSI參考模型和TCP/IP參考模型

這裏寫圖片描述

通常用戶操作的是應用層,而編程人員需要做的是傳輸層和網際層,用戶在應用層操作的數據,經過逐層封包,最後到物理層發送到另一個模型中,再進行逐層解包,圖示爲:
![package1](https://img-blog.csdn.net/20150812000227184)

2、網絡通信三要素:IP地址,端口號,傳輸協議

1.IP地址

 1. 它是網絡中的設備標識
 2. 不易記憶,可用主機名錶示,兩者存在映射關係
 3. 本機迴環地址:127.0.0.1,主機名爲:localhost。

IP地址:java中對應的是InetAddress類,存在於java.net包中。

InetAddress類:
(一)無構造函數,可通過getLocalHost()方法返回本地主機獲取

InetAddress對象,此方法是靜態的。
InetAddress i = InetAddress.getLocalHost();

(二)方法:

1. static InetAddress getByName(String host):獲取指定主機的IP和主機名。(最好用ip地址去獲取,主機名需要解析)

2. static InetAddress[] getAllByName(String host):在給定主機名的情況下,根據系統上配置的名稱服務返回IP地址所組成的數組。返回對象不唯一時,用此方法。

3. String getHostAddress():返回IP地址字符串文本形式,以IP地址爲主。

4. String getHostName():返回IP地址主機名。

(三)如何獲取任意一臺主機的IP地址對象:

1. 功能:返回InetAddress對象

2. 對於任意主機,需要指定傳入主機名的參數

注意:如果IP地址和對應的主機名,這種映射關係沒有在網絡上,就不會解析成功,返回的還是指定的IP。

import java.net.InetAddress;
import java.net.UnknownHostException;

public class IpDemo {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        //獲取我的本機信息
        InetAddress ip = InetAddress.getByName("LQX");
    //本機名和IP的打印
        System.out.println("IP:"+ip.getHostAddress()+"\tname="+ip.getHostName());
        //這個是我在hosts文件中定義的一個對應關係
        InetAddress ip2 = InetAddress.getByName("www.lqx.com");
        System.out.println("IP:"+ip2.getHostAddress()+"\tname:"+ip2.getHostName());
        //查詢百度網站的IP,百度應該不止有一個主機
         InetAddress[] baidu=InetAddress.getAllByName("www.baidu.com");  
            for (InetAddress b :baidu)  
            {  
                String baddress=b.getHostAddress();  
                String bname=b.getHostName();  
                System.out.println("baiduIP="+baddress+"\tbaiduname="+bname);  
            }  
    }

}

打印結果:
ip

2.端口號

1. 定義:

     隨着計算機網絡技術的發展,原來物理上的接口(如鍵盤、鼠標、網卡、顯示卡等輸入/輸出接口)已不能滿足網絡通信的要求,TCP/IP協議作爲網絡通信的標準協議就解決了這個通信難題。TCP/IP協議集成到操作系統的內核中,這就相當於在操作系統中引入了一種新的輸入/輸出接口技術,因爲在TCP/IP協議中引入了一種稱之爲"Socket(套接字)"應用程序接口。有了這樣一種接口技術,一臺計算機就可以通過軟件的方式與任何一臺具有Socket接口的計算機進行通信。端口在計算機編程上也就是"Socket接口"。

a、用於標識進程的邏輯地址,不用進程的標識。
b、有效端口:0 ~65535,系統使用或保留的端口是:0~ 1024。

3.傳輸協議

即通信規則,包含TCP和UDP協議

一. UDP(User Datagram Protocol)用戶數據報協議

1.  一種無連接的傳輸層協議,位於第四層——傳輸層,處於IP協議的上一層

2. 當報文發送之後,是無法得知其是否安全完整到達的

3. 資源消耗小,處理速度快的優點

所以通常音頻、視頻和普通數據在傳送時使用UDP較多,因爲它們即使偶爾丟失一兩個數據包,也不會對接收結果產生太大影響。比如我們聊天用的ICQ和QQ就是使用的UDP協議。
二. TCP(Transmission Control Protocol 傳輸控制協議)

1. 一種面向連接的、可靠的、基於字節流的傳輸層通信協議,位於第四層——傳輸層,和UDP協議位於同一層

2. 通過三次握手完成連接,是可靠的協議

3. 必須建立連接,效率稍慢

TCP三次握手的過程如下:
(1)
客戶端發送報文給服務器進入SEND狀態。

(2)
服務器端收到報文,迴應一個ACK報文,進入RECV狀態。

(3)
客戶端收到服務器端的SYN報文,迴應一個ACK報文,進入Established
建立狀態。

3、JAVA的UDP和TCP編程

1.Socket套接字

1. 用於描述IP地址和端口,是一個通信鏈的句柄,可以用來實現不同虛擬機或不同計算機之間的通信

2.它被稱之爲插座,相當於港口一樣,是網絡服務提供的一種機制。

3.通信兩端都要有Socket,才能建立服務。


4.網絡通信其實就是Socket間的通信,數據在兩個Socket間通過IO傳輸。

2.UDP傳輸

在Java API中,實現UDP方式的編程,包含客戶端網絡編程和服務器端網絡編程,主要由兩個類實現,分別是:

1. DatagramSocket:UDP客戶端編程涉及的步驟也是4個部分:建立連接、發送數據、接收數據和關閉連接。

DatagramSocket ds = new DatagramSocket();
這樣就建立了一個鏈接,但是沒有指定端口,系統會使用未被佔用的端口,一般常用來做發送端。
DatagramSocket receive = new DatagramSocket(10001);
這種定義常用來做接收端,他會一直監聽10001端口。

2. DatagramPacket:這個類中封裝了許多傳輸的信息,對象中包含發送到的地址、發送到的端口號以及發送的內容等。

DatagramPacket dp = new DatagramPacket(byte[] buf, int length, InetAddress address, int port) ;
IO編程在UDP方式的網絡編程中變得不是必須的內容。

接着,介紹一下UDP客戶端編程中發送數據的實現。在UDP方式的網絡編程中,IO技術不是必須的,在發送數據時,需要將需要發送的數據內容首先轉換爲byte數組,然後將數據內容、服務器IP和服務器端口號一起構造成一個DatagramPacket類型的對象,這樣數據的準備就完成了,發送時調用網絡連接對象中的send方法發送該對象即可。
/***
 * UDP發送端:
 * 需求:通過udp傳輸方式,將一段文字數據發送出去
 */
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class Send {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub

        //1.獲取目標地址(本機地址)
        InetAddress ip = InetAddress.getLocalHost();
        //2.發送端的聲明
        DatagramSocket send = new DatagramSocket();

        //3.要發送的字符串
        String s = "Hello my name is Luan";
        //轉byte
        byte []b = s.getBytes();
        //4.傳送字節數組b,目標地址爲本機,端口10000
        DatagramPacket packet = new DatagramPacket(b, b.length, ip, 10000);

        //5.使用DatagramSocket類中的Send方法發送數據包
        send.send(packet);
        //6.資源關閉
        send.close();
    }

}


/***
 * UDP接收端
 * 需求:定義一個應用程序,用於接收udp協議傳輸的數據並處理。 
 */
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class Receive {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //1.接收端需要提供端口,實時監聽
        DatagramSocket recv = new DatagramSocket(10000);
        //2.定義數據包,用於存儲數據
        byte b[] = new byte[1024];
        //定義收到的包是放在字節數組b裏的
        DatagramPacket packet = new DatagramPacket(b, b.length);
        //3.receive方法獲取數據包
        recv.receive(packet);//阻塞式方法:沒有數據就不繼續往下執行,至到得到數據。
        String s = new String(b, 0, packet.getLength());
        System.out.println(packet.getAddress()+"::"+packet.getPort()+"::"+s);
        //4.關閉資源
        recv.close();
    }

}

udp1
信息傳過來了,ip地址是沒有問題的,我上的校園網分發的IP就是他。端口號是發送端的端口號,沒有問題。

/***
 * UDP的發送端
 * 需求:用鍵盤錄入的方式,來發送數據 
 */
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class InputSend {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub


        //1.獲取目標地址(本機地址)
        InetAddress ip = InetAddress.getLocalHost();
        //2.發送端的聲明
        DatagramSocket send = new DatagramSocket();
        DatagramPacket packet = null;
        //3.輸入的字符讀取到內存
         BufferedReader in
           = new BufferedReader(new InputStreamReader(System.in));
         String s =null;
         while((s=in.readLine())!=null)
         {
                //如果發的是“88”,則資源關閉
                if(s.equals("88"))
                {
                    break;
                }
                //轉byte
                byte []b = s.getBytes();
                //傳送字節數組b,目標地址爲本機,端口10000
                packet = new DatagramPacket(b, b.length, ip, 10000);
                //使用DatagramSocket類中的Send方法發送數據包
                send.send(packet);
         }
         send.close();
    }
}

/***
 * 接收端
 */
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class InputReceive {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub

        //1.接收端需要提供端口,實時監聽
                DatagramSocket recv = new DatagramSocket(10000);
                //2.定義數據包,用於存儲數據

                while(true)
                {
                    byte b[] = new byte[1024];
                    //定義收到的包是放在字節數組b裏的
                    DatagramPacket packet = new DatagramPacket(b, b.length);
                    //3.receive方法獲取數據包
                    recv.receive(packet);//阻塞式方法 :沒有數據就不繼續往下執行,至到得到數據。
                    String s = new String(b, 0, packet.getLength());
                    System.out.println(packet.getAddress()+"::"+packet.getPort()+"::"+s);
                }
    }
}

發送端:
這裏寫圖片描述
接收端:
這裏寫圖片描述

/***
 *需求:UDP的客戶端的聊天程序
 *需要用到線程的使用:發送端和接收端分別做成兩個線程
 *共同組成了這個客戶端的進程
 */
import java.io.*;
import java.net.*;

public class UDPTalk {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Send s1 = new Send();
        receive r1 = new receive();
        Thread t1 = new Thread(s1);
        Thread t2 = new Thread(r1);
        t1.start();
        t2.start();

    }

}
//接收端
class Send implements Runnable {
    private DatagramSocket send = null;
    private DatagramPacket packet = null;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            InetAddress ip = InetAddress.getLocalHost();
            send = new DatagramSocket();
            BufferedReader in = 
                    new BufferedReader(new InputStreamReader(System.in));
             String s =null;
             while((s=in.readLine())!=null)
             {
                    //如果發的是“88”,則資源關閉
                    if(s.equals("88"))
                    {
                        break;
                    }
                    //轉byte
                    byte []b = s.getBytes();
                    //傳送字節數組b,目標地址爲本機,端口10000
                    packet = new DatagramPacket(b, b.length, ip, 10000);
                    //使用DatagramSocket類中的Send方法發送數據包
                    send.send(packet);
             }
             send.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            throw new RuntimeException("發送數據失敗"); 
            //System.out.println("目的主機無效!");
        } 
    }
}

//接收端
class receive implements Runnable
{
    private DatagramSocket recv = null;
    private DatagramPacket packet = null;
    @Override
    public void run() {
        // TODO Auto-generated method stub
        //1.接收端需要提供端口,實時監聽
        try {
            recv = new DatagramSocket(10000);
            while(true)
            {
                byte b[] = new byte[1024];
                //定義收到的包是放在字節數組b裏的
                DatagramPacket packet = new DatagramPacket(b, b.length);
                //3.receive方法獲取數據包
                recv.receive(packet);//阻塞式方法 :沒有數據就不繼續往下執行,至到得到數據。
                String s = new String(b, 0, packet.getLength());
                System.out.println(packet.getAddress()+"::"+packet.getPort()+"::"+s);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
             throw new RuntimeException("接收端接收數據失敗");  
        }
    }   
}

udp3.0
只能自己和自己聊了,如果想和別人聊,那麼要把目標IP改爲廣播地址。
## 標題 ##
比如我這個就應該是111.114.116.255,那麼大家都往這個IP發送內容的話就可以一起聊天了。

2.TCP傳輸

TCP傳輸,需要明確的區分客戶端和服務端。

  1. 客戶端使用的類是:Socket,他的構造方法會指定目標地址和端口;
    Socket client1 = new Socket(InetAddress address, int port);

    兩個基本方法:
    public InputStream getInputStream():返回此套接字的輸入流,Socket對象調用

    public OutputStream getOutputStream():返回套接字的輸出流,Socket對象調用

  2. 服務器端使用的類:ServerSocket,他的構造方法只需制定需要監聽的端口號即可。
    ServerSocket server = new ServerSocket(int port);
    基本方法:
    public Socket accept():返回值是一個Socket對象,也就是說在服務器端開闢了一個空間,這個空間專門爲對應的客戶端服務。可以理解爲,只要客戶端對服務器有請求,那麼在服務器就會獲取這個客戶端的Socket對象,並使用這個服務器端的客戶端Socket對象與客戶端交流。

/***
 * 客戶端代碼
 * 需求:客戶端給服務端發送數據,服務端收到後,給客戶端反饋信息。
 */
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class Client {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //目標IP獲取
        InetAddress ip = InetAddress.getLocalHost();
        //1.建立客戶端Socket,指定目的主機和端口  
        Socket client1 = new Socket(ip, 10000);
        //2.獲取Socket流中輸出流,發送數據
        OutputStream ou = client1.getOutputStream();
        String s = "這是我的第一個TCP編程!";
        byte b[] = s.getBytes();
        ou.write(b);

        //對服務器返回的數據進行接收
        InputStream in =client1.getInputStream();
        byte b2[] = new byte[1024];
        int len2 = in.read(b2);
        String s2 = new String(b2, 0, len2);
        System.out.println(s2);

        client1.close();
    }
}

/***
 * 服務器端
 *需求: 響應客戶端的請求
 */
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //1.服務端使用的是ServerSocket類
        ServerSocket server = new ServerSocket(10000);
        //2.accept方法會獲得一個Socket對象,並偵聽此對象
        Socket client = server.accept();
        //3、獲取對應客戶端對象的讀取流讀取發過來的數據,並打印
        InputStream in = client.getInputStream();
        byte b[] = new byte[1024];
        int len = in.read(b);
        String s = new String(b, 0, len);
        System.out.println(s);

        //對客戶端的回覆
        OutputStream ou = client.getOutputStream();
        ou.write("我是服務器,收到了".getBytes());
        server.close();
    }
}

服務器端顯示收到了:
這裏寫圖片描述
客戶端收到了服務器端的響應:
這裏寫圖片描述

/***
 * 練習 
 * 需求:建立一個文本轉換服務器 
 * 客戶端給服務端發送文本,服務端會將文本轉成大寫再返回給客戶端。 
 * 而且客戶端可以不斷的進行文本轉換。當客戶端輸入over時,轉換結束。
 */
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;

public class UpCaseClient1 {

    public static void main(String[] args) throws IOException, IOException {
        // TODO Auto-generated method stub

        //創建socket服務
        Socket client = new Socket("127.0.0.1", 10000);

         //定義目的,將數據寫入到Socket輸出流。發給服務端  
        PrintWriter pw = new PrintWriter(client.getOutputStream(), true);

        //定義讀取鍵盤數據的流對象
        BufferedReader br1 = 
                new BufferedReader(new InputStreamReader(System.in));

        //定義一個Socket讀取流,讀取服務端返回的大寫信息。
        BufferedReader br2 = 
                new BufferedReader(new InputStreamReader(client.getInputStream()));

        String s = null;
        String ret = null;
        while((s=br1.readLine())!=null)
        {
            //判斷,是“over”,結束
            if(s.equals("over"))
            {
                break;
            }else{
                pw.println(s);//發送
                ret = br2.readLine();//讀取返回的信息
                System.out.println(ret);
            }
        }
        client.close();
    }
}


/**
 * 服務器端
 */
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class UpCaseServer1 {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        //創建服務端的ServerSocket服務,並指定監聽端口 
        ServerSocket server = new ServerSocket(10000);

        //獲取客戶端連接
        Socket client1 = server.accept();

        //讀取Socket流中的數據  
        BufferedReader br1 = 
                new BufferedReader(new InputStreamReader(client1.getInputStream()));

         //將大寫數據寫入到Socket輸出流,併發送給客戶端。
        PrintWriter pw = new PrintWriter(client1.getOutputStream(), true);
        String s = null;
        while((s = br1.readLine())!=null)
        {
            if(s.equals("over"))
            {
                break;
            }else{
                //將讀到數據轉換爲大寫後返回 
                s = s.toUpperCase();
                pw.println(s);
                System.out.println(s);
            }
        }
        server.close();
    }
}

這裏寫圖片描述

這裏遇到的問題主要是:由於Writer類實現了Flushable接口,調用 flush 方法將所有已緩衝輸出寫入底層流。
所以,出現的兩邊都在等待的問題,第一點就是因爲,數據沒有實時刷新造成的,那麼需要調用flush方法手動刷進去。

錯誤案例,客戶端和服務器端都沒有反應

/**客戶端
*/
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;

public class UpCaseClient1 {

    public static void main(String[] args) throws IOException, IOException {

        //創建socket服務
        Socket client = new Socket("127.0.0.1", 10000);

         //定義目的,將數據寫入到Socket輸出流。發給服務端  
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));

        //定義讀取鍵盤數據的流對象
        BufferedReader br1 = 
                new BufferedReader(new InputStreamReader(System.in));

        //定義一個Socket讀取流,讀取服務端返回的大寫信息。
        BufferedReader br2 = 
                new BufferedReader(new InputStreamReader(client.getInputStream()));

        String s = null;
        String ret = null;
        while((s=br1.readLine())!=null)
        {
            //判斷,是“over”,結束
            if(s.equals("over"))
            {
                break;
            }else{
                bw.write(s+"\r\n");
                //bw.newLine();//換行  
                //bw.flush();//此處是重點,如果此處不打開,那麼數據將會不再刷新出去,那麼客戶端和服務器端都在等待。
                ret = br2.readLine();//讀取返回的信息
                System.out.println(ret);
            }
        }
        client.close();
    }
}

/**
 * 服務器端
 */
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class UpCaseServer1 {

    public static void main(String[] args) throws IOException {
        //創建服務端的ServerSocket服務,並指定監聽端口 
        ServerSocket server = new ServerSocket(10000);

        //獲取客戶端連接
        Socket client1 = server.accept();

        //讀取Socket流中的數據  
        BufferedReader br1 = 
                new BufferedReader(new InputStreamReader(client1.getInputStream()));

         //將大寫數據寫入到Socket輸出流,併發送給客戶端。
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client1.getOutputStream()));
        String s = null;
        while((s = br1.readLine())!=null)
        {
            if(s.equals("over"))
            {
                break;
            }else{
                //將讀到數據轉換爲大寫後返回 
                s = s.toUpperCase();
                //pw.println(s);
                bw.write(s+"\r\n");
                //bw.newLine();//換行  
                //bw.flush();//此處重點同上
                System.out.println(s);

            }
        }
        server.close();
    }
}

問題:

上面的代碼運行不了,歸根結底就是因爲,Write繼承了接口 Flushable,那麼,每次服務器讀取一行,如果讀不到換行標誌,則等待;客戶端讀取鍵盤輸入,讀取後不使用flush方法刷出去,那麼積壓住,兩邊都等待,造成兩邊都是等待的問題

解決辦法:

1.手動添加換行標誌。
2.使用PrintWriter pw = new PrintWriter(client.getOutputStream(), true);treu的意思爲自動刷新,且提供prinlln()方法,免去了手動添加換行和刷新的麻煩。
/***
 * 需求:向服務器上傳一個文件,服務返回一條信息 
 * 1、客戶端:
 * 源:硬盤上的文件;目的:網絡設備,即網絡輸出流。
 * 若操作的是文本數據,可選字符流,並加入高效緩衝區。若是媒體文件,用字節流。

 * 2、服務端:
 * 源:socket讀取流;目的:socket輸出流。
 * 
 * 3、出現的問題: 
 * 現象:
 * a、文件已經上傳成功了,但是沒有得到服務端的反饋信息。
 * b、即使得到反饋信息,但得到的是null,而不是“上傳成功”的信息
 * 
 * 原因:
 * a、因爲客戶端將數據發送完畢後,由於雙發並沒有指定結束標誌,那麼服務端仍然在等待讀取數據,雙方都在等待。
 * b、上個問題解決後,收到的不是指定信息而是null,是因爲服務端寫入數據後,需要刷新,才能將信息反饋給客服端。
 * 
 * 解決a:
 * 方法一:定義結束標記,先將結束標記發送給服務端,讓服務端接收到結束標記,然後再發送上傳的數據。但是這樣定義可能會發生定義的標記和文件中的數據重複,而導致提前結束。
 * 方法二:定義時間戳,由於時間是唯一的,在發送數據前,先獲取時間,發送完後在結尾處寫上相同的時間戳,在服務端,接收數據前先接收一個時間戳,然後在循環中判斷時間戳以結束標記。
 * 方法三:通過socket方法中的shutdownOutput(),關閉輸入流資源,從而結束傳輸流,以給定結束標記。通常用這個方法。
 * 解決b:
 * 方法一:若使用 BufferedWriter bwout=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));  則需要調用flush()方法刷新
 * 方法二:直接使用PrintWriter pw2 = new PrintWriter(client.getOutputStream(),true);自動刷新。
 */

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;

/***
 * 練習 
 * 需求:向服務器上傳一個文件,服務器返回一條信息 
 * @author LQX
 *
 */
public class UpLoadClient {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub

        Socket client = new Socket("127.0.0.1", 10000);
        //文件的讀取
        BufferedReader br1 = 
                new BufferedReader(new FileReader("f:\\DemoClass.java"));

        //定義目的,將數據寫入到Socket數據流中,併發送給服務端
        //此處我設置自動刷新,方便操作,也可以使用BufferedReader,那麼後面就必須手動刷新
        PrintWriter pw = new PrintWriter(client.getOutputStream(), true);

        //讀取Socket讀取流中的數據 
        BufferedReader br2 = 
                new BufferedReader(new InputStreamReader(client.getInputStream()));

        String s = null;

        while((s = br1.readLine())!=null)
        {
            pw.println(s);
        }
        /**
         * 通過socket方法中的shutdownOutput(),關閉輸入流資源,
         * 從而結束傳輸流,以給定結束標記。通常用這個方法。
         * 不加這個,那麼,服務器端沒有結束標誌,仍然等待客戶端發送數據。
         */
        client.shutdownOutput();//關閉客戶端的輸出流。相當於給流中加入一個結束標記-1. 
        System.out.println(br2.readLine());
        client.close();
    }
}


/***
 * 服務器端
 * 主要使用了PrintWriter(OutputStream out, boolean autoFlush) 構造方法
 * 直接指定了自動刷新,比較方便
 * 
 */
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class UpLoadServer {
public static void main(String[] args) throws IOException {
    ServerSocket server = new ServerSocket(10000);
    //獲取客戶端鏈接
    Socket client = server.accept();

    //讀取Socket讀取流中的數據  
    BufferedReader br = 
            new BufferedReader(new InputStreamReader(client.getInputStream()));

    //
    PrintWriter pw1 = new PrintWriter(new FileWriter("f:\\Copy.txt"),true);

    //將返回信息寫入Socket流的寫入流中  
    PrintWriter pw2 = new PrintWriter(client.getOutputStream(),true);
    String s = null;
    while((s=br.readLine())!=null)
    {
        System.out.println(s);
        pw1.println(s);
    }
    pw2.println("接收成功!");
    server.close();
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章