天天看點

Java精選筆記_網絡程式設計

網絡程式設計

概述

    現在的網絡程式設計基本上都是基于請求/響應方式的,也就是一個裝置發送請求資料給另外一個,然後接收另一個裝置的回報。

    在網絡程式設計中,發起連接配接程式,也就是發送第一次請求的程式,被稱作用戶端(Client),等待其他程式連接配接的程式被稱作伺服器(Server)。

網絡通信協定

    連接配接和通信的規則被稱為網絡通信協定,它對資料的傳輸格式、傳輸速率、傳輸步驟等做了統一規定,通信雙方必須同時遵守才能完成資料交換。

IP位址和端口号

    IP位址:InetAddress

    網絡中裝置的辨別

    不易記憶,可用主機名

    本地回環位址:127.0.0.1  主機名:localhost

    端口号

    用于辨別程序的邏輯位址,不同程序的辨別。邏輯位址,區分不同的服務

    有效端口:0~65535,其中0~1024系統使用或保留端口。

    備注:不是所謂的實體端口!

InetAddress

    InetAddress:構造方法私有,不能直接建立對象。

    InetAddress getByName(String host): 在給定主機名的情況下确定主機的ip位址。

    InetAddress getLocalHost():傳回本地主機。

    InetAddress[] getAllByName(String host);

    ip.getHostAddress()

    ip.getHostName()

Eg:

package com.li.net;

import java.net.InetAddress;

public class Demo1 {

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

        InetAddress i = InetAddress.getLocalHost();

        System.out.println(i);

        i = InetAddress.getByName("www.baidu.com");

        System.out.println(i);

        System.out.println(i.getHostAddress());

        System.out.println(i.getHostName());

    }

}

輸出:

XP-201706252326/10.6.147.2

www.baidu.com/61.135.169.105

61.135.169.105

www.baidu.com

UDP與TCP協定

    TCP/IP協定(Transmission Control Protocal/Internet Protoal傳輸控制協定/英特網互聯協定),它是一個包括TCP協定和IP協定。

UDP(User Datagram Protocol)​​使用者資料報協定​​ ICMP(Internet Control Message Protocol)協定和其它一些協定的協定組

差別

類似于圖像、聲音等對可靠性要求沒有那麼高的業務可以用UDP,他們不需要準确存儲對準确性無要求但要求速度快。

類似于文本、程式、檔案等要求可靠的資料最好就用TCP,但會犧牲一些速度。 

對系統資源的要求:TCP較多,UDP少。 

程式結構:UDP程式結構較簡單,TCP複雜。 

流模式與資料報模式:TCP保證資料正确性,UDP可能丢包; TCP保證資料順序,UDP不保證

用途

    TCP是面向連接配接的,有比較高的可靠性,一些要求比較高的服務一般使用這個協定,如FTP、Telnet、SMTP、HTTP、POP3等,而 UDP是面向無連接配接的,使用這個協定的常見服務有DNS、SNMP、QQ等。

    UDP是一種面向無連接配接的通信協定,該協定使得資料傳輸的速度得到大幅度的提高。視訊聊天語音聊天基本都是用UDP協定。 

總結

UDP:

    1、将資料源和目的地封裝到資料包中,不需要建立連接配接

    2、每個資料包的大小限制在64k以内

    3、因無連接配接,是不可靠協定

    4、不需要建立連接配接,速度快

例子:聊天、對講機就是UDP的,面向無連接配接(不管在不在,知不知道,隻管發送,求速度),丢資料也不管。速度快。資料被分成包

TCP:

    1、建立連接配接,形成傳輸資料的通道

    2、在連接配接中進行大量資料的傳輸

    3、通過三次握手完成連接配接、是可靠協定

    4、必須建立連接配接,效率會稍低

例子:電話通話,必須連接配接,對方同意才可以發送資料(不然就等待),不能丢失資料。

UDP通信

DatagramPacket

DatagramPacket類的執行個體對象就相當于一個集裝箱,用于封裝UDP通信中發送或者接收的資料。

通過這個對象中的方法,就可以擷取到資料包中的各種資訊。

    byte[] getData()

    int getLength()

    int getPort()

    setData(byte[]

    setPort()

DatagramSocket

DatagramSocket類的作用就類似于碼頭,使用這個類的執行個體對象就可以發送和接收DatagramPacket資料包,封裝了udp傳輸協定的socket對象。

具備發送和接受功能,在進行udp傳輸時,需要明确一個是發送端,一個是接收端。

    receive(DatagramPacket)

    send(DatagramPacket)

UDP網絡程式設計

udp的發送端

    ①:建立udp的socket服務,建立對象時如果沒有明确端口,系統會自動配置設定一個未被使用的端口。

    ②:明确要發送的具體資料。

    ③:将資料封裝成了資料包。

    ④:用socket服務的send方法将資料包發送出去。

    ⑤:關閉資源。

發送端(用戶端)

import java.net.*;

class  UdpSend {

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

           // 1,建立udp的socket服務。

           DatagramSocket ds = new DatagramSocket(8888);//指定發送端口,這個可以不指定,系統會随機配置設定。

            // 2,明确要發送的具體資料。

            String text = "udp傳輸示範 哥們來了";

            byte[] buf = text.getBytes();

             // 3,将資料封裝成了資料包。

             DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("10.1.31.127"),10000);

             // 4,用socket服務的send方法将資料包發送出去。

             ds.send(dp);

             // 5,關閉資源。

             ds.close();

     }

}

udp的接收端

①:建立udp的socket服務,必須要明确一個端口,作用在于,隻有發送到這個端口的資料才是這個接收端可以處理的資料。

②:定義資料包,用于存儲接收到資料。

③:通過socket服務的接收方法将收到的資料存儲到資料包中。

④:通過資料包的方法擷取資料包中的具體資料内容,比如ip、端口、資料等等。

⑤:關閉資源。

接收端(伺服器端)

import java.net.*;

class UdpRece {

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

           // 1,建立udp的socket服務。

           DatagramSocket ds = new DatagramSocket(10000); //必須指定,并且和上面的端口号一樣!

           // 2,定義資料包,用于存儲接收到資料。先定義位元組數組,資料包會把資料存儲到位元組數組中。

           byte[] buf = new byte[1024];

           DatagramPacket dp = new DatagramPacket(buf,buf.length);

           // 3,通過socket服務的接收方法将收到的資料存儲到資料包中。

           ds.receive(dp); //該方法是阻塞式方法。

           // 4,通過資料包的方法擷取資料包中的具體資料内容,比如ip,端口,資料等等。

           String ip = dp.getAddress().getHostAddress();

           int port = dp.getPort();

           String text = new String(dp.getData(),0,dp.getLength()); //将位元組數組中的有效部分轉成字元串。

           System.out.println(ip+":"+port+"--"+text);

           // 5,關閉資源。

           ds.close();

    }

}

UDP案例--聊天程式

通過鍵盤錄入擷取要發送的資訊。

将發送和接收分别封裝到兩個線程中。

package com.li.net;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//用戶端,發送端
class Send implements Runnable {
    private DatagramSocket ds;
    public Send(DatagramSocket ds) {
        super();
        this.ds = ds;
    }
    @Override
    public void run() {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//資料源是鍵盤錄入
            String line;
            while ((line = br.readLine()) != null) {
                byte[] buf = line.getBytes();
                DatagramPacket dp = new DatagramPacket(buf, buf.length,InetAddress.getByName("localhost"), 10225);
                ds.send(dp);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
// 伺服器端,接收端
class Rece implements Runnable {
    private DatagramSocket ds;
    public Rece(DatagramSocket ds) {
        super();
        this.ds = ds;
    }
    @Override
    public void run() {
        try {
            while (true) {
                byte[] buf = new byte[1024];
                DatagramPacket dp = new DatagramPacket(buf, 0, buf.length);
                ds.receive(dp);
                String ip = dp.getAddress().getHostAddress();
                String data = new String(dp.getData(), 0, dp.getLength());
                System.out.println(ip + "     " + data);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
public class Demo6 {
    public static void main(String[] args) throws Exception {
        DatagramSocket sendDs = new DatagramSocket();
        DatagramSocket receDs = new DatagramSocket(10225);
        new Thread(new Send(sendDs)).start();
        new Thread(new Rece(receDs)).start();
    }
}
輸出:
你好
127.0.0.1     你好
你好
127.0.0.1     你好      

TCP通信

TCP通信是嚴格區分用戶端與伺服器端的,在通信時,必須先由用戶端去連接配接伺服器端才能實作通信,伺服器端不可以主動連接配接用戶端,并且伺服器端程式需要事先啟動,等待用戶端的連接配接。

在JDK中提供了兩個類用于實作TCP程式,一個是ServerSocket類,用于表示伺服器端,一個是Socket類,用于表示用戶端。

ServerSocket

    ServerSocket(端口) - 構造器

    setSoTimeout(int)

    Socket accept()

    close()

Socket

Socket就是為網絡服務提供的一種機制。

    Socket(IP位址, 端口) - 構造器

    getInputStream()

    getOutputStream()

    getChannel()

    close()

TCP案例--檔案上傳

題目:上傳檔案,多用戶端上傳,并且保證不會因為檔案的名稱而重複!

用戶端:

package com.li.net;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class Demo22 {
    public static void main(String[] args) throws Exception {
        Socket s = new Socket("localhost", 12036);
        BufferedReader br = new BufferedReader(new FileReader("E:/你好.txt"));
        PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
        BufferedReader br2 = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String line;
        while((line = br.readLine()) != null) {
            pw.println(line);
        }
        s.shutdownOutput();
        String str = br2.readLine();
        System.out.println(str);
        s.close();
    }
}      

伺服器端:

package com.li.net;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

class MyUpdate implements Runnable {
    private Socket s;
    public MyUpdate(Socket s) {
        super();
        this.s = s;
    }
    @Override
    public void run() {
        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip+".........connected!");
        int count = 0;
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            File file = new File("E:/");
            File f = new File(file,"你好"+count+".txt");
            while(f.exists()) {    //如果寫成if,就不可以!
                f = new File(file,"你好"+(++count)+".txt"); 
            }
            PrintWriter pw = new PrintWriter(new FileWriter(f),true);
            PrintWriter pw2 = new PrintWriter(s.getOutputStream(),true);
            String line;
            while((line = br.readLine()) != null) {
                pw.println(line);
            }            
            pw2.println("恭喜您,上傳成功!");
            s.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
public class Demo23 {
    public static void main(String[] args) throws Exception {    
        ServerSocket ss = new ServerSocket(12036);
        while(true) {
            Socket s = ss.accept();
            new Thread(new MyUpdate(s)).start();
        }
    }
}