網(wǎng)絡編程是什么

網(wǎng)絡編程的本質(zhì)是兩個設備之間的數(shù)據(jù)交換,當然,在計算機網(wǎng)絡中,設備主要指計算機。數(shù)據(jù)傳遞本身沒有多大的難度,不就是把一個設備中的數(shù)據(jù)發(fā)送給兩外一個設備,然后接受另外一個設備反饋的數(shù)據(jù)。

何為Socket

網(wǎng)絡上的兩個程序通過一個雙向的通信連接實現(xiàn)數(shù)據(jù)的交換,這個連接的一端稱為一個socket。建立網(wǎng)絡通信連接至少要一對端口號(socket)。socket本質(zhì)是編程接口(API),對TCP/IP的封裝,TCP/IP也要提供可供程序員做網(wǎng)絡開發(fā)所用的接口,這就是Socket編程接口;HTTP是轎車,提供了封裝或者顯示數(shù)據(jù)的具體形式;Socket是發(fā)動機,提供了網(wǎng)絡通信的能力。

Socket編程

一個是ServerSocket,一個是Socket。服務端和客戶端之間通過Socket建立連接,之后它們就可以進行通信了。首先ServerSocket將在服務端監(jiān)聽某個端口,當發(fā)現(xiàn)客戶端有Socket來試圖連接它時,它會accept該Socket的連接請求,同時在服務端建立一個對應的Socket與之進行通信。這樣就有兩個Socket了,客戶端和服務端各一個。
對于Socket之間的通信其實很簡單,服務端往Socket的輸出流里面寫東西,客戶端就可以通過Socket的輸入流讀取對應的內(nèi)容。Socket與Socket之間是雙向連通的,所以客戶端也可以往對應的Socket輸出流里面寫東西,然后服務端對應的Socket的輸入流就可以讀出對應的內(nèi)容。
萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

下面是一個例子,客戶端讀寫和服務端讀寫

服務端代碼

public class Server {public static void main(String args[]) throws IOException {      //定義一個ServerSocket監(jiān)聽在端口8888上  
      int port = 8888; 
      int i=1; //連接計數(shù)
      //server嘗試接收其他Socket的連接請求,
      ServerSocket server = new ServerSocket(port);  
      //server的accept方法是阻塞式的 ,即等待著客戶端的請求
      Socket socket = server.accept();  
      System.out.println("連接"+i++);      //跟客戶端建立好連接,我們就可以獲取socket的InputStream,從中讀取客戶端發(fā)過來的信息。  
      Reader reader = new InputStreamReader(socket.getInputStream());    
      char chars[] = new char[64];  
      int len;  
      StringBuilder sb = new StringBuilder();  
      String temp;  
      int index;  
      while ((len=reader.read(chars)) != -1) {  
         temp = new String(chars, 0, len);  
         if ((index = temp.indexOf("eof")) != -1) { //遇到eof時就結束接收  
            sb.append(temp.substring(0, index));  
            break;  
         }  
         sb.append(temp);  
      }  
      System.out.println("from client: " + sb);  
      //讀完后寫數(shù)據(jù) 
      Writer writer = new OutputStreamWriter(socket.getOutputStream());  
      writer.write("Hello Client:我是服務端輸入數(shù)據(jù)"); 
      //釋放資源
      writer.flush();  
      writer.close(); 
      reader.close();  
      socket.close();  
      server.close(); 
   }  
}

輸出

萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

注意點

  • 服務端從Socket的InputStream中讀取數(shù)據(jù)的操作也是阻塞式的,如果從輸入流中沒有讀取到數(shù)據(jù)程序會一直在那里不動,直到客戶端往Socket的輸出流中寫入了數(shù)據(jù),或關閉了Socket的輸出流。當然,對于客戶端的Socket也是同樣如此。

  • 輸入流中讀取客戶端發(fā)送過來的數(shù)據(jù),接下來我們再往輸出流里面寫入數(shù)據(jù)給客戶端,接下來關閉對應的資源文件。而實際上上述代碼可能并不會按照我們預先設想的方式運行,因為從輸入流中讀取數(shù)據(jù)是一個阻塞式操作,在上述的while循環(huán)中當讀到數(shù)據(jù)的時候就會執(zhí)行循環(huán)體,否則就會阻塞,這樣后面的寫操作就永遠都執(zhí)行不了了,針對這種情況,通常我們都會約定一個結束標記,當客戶端發(fā)送過來的數(shù)據(jù)包含某個結束標記時就說明當前的數(shù)據(jù)已經(jīng)發(fā)送完畢了,這個時候我們就可以進行循環(huán)的跳出了。

  • 在上述代碼中,當服務端讀取到客戶端發(fā)送的結束標記,即“eof”時就會結束數(shù)據(jù)的接收,終止循環(huán),這樣后續(xù)的代碼又可以繼續(xù)進行了。

客戶端代碼

public class Client { public static void main(String args[]) throws Exception {  
      //為了簡單起見,所有的異常都直接往外拋  
      String host = "192.168.74.1";  //要連接的服務端IP地址  
      int port = 8888;   //要連接的服務端對應的監(jiān)聽端口  
      //與服務端建立連接  
      Socket client = new Socket(host, port);  
      //建立連接后就可以往服務端寫數(shù)據(jù)了  
      Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello ,我是客戶端輸入數(shù)據(jù)");
      writer.write("eof"); 
      writer.flush();//寫完后要記得flush  
      //讀取來自服務端數(shù)據(jù)
      Reader reader = new InputStreamReader(client.getInputStream());  
      char chars[] = new char[64];  
      int len;  
      StringBuffer sb = new StringBuffer();  
      String temp;  
      int index;  
      while ((len=reader.read(chars)) != -1) {  
         temp = new String(chars, 0, len);  
         if ((index = temp.indexOf("eof")) != -1) {  
            sb.append(temp.substring(0, index));  
            break;  
         }  
         sb.append(new String(chars, 0, len));  
      }  
      System.out.println("from server: " + sb);
      writer.close(); 
      reader.close();  
      client.close();  
   }  
}

輸出

萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

注意點

  • 過程:先是給服務端發(fā)送了一段數(shù)據(jù),之后讀取服務端返回來的數(shù)據(jù),跟之前的服務端一樣在讀的過程中有可能導致程序一直掛在那里,永遠跳不出while循環(huán),解決方法和服務端一樣,用一個結束標志。

  • 對于客戶端往Socket的輸出流里面寫數(shù)據(jù)傳遞給服務端要注意一點,如果寫操作之后程序不是對應著輸出流的關閉,而是進行其他阻塞式的操作(比如從輸入流里面讀數(shù)據(jù)),記住要flush一下,只有這樣服務端才能收到客戶端發(fā)送的數(shù)據(jù),否則可能會引起兩邊無限的互相等待。在稍后講到客戶端和服務端同時讀和寫的時候會說到這個問題。

http://www.cnblogs.com/favour/p/7107829.html