1.Java與網(wǎng)絡(luò) * 網(wǎng)絡(luò)是java取得成功的領(lǐng)域之一 * (其他語言)數(shù)頁代碼---->(Java)一條語句 * 在java中有一個用來存儲 internet 地址的類 InetAddress 例子://獲取本機(jī)IP地址,創(chuàng)建 InetAddress 不用 new import java.net.*; public class GetLocalHost{ public static void main(String args[]){ InetAddress myIP=null; try{ myIP=InetAddress.getLocalHost(); System.out.println(myIP); }catch(Exception e){ e.printStackTrace(); } } } * java提供的網(wǎng)絡(luò)功能有3大類: a. URL 通過URL可以直接送出或讀入網(wǎng)絡(luò)上的數(shù)據(jù) b. socket 傳統(tǒng)網(wǎng)絡(luò)程序的最常用方式,可以想象為兩個程序通過網(wǎng)絡(luò)的通信信道 c. Datagram 更低級的網(wǎng)絡(luò)傳輸方式,他把數(shù)據(jù)的目的地記錄在數(shù)據(jù)包中,直接放在網(wǎng)上 2. OSI 模型和 TCP/IP 協(xié)議棧 * OSI 模型從下到上依次為: (1)物理層 規(guī)定電氣特性 (2)數(shù)據(jù)鏈路層 保證相臨兩臺計算機(jī)傳輸,用物理地址(網(wǎng)卡地址 )做網(wǎng)絡(luò)標(biāo)識,主要設(shè)備 hub (3)網(wǎng)絡(luò)層 實現(xiàn)跨網(wǎng)段傳輸,用 IP 做標(biāo)識,主要設(shè)備 router, 協(xié)議 IP (4)傳輸層 保證無差錯傳輸,協(xié)議 TCP,每個包都有syn號和效驗碼,傳輸前后的效驗碼比較,相同為正確,不同為錯誤,重傳 這一層承上啟下,出現(xiàn)了端口概念:用來區(qū)分不同的應(yīng)用,范圍 0--65535,0--1024一般不要用,是系統(tǒng)保留號 (5)會話層 如身份驗證 (6)表現(xiàn)層 (7)應(yīng)用層 Http,Ftp...... * TCP/IP 協(xié)議棧把OSI 模型合為四層 (1)鏈路層(物理層,數(shù)據(jù)鏈路層) (2)網(wǎng)絡(luò)層 IP,ICMP,ARP,RARP... (3)傳輸層 TCP,UDP... (4)應(yīng)用層 (會話層,表現(xiàn)層,應(yīng)用層) HTTP,F(xiàn)TP,TELNET,POP3,SMPT... 3.Socket * Socket 是網(wǎng)絡(luò)上運(yùn)行的程序之間雙向通信連路的最后終結(jié)點(diǎn) * IP 與 端口 的組合得出一個套接字,可以完全分辨internet上的程序 * 端口號:TCP/IP 為每種程序定義了一個端口號,當(dāng)一臺計算機(jī)上運(yùn)行不同程序時,根據(jù)端口號不同提供響應(yīng)服務(wù) 端口號不是計算機(jī)上的物理連接器,只是具有軟件意義的假想端口 * 常用端口號: ftp: 21 http: 80 telnet: 23 nntp: 119 dns: 53 pop3: 110 * 在服務(wù)器端通過指定一個用來等待連接的端口號創(chuàng)建 ServerSocket 實例 * 在客戶端通過規(guī)定一個主機(jī)和端口號創(chuàng)建 Socket 實例,連接到服務(wù)器 * 寫一個 SocketServer 的步驟: (1)創(chuàng)建一個ServerSocket對象 (2)調(diào)用 accept(),從客戶端接受一個連接請求并返回一個新 socket accept()是個阻塞方法,使 Server 啟動,等待請求,開始監(jiān)聽 (3)從接受的socket中得到輸入/輸出流 (4)根據(jù)數(shù)據(jù)類型封裝高級流(可選) (5)收發(fā)信息 (6)釋放資源 * 寫一個 socket 客戶端的步驟: (1)創(chuàng)建一個 socket,向 Server發(fā)請求得到一個連接 (2)得到輸入/輸出流 (3)根據(jù)數(shù)據(jù)類型封裝高級流(可選) (4)收發(fā)信息 (5)釋放資源 例子: //server 讀取 client 發(fā)來的數(shù)據(jù)顯示出來,直到收到 "bye" 結(jié)束 //先打開一個命令行窗口運(yùn)行 Server,然后再開一個運(yùn)行 Client import java.io.*; import java.net.*; public class Server{ public static void main(String args[]){ ServerSocket ss=null; Socket s=null; BufferedReader br=null; String read=null; try{ ss=new ServerSocket(1111); System.out.println("Server is listening on 1111......"); s=ss.accept(); br=new BufferedReader(new InputStreamReader(s.getInputStream())); while(true){ read=br.readLine(); System.out.println("read=>"+read); if(read.equals("bye")) break; } }catch(Exception e){ e.printStackTrace(); }finally{ try{ if(br!=null) br.close(); if(s!=null) s.close(); if(ss!=null) ss.close(); System.out.println("Connection is closed"); }catch(Exception e){ e.printStackTrace(); } } } //client 接收客戶輸入向server 發(fā)出,直到用戶輸入 "bye" 結(jié)束 import java.io.*; import java.net.*; public class Server{ public static void main(String args[]){ ServerSocket ss=null; Socket s=null; BufferedReader br=null; String read=null; try{ ss=new ServerSocket(1111); System.out.println("Server is listening on 1111......"); s=ss.accept(); br=new BufferedReader(new InputStreamReader(s.getInputStream())); while(true){ read=br.readLine(); System.out.println("read=>"+read); if(read.equals("bye")) break; } }catch(Exception e){ e.printStackTrace(); }finally{ try{ if(br!=null) br.close(); if(s!=null) s.close(); if(ss!=null) ss.close(); System.out.println("Connection is closed"); }catch(Exception e){ e.printStackTrace(); } } } } } * 上面的例子 client 一結(jié)束 server 也結(jié)束了,這太不實際了,下面做一個可以處理多用戶的 server 這就需要多線程,server接到一個用戶的請求就創(chuàng)建一個線程處理他 例子: //多線程處理多請求,多開幾個窗口試一下 import java.io.*; import java.net.*; public class Server{ public static void main(String args[]){ ServerSocket ss=null; Socket s=null; BufferedReader br=null; String read=null; try{ ss=new ServerSocket(1111); System.out.println("Server is listening on 1111......"); //br=new BufferedReader(new InputStreamReader(s.getInputStream())); while(true){ s=ss.accept(); Thread t=new NewServer(s); t.start(); } }catch(Exception e){ e.printStackTrace(); }finally{ try{ if(br!=null) br.close(); if(s!=null) s.close(); if(ss!=null) ss.close(); System.out.println("Connection is closed"); }catch(Exception e){ e.printStackTrace(); } } } } class NewServer extends Thread{ BufferedReader br=null; String read=null; Socket s=null; public NewServer(Socket s){ this.s=s; } public void run(){ try{ br=new BufferedReader(new InputStreamReader(s.getInputStream())); while(true){ read=br.readLine(); System.out.println(getName()+" read=>"+read); if(read.equals("bye")) break; } System.out.println(getName() +" connection is closed"); }catch(Exception e){ e.printStackTrace(); }finally{ if(br!=null) try{ br.close();} catch(Exception e){ e.printStackTrace(); } if(s!=null) try{ s.close(); } catch(Exception e){ e.printStackTrace(); } } } } * 下面來做一個雙向交互的例子,簡單的用戶名驗證,接受用戶輸入的用戶名,直到輸入“java"為止 例子: import java.io.*; import java.net.*; public class LoginServer{ public static void main(String[] args){ ServerSocket ss=null; Socket s=null; BufferedReader br=null; PrintWriter pw=null; String line=null; String username="java"; try{ ss=new ServerSocket(1111); System.out.println("Server is listening on 1111......"); s=ss.accept(); pw=new PrintWriter( new OutputStreamWriter(s.getOutputStream())); br=new BufferedReader( new InputStreamReader(s.getInputStream())); while(true){ pw.println("login:"); pw.flush(); line=br.readLine(); System.out.println(line); if(line.equals(username)) { pw.println("login sucessful"); pw.flush(); break; } pw.println("wrong name"); pw.flush(); line=null; } }catch(Exception e){ e.printStackTrace(); }finally{ if(pw!=null) try{ pw.close(); }catch(Exception e){ e.getMessage(); } if(br!=null) try{ br.close(); } catch(Exception e){ e.getMessage(); } if(s!=null) try{ s.close(); } catch(Exception e){ e.getMessage(); } if(ss!=null) try{ ss.close(); } catch(Exception e){ e.getMessage(); } } } } import java.io.*; import java.net.*; public class LoginClient{ public static void main(String[] args){ Socket s=null; BufferedReader br=null,input; PrintWriter pw=null; String line=null; String r=null,t=null; try{ s=new Socket("127.0.0.1",1111); br=new BufferedReader( new InputStreamReader(s.getInputStream())); input=new BufferedReader( new InputStreamReader(System.in)); pw=new PrintWriter( new OutputStreamWriter(s.getOutputStream())); while(true){ line= br.readLine(); System.out.print(line); r=input.readLine(); pw.println(r); pw.flush(); t=br.readLine(); System.out.println(t); if(t.equals("login sucessful")) break; line=null; } }catch(Exception e){ e.printStackTrace(); }finally{ if(pw!=null) try{ pw.close(); } catch(Exception e){ e.printStackTrace(); } if(br!=null) try{ br.close(); } catch(Exception e) { e.printStackTrace(); } if(s!=null) try{ s.close(); } catch(Exception e){ e.getMessage(); } } } } 4. UDP * UDP 為無連接協(xié)議,不可靠傳輸。DatagramSocket 和 DatagramPacket 支持 Java UDP * 數(shù)據(jù)報是一個網(wǎng)絡(luò)上發(fā)送的單獨(dú)信息,他到達(dá)的時間和內(nèi)容不能得到保證 * TCP 提供高可靠服務(wù),適用于一次傳送交換大量報文 的情況,信道上包不需要源地址和目的地址 UDP提供高效率服務(wù),適用于依次傳輸交換少量報文的情況,每個包要包含目的地址和端口號 * 數(shù)據(jù)報文的使用以包為中心:打包,拆包 * 寫 UDP Server 的步驟: (1)創(chuàng)建一個綁定端口的 datagram DatagramSocket(port) (2)準(zhǔn)備一個DatagramPacket接受客戶端的信息 DatagramPacket(buffer,len) (3)從DatagramSocket接收信息放入 DatagramPacket (4)讀取信息 * 寫 UDP Client 的步驟: (1)創(chuàng)建一個 datagram socket DatagramSocket() (2)準(zhǔn)備一個包含信息和服務(wù)器協(xié)議地址信息的datagram packet DatagramPacket(buffer,len,Serveraddr,serverport) (3)從datagram socket 把datagram packet發(fā)送到server 例子: import java.net.*; public class UDPServer{ public static void main(String[] args){ DatagramSocket ds=null; DatagramPacket dp=null; byte buf[]=new byte[1024]; try{ ds=new DatagramSocket(1111); dp=new DatagramPacket(buf,buf.length); System.out.println("begin recieve......"); ds.receive(dp); String s=new String(dp.getData(),0,dp.getLength()); System.out.println("read=>"+s); System.out.println("address:"+dp.getAddress()); System.out.println("socket address:"+dp.getSocketAddress()); System.out.println("port:"+dp.getPort()); }catch(Exception e){ e.printStackTrace(); }finally{ if( ds != null ) try{ ds.close(); } catch( Exception e ){} } } } import java.net.*; public class UdpC{ public static void main(String[] args){ DatagramSocket ds=null; DatagramPacket dp=null; byte buf[]="hello world".getBytes(); try{ ds=new DatagramSocket(); dp=new DatagramPacket(buf,buf.length,InetAddress.getLocalHost(),1111); ds.send(dp); }catch(Exception e){ e.printStackTrace(); }finally{ if(ds!=null) try{ ds.close(); }catch(Exception e){ e.printStackTrace(); } } } } 5.小結(jié) * 網(wǎng)絡(luò)上的數(shù)據(jù)傳輸是將網(wǎng)絡(luò)連接轉(zhuǎn)換成輸入輸出流 * Socket適用于面向連接的,高可靠的應(yīng)用 * Socket是由IP和端口構(gòu)成的一種網(wǎng)上通信連路的一端 * UDP適用效率高的應(yīng)用 * Socket server/client 的編程步驟 * UDP server/client 的編程步驟 |
|