天天看點

黑馬程式員——黑馬學習日志之十七 網絡程式設計

------- android教育訓練、java教育訓練、期待與您交流! ----------

黑馬學習日志之十七 網絡程式設計

1 網絡程式設計概述:

網絡程式設計的本質是兩個裝置之間的資料交換,就是把一個裝置中的資料發送給另外一個裝置,然後接收另外一個裝置回報的資料。

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

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

用戶端程式可以在需要的時候啟動,而伺服器為了能夠時刻響應連接配接,則需一直啟動。連接配接一旦建立以後,就用戶端和伺服器端就可以進行資料傳遞。

2 網絡通訊要素:

IP位址、端口号、傳輸協定。

IP位址: InetAddress

網絡中裝置的辨別,不易記憶,可用主機名。

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

端口号:

用于辨別程序的邏輯位址,給不同程序進行辨別

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

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

傳輸協定:通訊的規則

常見協定:TCP,UDP。

3 TCP和UDP

兩者差別

這兩種傳輸協定也就是合于适配不同的業務和不同的硬體終端。 

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

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

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

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

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

兩者用途

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

UDP是面向無連接配接的,使用這個協定的常見服務有DNS、SNMP、QQ等。UDP是一種面向無連接配接的通信協定,該協定使得資料傳輸的速度得到大幅度的提高。視訊聊天語音聊天基本都是用UPD協定。 

總結:

UDP:

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

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

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

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

例子:聊天、對講機

TCP:

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

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

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

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

例子:電話通話,

4 InetAddress

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

InetAddress getByName(String host): //擷取指定主機。

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

InetAddress[] getAllByName(String host)

getHostAddress(), 

getHostName()

例子:

import java.net.InetAddress;

public class Demo {

        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());

        }

}

5 Socket

Socket就是為網絡服務提供的一種機制。通信的兩端都有Socket。網絡通信其實就是Socket間的通信。資料在兩個Socket間通過IO傳輸。隻要是網絡傳輸,必須有socket 。資料一定要封裝到資料包中,資料包中包括目的位址、端口、資料等資訊。

6 UDP傳輸

直接操作udp不可能,對于java語言應該将udp封裝成對象,便于我們的使用,

這個對象就是DatagramSocket.,封裝了udp傳輸協定的socket對象。

因為資料包中包含的資訊較多,為了操作這些資訊友善,也一樣會将其封裝成對象。這個資料包對象就是:DatagramPacket,通過這個對象中的方法,就可以擷取到資料包中的各種資訊。

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

udp的發送端:

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

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

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

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

5:關閉資源。

udp的接收端:

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

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

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

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

5:關閉資源。

例子:

發送端(用戶端)

import java.net.*;

class  UdpSend{

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

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

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

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

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

                byte[] buf = text.getBytes();

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

                DatagramPacket dp = 

                        new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10025);

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

                ds.send(dp);

                // 5,關閉資源。

                ds.close();

        }

}

接收端(伺服器端)

import java.net.*;

class UdpRece {

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

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

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

                // 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();

        }

}

7 TCP傳輸:

tcp的兩個端點:一個是用戶端,一個是服務端。

用戶端:對應的對象,Socket

服務端:對應的對象,ServerSocket

兩個端點建立連接配接後會有一個傳輸資料的通道,這個通道稱為流,而且是建立在網絡基礎上的流,稱之為socket流。該流中既有讀取,也有寫入。

TCP用戶端:

1:建立tcp的socket服務,最好明确具體的位址和端口。

        這樣對象在建立時,就已經可以對指定ip和端口進行連接配接(三次握手)。

2:如果連接配接成功,就意味着通道建立了,socket流就已經産生了。

        通過getInputStream和getOutputStream擷取到socket流中的讀取流和寫入流即可。

3:關閉資源。

//需求:用戶端給伺服器端發送一個資料。

import java.net.*;

import java.io.*;

class  TcpClient{

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

                Socket s = new Socket("192.168.1.127",10007);

                OutputStream out = s.getOutputStream();  //擷取socket流中的輸出流對象。

                out.write("tcp示範!".getBytes());

                s.close();

        }

}

TCP服務端:

1:建立服務端socket服務,并監聽一個端口。

2:服務端為了給用戶端提供服務,擷取用戶端的内容,可以通過accept方法擷取連接配接過來的用戶端對象。

3:可以通過擷取到的socket對象中的socket流和具體的用戶端進行通訊。

4:如果通訊結束,關閉資源。注意:要先關用戶端,再關服務端。

class  TcpServer {

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

                ServerSocket ss = new ServerSocket(10007);  //建立服務端的socket服務

                Socket s = ss.accept();  //擷取用戶端對象

                String ip = s.getInetAddress().getHostAddress();

                System.out.println(ip+"......connected"); //這樣就知道是哪個ip連接配接進來了

                // 可以擷取到連接配接進來的socket對象的socket流,這樣就能和用戶端之間進行通訊了。

                InputStream in = s.getInputStream();  //擷取用戶端對象的socket讀取流

                byte[] buf = new byte[1024];

                int len = in.read(buf);

                String text = new String(buf,0,len);

                System.out.println(text);

                // 關閉資源。(注意:先關用戶端,再關服務端。)

                s.close();

                ss.close();

        }

}

注意:對于UDP和TCP,既可以定義輸出流也可以建立輸入流,具體情況根據需要建構;比如:我們需要用戶端給伺服器端發送資料,伺服器端再給用戶端回報資料;那麼就要在用戶端和伺服器端分别多加一個輸入流和輸出流!

8 上傳檔案

import java.io.*;

import java.net.Socket;

public class ClientDemo {

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

                Socket s = new Socket("localhost",10127);

                BufferedReader br  = new BufferedReader(new FileReader("e:\\hello.txt"));

                PrintWriter pw = new PrintWriter(s.getOutputStream(),true);

                String line;

                while((line = br.readLine()) != null){

                        pw.println(line);

                }

                s.shutdownOutput();  //結束标記,阻塞式方法。

                BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

                String str = bufIn.readLine();  //伺服器端回報的資料

                System.out.println(str);

                br.close();

                s.close();

        }

}

//服務端

import java.io.*;

import java.net.*;

public class ServerDemo {

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

                ServerSocket ss = new ServerSocket(10127);

                Socket s = ss.accept();

                System.out.println(s.getInetAddress().getHostAddress() +".....connected!");

                BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));

                PrintWriter pw = new PrintWriter(new FileWriter("e:\\hello2.txt"),true);  //建議列印時都用列印流

                String line = null;

                while((line = br.readLine()) != null){

                        pw.println(line);  //用write();不會自動換行和重新整理

                }

                PrintWriter out = new PrintWriter(s.getOutputStream(),true);

                out.println("上傳成功!");

                s.close();

                ss.close();

        }

}

對于網絡程式設計而言,重要的是了解其步驟,按照步驟的需要,一步步搭建根基!

用戶端和服務端需要互動,那麼就要建構相對應的流,供其輸入和輸出!

對于阻塞式方法,一定要注意,提供停止标簽!

對于PrintWriter ,記得用println而不是write;不要忘了加上true,自動重新整理!

------- android教育訓練、java教育訓練、期待與您交流! ----------