------- 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教育訓練、期待與您交流! ----------