Java中另一個重要技術就是網絡編程了,爲了更好的學習web方向的知識,有必要對java之網絡編程好好學習,本文將圍繞網絡編程技術進行分析。
常見的網絡協議:UDP、TCP
UDP
1、 將數據源和目的封裝爲數據包,不需要建立連接
2、每個數據包大小在64K內
3、因爲面向無連接,所以不可靠(丟失數據)
4、不需要連接,速度快
常見的UDP:聊天、視頻會議、桌面共享等等。
TCP
1、 建立連接,形成傳輸數據的通道
2、在連接中進行大量數據的傳輸
3、通過三次握手完成連接,是可靠協議
4、必須建立連接,效率會相對較低
Socket
Socket就是爲網絡服務的一種機制,通信兩段都有socket,網絡通信其實就是socket間的通信。數據自練個socket間通過IO傳輸。
UDP建立連接步驟
需求:通過UDP傳輸方式,將一段文字發送出去,另一端進行接受並打印
思路:
發送端:
1、建立UDP socket服務
2、提供數據,將數據封裝到數據包中
3、通過socket服務,將數據包發送出去
4、關閉資源
接受端:
1、定義UDP socket服務,通常會監聽一個端口,方便與明確該應用程序處理的對象。
2、定義一個數據包,以便於存儲接收到數據,數據包對象中提供了更多操作接收數據處理的方法
3、通過socket服務的receive方法,將接收到的數據包存於已定義的數據包中。
4、通過數據對象特有的功能將這些不同的數據取出,並進行後續的處理
5、關閉資源
具體步驟:
發送端:
1、創建UDP服務,通過DatagramSocket對象
DatagramSocket ds =new DatagramSocket();
2、確定數據並封裝成數據包
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAdress,port)
3、通過socket服務,將已經封包的數據進行發送
ds.senf(dp)
4、關閉資源
ds.close();
接收端:
1、創建UDP socket,建立端點(指明監聽的端口)
DatagramSocket ds =new DatagramSocket(100010);
2、 定義數據包用於存儲接受進來的數據
Byte []by=new byte[1024];
DatagramPacket dp=new DatagramPacket(by,by.length);
3、通過服務的receive方法接受數據,並存於到已定義的數據包中
ds.receive(dp);
4、通過數據包的特有方法去除取出其中的數據
String s=new String(dp.getData());
5、關閉資源
ds.close();
TCP建立連接步驟
需求:建立TCP鏈接,並傳輸一段數據到服務器,服務器接收數據並打印該數據
客戶端
1、 建立服務端點,指明主機名以及端口號
Socket s=new Socket("127.0.0.1",10010);
2、讀取客戶端要傳送的數據
byte []by="TCP I am coming".getBytes();
3、通過socket輸出流將數據發給服務器
OutputStream out=s.getOutputStream();
out.wirte(by);
5、關閉資源
s.close();
服務端:
1、 建立服務端並指明監聽端口
ServerSocket ss=new ServerSocker=t(10010);
2、開啓服務,並接受數據
Scoket s=ss.accept();
3、讀取接受到的數據,並封裝成包(本例只是打印)
InputStream in=s.getInputStream();
int len=0;
byte by[]=new byte[1024];
len=in.read(by);
System.out.println(new String(by,0,len));
4、關閉資源
s.close();
案例分析:
需求:編寫一個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; import java.util.Scanner; /* * 發送端 * * */ public class UDP_Send_03 implements Runnable{ private DatagramSocket ds; UDP_Send_03(DatagramSocket ds){ this.ds=ds; } public void run() { try { ds=new DatagramSocket(); Scanner sc=new Scanner(System.in); String line; while((line=sc.nextLine())!=null){ if("886".equals(line)) break; byte by[]=line.getBytes(); DatagramPacket dp=new DatagramPacket(by,by.length,InetAddress.getByName("127.0.0.1"),10110); ds.send(dp); } } catch (SocketException e) { e.printStackTrace(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
接收端:
import java.io.IOException; import java.net.*; /* * 編寫一個聊天程序: * * 接受端 * */ public class UDP_Rec_03 implements Runnable { private DatagramSocket ds; UDP_Rec_03(DatagramSocket ds){ this.ds=ds; } public void run() { try { ds=new DatagramSocket(10110); while(true){ byte by[]=new byte[1024]; DatagramPacket dp=new DatagramPacket(by,by.length); ds.receive(dp); String data=new String(dp.getData(),0,dp.getLength()); System.out.println(data); } } catch (SocketException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } //通過多線程的方式同時開啓兩個服務,這樣就可以模擬聊天軟件的環境進行交流了 public static void main(String[] args) throws SocketException { DatagramSocket ds=new DatagramSocket(); UDP_Rec_03 rec=new UDP_Rec_03(ds); UDP_Send_03 send=new UDP_Send_03(ds); new Thread(rec).start(); new Thread(send).start(); } }
案例2:編寫一個基於TCP的程序,完成客戶端向服務器發送一段文字,服務器接收到後返回一段文字,客戶端打印反饋的信息
客戶端:
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; /* * 文件複製,需求:將客戶端的文件發到服務端,進行磁盤存儲 * */ public class CopyOfTCP_cli_04優化版 { public static void main(String[] args) throws UnknownHostException, IOException { Socket s=new Socket("127.0.0.1",10011); //獲取輸出流,將字節轉化爲字符,可以一次寫一行數據 PrintWriter pw=new PrintWriter(s.getOutputStream(),true); //讀取文件,用到了帶緩衝的Reader,可以一次讀取一行 BufferedReader br=new BufferedReader(new FileReader("E:\\a.txt")); String line=null; while((line=br.readLine())!=null){ pw.println(line); } //文件發送完成,需要發送一個結束標記 要格外注意 pw.println("over"); //或者使用s.shutdownOutput(); BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream())); while((line=in.readLine())!=null) { System.out.println("服務器說:"+line); } br.close(); in.close(); pw.close(); s.close(); } }
服務端:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class CopyOfTCP_ser_04優化版 { public static void main(String[] args) throws IOException { ServerSocket ss=new ServerSocket(10011); Socket s=ss.accept(); //接受客戶端發送的文件,用到了緩衝,並且將字節流轉化爲了字符流 BufferedReader br =new BufferedReader(new InputStreamReader(s.getInputStream())); //向文件中寫數據,用到了緩衝,可以寫一行 BufferedWriter bo=new BufferedWriter(new FileWriter("E:\\BB.txt")); //向客戶端寫數據,用到了將字節流包裝爲Printwriter 從而可以將字節轉化爲字符串處理 PrintWriter out=new PrintWriter(s.getOutputStream(),true); String line=null; while((line=br.readLine())!=null){ if("over".equals(line)) break; bo.write(line); bo.newLine(); bo.flush(); } out.println("文件收到"); out.flush(); s.close(); } }