------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------
一、網(wǎng)絡參考模型
1、OSI參考模型和TCP/ip 參考模型

七層描述:
(1). 物理層:主要定義物理設備標準,如網(wǎng)線的接口類型、光纖的接口類型、各種傳輸介質的傳輸速率等。它的主要作用是傳輸比特流。
(2). 數(shù)據(jù)鏈路層:主要將從物理層接收的數(shù)據(jù)進行MAC地址(網(wǎng)卡的地址)的封裝與解封裝。這一層工作的設備是交換機,數(shù)據(jù)通過交換機來傳輸。
(3). 網(wǎng)絡層:主要將下層接收到的數(shù)據(jù)進行IP地址(例,192.168.0.1)的封裝與解封裝。這一層工作的設備是路由器。。
(4). 傳輸層:定義了一些傳輸數(shù)據(jù)的協(xié)議和端口號(WWW端口號80等),主要是將從下層接收的數(shù)據(jù)進行分段和傳輸,到達目的地址后再進行重組。
(5). 會話層:通過傳輸層(端口號:傳輸端口與接收端口)建立數(shù)據(jù)傳輸?shù)耐贰V饕谀愕南到y(tǒng)之間發(fā)起會話或者接收會話請求(設備之間需要互相認識可以是IP也可以是MAC或者是主機名)。
(6). 表示層:主要是進行對接收的數(shù)據(jù)進行解釋,加密與解密、壓縮與解壓縮等(也就是把計算機能夠識別的東西轉換成人能夠識別的東西(如圖片、聲音等)。
(7). 應用層:主要是一些終端的應用,比如說FTP(各種文件下載)、WEB(IE瀏覽)、QQ之類的(可以把它理解成我們在電腦屏幕上可以看到的東西,就是終端應用)。
注:
(1).每個網(wǎng)卡的MAC地址都是全球唯一的。
(2).路由器實現(xiàn)將數(shù)據(jù)包發(fā)送到指定的地點。
(3).應用軟件之間通信的過程就是層與層之間封包、解包的過程
(4).OSI參考模型雖然設計精細,但過于麻煩,效率不高,因此才產(chǎn)生了簡化版的TCP/IP參考模型。
2、網(wǎng)絡通信三要素:IP地址,端口號,傳輸協(xié)議。
(1)、IP地址:InetAdderss類
1.它是網(wǎng)絡中的設備標識
2.不易記憶,可用主機名表示,兩者存在映射關系
3.IPV4數(shù)量已經(jīng)不夠分配,所以產(chǎn)生了IPV6
4.本地回環(huán)地址:127.0.0.1 主機名:localhost
5.在沒有連接互聯(lián)網(wǎng)的情況,為了讓訪問本機方便,所以分配了一個默認的IP地址,也就是本地回環(huán)地址
(2)、端口號
1.用于標識進程(應用程序)的邏輯地址,不同進程的標識
2.有效端口:0~65535,其中0~1024系統(tǒng)使用或保留端口。
3.沒有程序都有端口號用來定為應用程序
(3)、傳輸協(xié)議
這是通訊的規(guī)則。常見協(xié)議有:UDP、TCP。
UDP
1.將數(shù)據(jù)以及源和目的封裝成數(shù)據(jù)包中,不需要建立連接
2.每個數(shù)據(jù)包的大小限制在64k內(nèi)
3.因無連接,所以是不可靠的協(xié)議
4.不需要建立連接,速度快
應用案例:QQ聊天、視頻聊天、對講機、FeiQ、視頻教學等在線視頻都是UDP
TCP
1.建立連接,形成傳輸數(shù)據(jù)的通道
2.在連接中進行大數(shù)據(jù)量傳輸
3.通過三次握手完成連接,是可靠協(xié)議。三次握手:第一次本方發(fā)送請求,第二次對方確認連接,第三次本方確認對方連接成功。
4.必須建立連接,效率會稍低
應用案例:FTP文件傳輸、迅雷下載、打電話
3、java.net.InetAdderss常用網(wǎng)絡方法
無構造函數(shù),只能用方法返回本類對象
1 static InetAddress getLocalHost();//返回一個InetAdderss本類對象2 static String getHostName();//返回此ip地址的主機名3 static String getHostAddress();//返回ip地址字符串4 String toString();//返回此ip地址的String表現(xiàn)形式5 static InetAddress getByName(String host);//獲取指定主機名的ip地址6 static InetAddress[] getAllByName(String host);//獲取指定主機名的全部ip地址
代碼演示:
1 import java.net.*; 2 class InetAddressDemo 3 { 4 public static void main(String[] args) throws Exception 5 { 6 InetAddress ia= InetAddress.getLocalHost();//返回InetAddress本來對象 7 String name=ia.getHostName();//獲取IP地址的主機名 8 String ip=ia.getHostAddress();//獲取本地ip地址 9 System.out.二、UDP協(xié)議-發(fā)送端和接收端
Socket:套接字,通信的端點。就是為網(wǎng)絡服務提供的一種機制,通信的兩端都有Socket,網(wǎng)絡通信其實就是Socket間的通信,數(shù)據(jù)在兩個Socket間通過IO傳輸。
1、DatagramSocket和DatagramPacket對象
(1)、DatagramSocket類常用方法
此類表示用來發(fā)送和接收數(shù)據(jù)報包的套接字。
1、構造方法
1 new DatagramSocket();//構造數(shù)據(jù)報套接字并綁定到本地主機任何端口上,發(fā)送端2 new DatagramSocket(int port);//創(chuàng)建數(shù)據(jù)報套接字并綁定到本地主機上的指定端口,接收端
2、一般方法
1 void connect(InetAddress address,int port);//將套接字連接到此套接字的遠程地址上2 void send(DatagramPacket p);//從此套接字發(fā)送數(shù)據(jù)包3 void receive(DatagramPacket p);//從此套接字接收數(shù)據(jù)包4 InetAddress getInetAddress();//返回此套接字連接的地址5 int getPort();//返回此套接字的端口
(2)、DatagramPacket類常用方法
此類表示數(shù)據(jù)報包
1、構造方法
1 new DatagramPacket(byte[] buf,int length,InetAddress address,int port);//構造數(shù)據(jù)報包,用來將長度為length的包發(fā)送到指定主機上的指定端口號2 new DatatgramPacket(byte[] buf,int length);//構造 DatagramPacket,用來接收長度為 length 的數(shù)據(jù)包
2、一般方法
1 InetAddress getAddress();//獲取某臺主機的ip地址2 byte[] getData();//獲取數(shù)據(jù)緩沖區(qū)的內(nèi)容3 int getLength();//獲取將要發(fā)送或者接收到的數(shù)據(jù)的長度4 int getPort();//獲取某臺主機的端口號
2、UDP傳輸發(fā)送和獲取數(shù)據(jù)的步驟
UDP發(fā)送端步驟:
1)、建立UDPSocket服務
2)、提供數(shù)據(jù),并將數(shù)據(jù)封裝到數(shù)據(jù)包中
3)、通過Socket服務的send方法,將數(shù)據(jù)包發(fā)送出去
4)、關閉資源
UDP接收端步驟:
1)、定義UDPSocket服務。通常會監(jiān)聽一個端口號。其實就是給這個接收網(wǎng)絡應用程序定義數(shù)字標識,方便于明確哪些數(shù)據(jù)過來哪個應該程序可以處理
2)、定義一個數(shù)據(jù)包。因為要存儲接收到的字節(jié)數(shù)據(jù)。因為數(shù)據(jù)包對象中有更多功能可以提取字節(jié)數(shù)據(jù)中的不同數(shù)據(jù)信息
3)、通過Sockt服務的receive方法將接收到的數(shù)據(jù)存入已經(jīng)定義好的數(shù)據(jù)包中
4)、通過數(shù)據(jù)包對象的特有功能,將這些不同的數(shù)據(jù)取出,打印在控制臺上
5)、關閉資源
需求:聊天程序(雙窗口模式)代碼演示:
1 import java.io.*; 2 import java.net.*; 3 class UDPSend 4 { 5 public static void main(String[] args) 6 { 7 DatagramSocket ds=null; 8 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 9 try 10 {11 //1,創(chuàng)建udp服務。通過DatagramSocket對象。12 ds=new DatagramSocket();13 String line=null;14 while ((line=br.readLine())!=null)15 {16 byte[] buf=line.getBytes();17 //2,確定數(shù)據(jù),并封裝成數(shù)據(jù)包。DatagramPacket(byte[] buf,int length, InetAddress address, int port) 20 DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.104"),55128);23 //3,通過socket服務,將已有的數(shù)據(jù)包發(fā)送出去。通過send方法 。26 ds.send(dp);27 if("over".equals(line))28 break;29 }30 31 }32 catch (Exception e)33 {34 System.out.println(e);35 }36 finally37 {38 if(ds!=null)39 try40 {41 //4,關閉資源。42 ds.close();43 }44 catch (Exception e)45 {46 System.out.println("發(fā)送端關閉失敗");47 }48 }49 }50 }51 class UDPReceive52 {53 public static void main(String[] args){54 DatagramSocket ds=null;55 DatagramPacket dp=null;56 try{57 //1,創(chuàng)建udp socket,建立端點。58 ds=new DatagramSocket(55128); 59 while (true)60 { //2,定義數(shù)據(jù)包。用于存儲數(shù)據(jù)。 61 byte[] buf=new byte[1024];62 dp=new DatagramPacket(buf,buf.length);63 //3,通過服務的receive方法將收到數(shù)據(jù)存入數(shù)據(jù)包中。64 ds.receive(dp);//阻塞式方法。65 //4,通過數(shù)據(jù)包的方法獲取其中的數(shù)據(jù)。66 String ip=dp.getAddress().getHostAddress();67 String data=new String(dp.getData(),0,dp.getLength());68 System.out.println(ip+"......"+data);69 if(data.equals("over"))70 break;71 }72 73 }74 catch (Exception e)75 {76 System.out.println(e);77 }78 finally79 {80 if(ds!=null)81 try82 {83 //5,關閉資源84 ds.close();85 }86 catch (Exception e)87 {88 System.out.println("接收端關閉失敗");89 }90 }91 }92 }需求:聊天程序(單窗口模式-群聊)代碼演示:
收數(shù)據(jù)的部分,和發(fā)數(shù)據(jù)的這兩部分需要同時執(zhí)行。那就需要用到多線程技術。一個線程控制收,一個線程控制發(fā)。因為收和發(fā)動作是不一致的,所以要定義兩個run方法。而且這兩個方法要封裝到不同的類中。
1 import java.io.*; 2 import java.net.*; 3 class UDPSend implements Runnable 4 { 5 private DatagramSocket ds; 6 UDPSend(DatagramSocket ds){ 7 this.ds=ds; 8 } 9 public void run(){10 try11 {12 //讀取鍵盤錄入13 BufferedReader br=new BufferedReader(new InputStreamReader(System.in));14 String line=null;15 while ((line=br.readLine())!=null)16 {17 byte[] buf=line.getBytes();18 //定義數(shù)據(jù)包,用來存放數(shù)據(jù)19 DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.104"),5556);20 //通過send方法把數(shù)據(jù)發(fā)送給接收端21 ds.send(dp);22 if("over".equals(line))23 break;24 }25 ds.close();26 }27 catch (Exception e)28 {29 System.out.println("發(fā)送失敗");30 }31 }32 }33 class UDPReceive implements Runnable34 {35 private DatagramSocket ds;36 UDPReceive(DatagramSocket ds){37 this.ds=ds;38 }39 public void run(){//復寫run方法40 try41 {42 while (true)43 {44 byte[] buf=new byte[1024];45 //定義數(shù)據(jù)包用來接收發(fā)送端發(fā)過來的數(shù)據(jù)信息46 DatagramPacket dp=new DatagramPacket(buf,buf.length);47 //接收數(shù)據(jù)48 ds.receive(dp);49 //對接收過來的數(shù)據(jù)進行ip地址等信息的解析50 String ip=dp.getAddress().getHostAddress();51 String data=new String(dp.getData(),0,dp.getLength());52 System.out.println(ip+"......."+data);53 if("over".equals(data))54 break;55 }56 ds.close(); 57 }58 catch (Exception e)59 {60 System.out.println("接收端接受失敗");61 }62 }63 }64 class ChatRoom65 {66 public static void main(String[] args)throws Exception{67 //定義兩個DatagramSocket服務68 DatagramSocket send=new DatagramSocket();69 DatagramSocket receive=new DatagramSocket(5556);70 //開啟兩個線程71 new Thread(new UDPSend(send)).start();72 new Thread(new UDPReceive(receive)).start();73 }74 }三、TCP協(xié)議-客戶端和服務端
客戶端(Client)首先與服務端(Server)建立連接,形成通道(其實就是IO流),然后,數(shù)據(jù)就可以在通道之間進行傳輸,并且單個Server端可以同時與多個Client端建立連接。Socket和ServerSocket,建立客戶端和服務器端。建立連接后,通過Socket中的IO流進行數(shù)據(jù)的傳輸。關閉socket。同樣,客戶端與服務器端是兩個獨立的應用程序。
TCP客戶端
客戶端需要明確服務器的ip地址以及端口,這樣才可以去試著建立連接,如果連接失敗,會出現(xiàn)異常。連接成功,說明客戶端與服務端建立了通道,那么通過IO流就可以進行數(shù)據(jù)的傳輸,而Socket對象已經(jīng)提供了輸入流和輸出流對象,通過getInputStream()和getOutputStream()獲取即可與服務端通訊。結束后關閉Socket。客戶端,通過查閱socket對象,發(fā)現(xiàn)在該對象建立時,就可以去連接指定主機。因為tcp是面向連接的。所以在建立socket服務時,就要有服務端存在,并連接成功。形成通路后,在該通道進行數(shù)據(jù)的傳輸。
TCP服務端
服務端需要明確它要處理的數(shù)據(jù)是從哪個端口進入的。當有客戶端訪問時,要明確是哪個客戶端,可通過accept()獲取已連接的客戶端對象,并通過該對象與客戶端通過IO流進行數(shù)據(jù)傳輸。當該客戶端訪問結束,關閉該客戶端。1,建立服務端的socket服務。ServerSocket();并監(jiān)聽一個端口。2,獲取連接過來的客戶端對象。通過ServerSokcet的 accept方法。沒有連接就會等,所以這個方法阻塞式的。3,客戶端如果發(fā)過來數(shù)據(jù),那么服務端要使用對應的客戶端對象,并獲取到該客戶端對象的讀取流來讀取發(fā)過來的數(shù)據(jù)。并打印在控制臺。4,關閉服務端。(可選)。
TCP協(xié)議因為是面向連接的。所以傳輸數(shù)據(jù)必須先開服務端,再開客戶端。否則,客戶端根本連接不上服務端。

1、Socket類中常用方法
(1)、構造方法
1 new Socket();2 new Socket(InetAddress address,int port);//創(chuàng)建一個流套接字并將其連接到指定 IP 地址的指定端口號。3 new Socket(String host,int port);// 創(chuàng)建一個流套接字并將其連接到指定主機上的指定端口號。
(2)、成員方法
1 void bind(SocketAddress bindpoint);//將套接字綁定到本地地址。 2 void connect(SocketAddress endpoint);//將此套接字連接到服務器。 3 InetAddress getInetAddress();//返回套接字連接的地址。4 InputStream getInputStream();//返回此套接字的輸入流。5 OutputStream getOutputStream();// 返回此套接字的輸出流。 6 int getPort();// 返回此套接字連接到的遠程端口 7 void shutdownInput();// 此套接字的輸入流置于“流的末尾”。 8 void shutdownOutput();// 禁用此套接字的輸出流
2、ServerSocket類中常用方法
(1)、構造方法
1 new ServerSocket();//創(chuàng)建非綁定服務器套接字。2 new ServerSocket(int port);//創(chuàng)建綁定到特定端口的服務器套接字。
(2)、成員方法
1 Socket accept();//偵聽并接受到此套接字的連接。 2 InetAddress getInetAddress();// 返回此服務器套接字的本地地址。
需求:TCP協(xié)議-服務端和客戶端交互代碼演示:
1 import java.io.*; 2 import java.net.*; 3 class TCPClient 4 { 5 public static void main(String[] args) throws Exception 6 { 7 //創(chuàng)建客戶端的socket服務。指定目的主機和端口 8 Socket s=new Socket("192.168.1.100",5544); 9 //為了發(fā)送數(shù)據(jù),應該獲取socket流中的輸出流。10 OutputStream out=s.getOutputStream();11 out.write("TCP,我來了!".getBytes());12 InputStream in=s.getInputStream();13 byte[] buf=new byte[1024];14 int len=in.read(buf);15 System.out.println(new String(buf,0,len));16 s.close();17 }18 }19 class TCPServer20 {21 public static void main(String[] args)throws Exception{22 //建立服務端socket服務。并監(jiān)聽一個端口。23 ServerSocket ss=new ServerSocket(5544);24 //通過accept方法獲取連接過來的客戶端對象。25 Socket s=ss.accept();26 //獲取ip地址27 String ip=s.getInetAddress().getHostAddress();28 System.out.println(ip+".....connnect");29 //獲取客戶端發(fā)送過來的數(shù)據(jù),那么要使用客戶端對象的讀取流來讀取數(shù)據(jù)。30 InputStream in=s.getInputStream();31 byte[] buf=new byte[1024];32 int len=in.read(buf);33 System.out.println(new String(buf,0,len));34 35 OutputStream out=s.getOutputStream();36 out.write("收到".getBytes());37 ss.close();38 //關閉客戶端.39 s.close();40 }41 }需求:建立一個文本轉換服務器。
客戶端給服務端發(fā)送文本,服務單會將文本轉成大寫在返回給客戶端。而且客戶度可以不斷的進行文本轉換。當客戶端輸入over時,轉換結束。
客戶端:
既然是操作設備上的數(shù)據(jù),那么就可以使用io技術,并按照io的操作規(guī)律來思考。
源:鍵盤錄入。
目的:網(wǎng)絡設備,網(wǎng)絡輸出流。
而且操作的是文本數(shù)據(jù)。可以選擇字符流。
步驟
1,建立服務。
2,獲取鍵盤錄入。
3,將數(shù)據(jù)發(fā)給服務端。
4,后去服務端返回的大寫數(shù)據(jù)。
5,結束,關資源。
都是文本數(shù)據(jù),可以使用字符流進行操作,同時提高效率,加入緩沖。
服務端:
源:socket讀取流。
目的:socket輸出流。
都是文本,裝飾。
1 import java.io.*; 2 import java.net.*; 3 class TransClient 4 { 5 public static void main(String[] args) throws Exception 6 { 7 Socket s=new Socket("192.168.1.100",7788); 8 //定義讀取鍵盤數(shù)據(jù)的流對象。 9 BufferedReader br=new BufferedReader(new InputStreamReader(System.in));10 //定義目的,將數(shù)據(jù)寫入到socket輸出流。發(fā)給服務端。11 PrintWriter out=new PrintWriter(s.getOutputStream(),true);12 //定義一個socket讀取流,讀取服務端返回的大寫信息。13 BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));14 String line=null;15 while ((line=br.readLine())!=null)16 {17 out.println(line);18 if("over".equals(line))19 break;20 String info=in.readLine(); 21 System.out.println("info="+info);22 }23 s.close();24 25 }26 }27 class TransServer28 {29 public static void main(String[] args)throws Exception{30 ServerSocket ss=new ServerSocket(7788); 31 Socket s=ss.accept();32 System.out.println(s.getInetAddress().getHostAddress()+".....connect");33 //讀取socket讀取流中的數(shù)據(jù)。34 BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));35 //目的。socket輸出流。將大寫數(shù)據(jù)寫入到socket輸出流,并發(fā)送給客戶端。36 PrintWriter out=new PrintWriter(s.getOutputStream(),true);37 String line=null;38 while ((line=in.readLine())!=null)39 {40 System.out.println(line);41 out.println(line.toUpperCase());42 if("over".equals(line))43 break;44 }45 s.close();46 ss.close();47 }48 }需求:TCP協(xié)議上傳文本文件
1 import java.io.*; 2 import java.net.*; 3 class TCPClient 4 { 5 public static void main(String[] args)throws Exception 6 { 7 Socket s=new Socket("192.168.1.100",9999); 8 BufferedReader br=new BufferedReader(new FileReader("TCPDemo.java")); 9 PrintWriter out=new PrintWriter(s.getOutputStream(),true);10 BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));11 String line=null;12 while ((line=br.readLine())!=null)13 {14 out.println(line);15 }16 s.shutdownOutput();//關閉客戶端的輸出流。相當于給流中加入一個結束標記-1.17 System.out.println(in.readLine());18 s.close();19 br.close();20 }21 }22 class TCPServer23 {24 public static void main(String[] args)throws Exception{25 ServerSocket ss=new ServerSocket(9999);26 Socket s=ss.accept();27 System.out.println(s.getInetAddress().getHostAddress()+"....connect");28 BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));29 PrintWriter pw=new PrintWriter(new FileWriter("E://TCPDemo.java"),true);30 PrintWriter out=new PrintWriter(s.getOutputStream(),true);31 String line=null;32 while ((line=in.readLine())!=null)33 {34 pw.println(line);35 }36 out.println("上傳成功");37 s.close();38 ss.close();39 pw.close();40 }41 }需求:TCP客戶端并發(fā)上傳圖片代碼演示:
服務端最好就是將每個客戶端封裝到一個單獨的線程中,這樣,就可以同時處理多個客戶端請求。
如何定義線程呢?
只要明確了每一個客戶端要在服務端執(zhí)行的代碼即可。將該代碼存入run方法中。
1 import java.io.*; 2 import java.net.*; 3 class PicClient 4 { 5 public static void main(String[] args)throws Exception{ 6 File file=new File(args[0]); 7 if(!(file.exists()&& file.isFile())){ 8 System.out.println("請上傳圖片"); 9 return;10 }11 if(!(file.getName().endsWith(".jpg"))){12 System.out.println("上傳格式錯誤");13 return;14 }15 if(file.length()>=1024*1024*4){16 System.out.println("文件過大,請切割后上傳");17 return;18 }19 20 Socket s=new Socket("192.168.1.104",5555);21 FileInputStream fis=new FileInputStream(file);22 OutputStream out=s.getOutputStream();23 byte[] buf=new byte[1024];24 int len=0;25 while ((len=fis.read(buf))!=-1)26 {27 out.write(buf,0,len);28 }29 s.shutdownOutput();//告訴服務端數(shù)據(jù)已寫完30 InputStream in=s.getInputStream();31 byte[] bufIn=new byte[1024];32 int num=in.read(bufIn);33 System.out.println(new String(bufIn,0,num));34 s.close();35 fis.close();36 }37 }38 class PicThread implements Runnable39 {40 private Socket s;41 PicThread(Socket s){42 this.s=s;43 }44 public void run(){45 String ip=s.getInetAddress().getHostAddress();46 System.out.println(ip+".....connect");47 try48 {49 int count=1;50 //創(chuàng)建file對象51 File file=new File("E://"+ip+"("+count+")"+".jpg");52 //如果file文件存在則count++,直到不存在為止53 while(file.exists())54 file=new File("E://"+ip+"("+(count++)+")"+".jpg");55 InputStream in=s.getInputStream();56 FileOutputStream fos=new FileOutputStream(file);57 byte[] buf=new byte[1024];58 int len=0;59 while ((len=in.read(buf))!=-1)60 {61 fos.write(buf,0,len);62 }63 OutputStream out=s.getOutputStream();64 out.write("上傳成功".getBytes());65 s.close(); 66 }67 catch (Exception e)68 {69 System.out.println(ip+"連接成功");70 }71 }72 }73 class PicServer74 {75 public static void main(String[] args)throws Exception{76 ServerSocket ss=new ServerSocket(5555);77 while (true)78 {79 Socket s=ss.accept();80 new Thread(new PicThread(s)).start();81 }82 }83 }需求:客戶端通過鍵盤錄入用戶名。服務端對這個用戶名進行校驗。最多就登錄三次。
如果該用戶存在,在服務端顯示xxx,已登陸。
并在客戶端顯示 xxx,歡迎光臨。
如果該用戶不存在,在服務端顯示xxx,嘗試登陸。
并在客戶端顯示 xxx,該用戶不存在。
1 import java.io.*; 2 import java.net.*; 3 class LoginClient 4 { 5 public static void main(String[] args)throws Exception 6 { 7 Socket s=new Socket("192.168.1.104",6666); 8 BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 9 //讀取socket流中的讀取流10 BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));11 //socket流中的輸出流12 PrintWriter out=new PrintWriter(s.getOutputStream(),true); 13 //循環(huán)3次輸入,如果輸入為null,直接停止輸入14 for (int x=0;x<3 ;x++ )15 {16 String name=br.readLine();17 if(name==null)18 break;19 out.println(name);20 String info=in.readLine();21 System.out.println(info);22 //如果獲取到流中有“歡迎“字樣,說明對方已經(jīng)登錄,這時候即使輸入的不到3次,也停止輸入,因為已經(jīng)登錄成功了。23 if(info.contains("歡迎")){ 24 break;25 }26 }27 s.close();28 }29 }30 class LoginThread implements Runnable31 {32 private Socket s;33 LoginThread(Socket s){34 this.s=s;35 }36 public void run(){37 String ip=s.getInetAddress().getHostAddress();38 System.out.println(ip+".....connect");39 try40 { 41 for (int x=0;x<3 ;x++ )42 {43 //讀取socket流中的輸入流44 BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));45 String name=in.readLine();46 if(name==null)47 break;48 //讀取文件49 BufferedReader br=new BufferedReader(new FileReader("Userinfo.txt"));50 //socket流輸出流51 PrintWriter out=new PrintWriter(s.getOutputStream(),true); 52 //定義一個標記, 從socket輸入流中的鍵盤數(shù)據(jù)判斷user.txt中是否有name符合,如果有標記為真,跳出while循環(huán)。53 boolean flag=false;54 String line=null;55 while ((line=br.readLine())!=null)56 {57 //判斷Userinfo.txt和name是否有相同的58 if(line.equals(name)){59 flag=true;60 break;61 }62 }63 if(flag){64 System.out.println(name+",已登陸");65 out.println(name+",歡迎光臨");66 break;67 }68 else{69 System.out.println(name+",嘗試登陸");70 out.println(name+",該用戶不存在");71 }72 }73 s.close();74 }75 catch (Exception e)76 {77 System.out.println(ip+"連接失敗");78 }79 }80 }81 class LoginServer82 {83 public static void main(String[] args)throws Exception{84 ServerSocket ss=new ServerSocket(6666);85 while (true)86 {87 Socket s=ss.accept();88 new Thread(new LoginThread(s)).start();89 }90 }91 }四、客戶端和服務器端原理
最常見的客戶端:瀏覽器,IE/Chrome。
最常見的服務端:服務器,Tomcat。
1. 自定義服務端
使用已有的客戶端IE,了解一下客戶端向服務端發(fā)了什么請求
1 import java.io.*; 2 import java.net.*; 3 class ServerDemo 4 { 5 public static void main(String[] args) throws Exception 6 { 7 ServerSocket ss=new ServerSocket(8080); 8 Socket s=ss.accept(); 9 PrintWriter out=new PrintWriter(s.getOutputStream(),true);10 out.println("<font size='5' color='red'>客戶端你好 </font>");11 //獲取到服務器向客戶端發(fā)送的數(shù)據(jù)12 InputStream is=s.getInputStream(); 13 byte[] buf=new byte[1024]; 14 int len=is.read(buf);15 System.out.println(new String(buf,0,len));16 ss.close();17 s.close(); 18 }19 }20 /*這是服務器向客戶端發(fā)送的數(shù)據(jù)21 (請求行,請求方式:GET;請求的資源路徑:/;HTTP協(xié)議版本:1.1。)22 GET / HTTP/1.123 (請求消息頭,屬性名:屬性值)24 Host: 127.0.0.1:808025 Connection: keep-alive26 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=027 .828 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like29 Gecko) Chrome/42.0.2311.152 Safari/537.3630 Accept-Encoding: gzip, deflate, sdch31 Accept-Language: zh-CN,zh;q=0.832 */HTTP是一個客戶端和服務端請求和應答的標準,客戶端按照HTTP的標準發(fā)送數(shù)據(jù)到服務端,服務端按照HTTP的標準解析收到的數(shù)據(jù)。很多軟件都內(nèi)置了此標準。
2. 模擬一個瀏覽器獲取信息。
1 import java.net.*; 2 import java.io.*; 3 public class MyBrowser 4 { 5 public static void main(String[] args) throws IOException { 6 Socket s = new Socket("192.168.1.100",8080); 7 //模擬瀏覽器,向tomcat服務端發(fā)送符合http協(xié)議的請求消息。 8 PrintWriter out = new PrintWriter(s.getOutputStream(),true); 9 out.println("GET /myweb/1.html HTTP/1.1");10 out.println("Accept: */*");11 out.println("Host: 192.168.1.100:8080");12 out.println("Connection: close");13 out.println();14 out.println();15 InputStream in = s.getInputStream();16 byte[] buf = new byte[1024];17 int len = in.read(buf);18 String str = new String(buf,0,len);19 System.out.println(str);20 s.close();21 }22 }HTTP服務端發(fā)回的應答消息:
(應答行,HTTP的協(xié)議版本:1.1;應答狀態(tài)碼:200;應答狀態(tài)描述信息:OK。)
HTTP/1.1 200 OK
(應答消息屬性信息,屬性名:屬性值。)
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"211-1433908112666"
Last-Modified: Wed, 10 Jun 2015 03:48:32 GMT
Content-Type: text/html
Content-Length: 211
Date: Wed, 10 Jun 2015 03:52:16 GMT
Connection: close
應答行中屬性名及屬性值的具體含義,初學者不用追究,在JavaWeb課程中將會深入講解。
五、URL和URLConnection類
URI:統(tǒng)一資源標示符。
URL:統(tǒng)一資源定位符,也就是說根據(jù)URL能夠定位到網(wǎng)絡上的某個資源,它是指向互聯(lián)網(wǎng)“資源”的指針。每個URL都是URI,但不一定每個URI都是URL。這是因為URI還包括一個子類,即統(tǒng)一資源名稱(URN),它命名資源但不指定如何定位資源。
URL類可以建立到遠程對象的連接,也就是說這里面封裝了socket,可以直接獲取socket流。
1、常用方法
1 String getFile();//獲取此 URL 的文件名。 2 String getHost();//獲取此 URL 的主機名(如果適用)。 3 String getPath();//獲取此 URL 的路徑部分。 4 int getPort();//獲取此 URL 的端口號。 5 String getProtocol();//獲取此 URL 的協(xié)議名稱。 6 String getQuery();//獲取此 URL 的查詢部分。7 URLConnection openConnection();//返回一個 URLConnection 對象,它表示到 URL 所引用的遠程對象的連接。8 InputStream openStream();//打開到此 URL 的連接并返回一個用于從該連接讀入的 InputStream。此方法是下面方法的縮寫: 9 openConnection().getInputStream()。
代碼演示:
1 import java.net.*; 2 import java.io.*; 3 class URLConnectionDemo 4 { 5 public static void main(String[] args) throws Exception 6 { 7 URL url = new URL("http://192.168.1.254:8080/myweb/demo.html"); 8 9 URLConnection conn = url.openConnection();10 System.out.println(conn);11 12 InputStream in = conn.getInputStream();13 14 byte[] buf = new byte[1024];15 16 int len = in.read(buf);17 18 System.out.println(new String(buf,0,len));之所以運行結果中響應頭不見了,只能看到主體數(shù)據(jù)的原因在于:URLConnection對象已經(jīng)把響應頭給解析了。
六、域名解析
在瀏覽器中輸入新浪的域名,DNS解析域名成IP,然后計算機再通過獲取到的IP訪問新浪服務器。
域名解析,最先走是本地的hosts(C:/WINDOWS/system32/drivers/etc/hosts)文件,解析失敗了,才去訪問DNS服務器解析、獲取IP地址。
可以通過hosts文件可以屏蔽游戲網(wǎng)站內(nèi)容彈出。

|
新聞熱點
疑難解答