java 網絡編程

    和網絡編程有關的基本API位於java.net包中,該包中包含了基本的網絡編程實現,該包是網絡編程的基礎。該包中既包含基礎的網絡編程類,也包含封裝後的專門處理WEB相關的處理類。在本章中,將只介紹基礎的網絡編程類。html

         首先來介紹一個基礎的網絡類——InetAddress類。該類的功能是表明一個IP地址,而且將IP地址和域名相關的操做方法包含在該類的內部。java

         關於該類的使用,下面經過一個基礎的代碼示例演示該類的使用,代碼以下:android

import java.net.*;
/**
 * 演示InetAddress類的基本使用
 */
public class InetAddressDemo {
         public static void main(String[] args) {
                   try{
                            //使用域名建立對象
                            InetAddress inet1 = InetAddress.getByName("www.163.com");
                            System.out.println(inet1);
                            //使用IP建立對象
                            InetAddress inet2 = InetAddress.getByName("127.0.0.1");
                            System.out.println(inet2);
                            //得到本機地址對象
                            InetAddress inet3 = InetAddress.getLocalHost();
                            System.out.println(inet3);
                            //得到對象中存儲的域名
                            String host = inet3.getHostName();
                            System.out.println("域名:" + host);
                            //得到對象中存儲的IP
                            String ip = inet3.getHostAddress();
                            System.out.println("IP:" + ip);
                   }catch(Exception e){}
         }
}

運行結果:web

www.163.com/60.174.243.159
/127.0.0.1
ifly-XXX/10.1.xxx.xxx
域名:ifly-XXX
IP:10.1.xxx.xxx


Socket編程編程

Java爲TCP協議提供了兩個類,分別在客戶端編程和服務器端編程中使用它們。在應用程序開始通訊以前,須要先建立一個鏈接,由客戶端程序發起;而服務器端的程序須要一直監聽着主機的特定端口號,等待客戶端的鏈接。在客戶端中咱們只須要使用Socket實例,而服務端要同時處理ServerSocket實例和Socket實例;兩者而且都使用OutputStreamInpuStream來發送和接收數據。api

服務器端:瀏覽器

                 ① 建立ServerSocket對象,綁定監聽端口
                 ② 經過accept()方法監聽客戶端請求          //沒有客戶端請求時,accept()會阻塞,不會繼續往下運行
                 ③ 鏈接創建後,經過輸入流讀取客戶端發送的請求信息
                 ④ 經過輸出流向客戶端發送鄉音信息
                 ⑤ 關閉相關資源
客戶端:
                 ① 建立Socket對象,指明須要鏈接的服務器的地址和端口號
                 ② 鏈接創建後,經過輸出流想服務器端發送請求信息
                 ③ 經過輸入流獲取服務器響應的信息
                 ④ 關閉響應資源
   注:客戶端不須要設定哪一個端口和服務器端進行通訊,可是服務器端須要設定監聽的端口號。

   學習一種知識最好的方式就是使用它,經過前面的筆記,咱們已經知道如何獲取主機的地址信息,如今咱們經過一個簡單的程序來初步學習傳輸層使用了TCP協議的Socket編程。緩存

1.TCP服務器端

  在Socket編程中,服務器端遠比客戶端要複雜得多。服務器端的工做就是創建一個通訊終端,被動的等待客戶端的鏈接。下面這個服務器端程序的示例的做用是:監遵從控制檯輸入獲取的端口號,而且將客戶端發送過來的消息,再發送回去。服務器

import java.net.*;
import java.text.MessageFormat;
import java.io.*;

public class TCPEchoServer {

    private static final int BUFSIZE = 32;

    /**
     * @param args
   */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
     // 從控制檯獲取須要監聽的端口號
        if (args.length != 1)
            throw new IllegalArgumentException("Parameter(s):<Port>");
        // 獲取端口號
        int servPort = Integer.parseInt(args[0]);
        // 實例化一個ServerSocket對象實例
        ServerSocket servSocket = new ServerSocket(servPort);
        System.out.println(MessageFormat.format("開始啓動監聽,端口號:{0}", args[0]));

        // 初始接收數據的總字節數
        int recvMsgSize;
        // 接收數據的緩衝區
        byte[] receiveBuf = new byte[BUFSIZE];

        // 循環迭代,監聽端口號,處理新的鏈接請求
        while (true) {
            // 阻塞等待,每接收到一個請求就建立一個新的鏈接實例
            Socket clntSocket = servSocket.accept();
            // 獲取鏈接的客戶端的 SocketAddress
            SocketAddress clientAddress = clntSocket.getRemoteSocketAddress();
            // 打印輸出鏈接客戶端地址信息
            System.out.println("Handling client at" + clientAddress);
            // 從客戶端接收數據的對象
            InputStream in = clntSocket.getInputStream();
            // 向客戶端發送數據的對象
            OutputStream out = clntSocket.getOutputStream();
            // 讀取客戶端發送的數據後,再發送到客戶端
            while ((recvMsgSize = in.read(receiveBuf)) != -1) {
                out.write(receiveBuf, 0, recvMsgSize);
            }
            // 客戶端關閉鏈接時,關閉鏈接
            System.out.println(" 客戶端關閉鏈接");
            clntSocket.close();
        }
    }
}
      while ((recvMsgSize = in.read(receiveBuf)) != -1) {
                out.write(receiveBuf, 0, recvMsgSize);
            }

上述代碼中,服務端能夠屢次接受  客戶端的消息,並將消息回傳給客戶端,直到客戶端關閉socket時,循環才結束。網絡

2.TCP客戶端

  在Socket編程中,首先客戶端須要向服務器端發送,而後被動的等待服務器端的響應。下面的示例中:咱們向服務器端發送信息,等待服務器端發送的消息,並打印顯示出來。 

import java.io.*;
import java.net.Socket;
import java.net.SocketException;

public class TCPEchoClient {

    /**
     * @param args
     * @throws IOException
    */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        // 判斷從控制檯接受的參數是否正確
        if ((args.length < 2) || (args.length > 3))
            throw new IllegalArgumentException("Parameter(s):<Server><Word>[<Port>]]");
        // 獲取服務器地址
        String server = args[0];
        // 獲取須要發送的信息
        byte[] data = args[1].getBytes();
        // 若是有三個從參數那麼就獲取發送信息的端口號,默認端口號爲8099
        int servPort = (args.length == 3) ? Integer.parseInt(args[2]) : 8099;
        // 根據服務器地址和端口號實例化一個Socket實例
        Socket socket = new Socket(server, servPort);
        System.out.println("Connected to server...sending echo string");
        // 返回此套接字的輸入流,即從服務器接受的數據對象
        InputStream in = socket.getInputStream();
        // 返回此套接字的輸出流,即向服務器發送的數據對象
        OutputStream out = socket.getOutputStream();
        // 向服務器發送從控制檯接收的數據
        out.write(data);
        // 接收數據的計數器,將寫入數據的初始偏移量
        int totalBytesRcvd = 0;
        // 初始化接收數據的總字節數
        int bytesRcvd;
        while (totalBytesRcvd < data.length) {
            // 服務器關閉鏈接,則返回 -1,read方法返回接收數據的總字節數
            if ((bytesRcvd = in.read(data, totalBytesRcvd, data.length
                    - totalBytesRcvd)) == -1)
                throw new SocketException("與服務器的鏈接已關閉");
            else 
                 System.out.println("client received data from client");
            totalBytesRcvd += bytesRcvd;          
        }
        // 打印服務器發送來的數據
        System.out.println("Received:" + new String(data));
        // 關閉鏈接
        socket.close();

    }
}

運行服務端程序: 對8099端口進行監聽:

運行客戶端程序: 向服務器端發送消息(默認端口號爲8099),同時服務器發回消息

服務器端變成:監聽到 ip地址爲 10.1.206.238:59918 的socket發送消息。

 HTTP協議

  HTTP是hypertext transfer protocol(超文本傳輸協議)的簡寫,它是TCP/IP協議的一個應用層協議,用於定義WEB瀏覽器與WEB服務器之間交換數據的過程。客戶端連上web服務器後,若想得到web服務器中的某個web資源,需遵照必定的通信格式,HTTP協議用於定義客戶端與web服務器通迅的格式。

   http協議主要有兩個版本,他們的區別:

  在HTTP1.0協議中,客戶端與web服務器創建鏈接後,只能得到一個web資源。
  在HTTP1.1協議,容許客戶端與web服務器創建鏈接後,在一個鏈接上獲取多個web資源。

HTTP請求

客戶端連上服務器後,向服務器請求某個web資源,稱之爲客戶端向服務器發送了一個HTTP請求

一個完整的HTTP請求包括以下內容:一個請求行、若干消息頭、以及實體內容

請求行以一個方法符號開頭,以空格分開,後面跟着請求的URI和協議的版本,格式以下:Method Request-URI HTTP-Version CRLF 
其中 Method表示請求方法;Request-URI是一個統一資源標識符;HTTP-Version表示請求的HTTP協議版本;CRLF表示回車和換行(除了做爲結尾的CRLF外,不容許出現單獨的CR或LF字符)。

請求方法(全部方法全爲大寫)有多種,各個方法的解釋以下:
  GET     請求獲取Request-URI所標識的資源
  POST    在Request-URI所標識的資源後附加新的數據
  HEAD    請求獲取由Request-URI所標識的資源的響應消息報頭
  PUT     請求服務器存儲一個資源,並用Request-URI做爲其標識
  DELETE  請求服務器刪除Request-URI所標識的資源
  TRACE   請求服務器回送收到的請求信息,主要用於測試或診斷
  CONNECT 保留未來使用
  OPTIONS 請求查詢服務器的性能,或者查詢與資源相關的選項和需求


HTTP請求的細節——消息頭

  HTTP請求中的經常使用消息頭

  accept:瀏覽器經過這個頭告訴服務器,它所支持的數據類型
  Accept-Charset: 瀏覽器經過這個頭告訴服務器,它支持哪一種字符集
  Accept-Encoding:瀏覽器經過這個頭告訴服務器,支持的壓縮格式
  Accept-Language:瀏覽器經過這個頭告訴服務器,它的語言環境
  Host:瀏覽器經過這個頭告訴服務器,想訪問哪臺主機
  If-Modified-Since: 瀏覽器經過這個頭告訴服務器,緩存數據的時間
  Referer:瀏覽器經過這個頭告訴服務器,客戶機是哪一個頁面來的  防盜鏈
  Connection:瀏覽器經過這個頭告訴服務器,請求完後是斷開連接仍是何持連接


Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, 
    application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://localhost:8080/JavaWebDemoProject/Web/2.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3)
Accept-Encoding: gzip, deflate
Host: localhost:8080
Connection: Keep-Alive

HTTP響應

一個HTTP響應表明服務器向客戶端回送的數據,它包括: 一個狀態行、若干消息頭、以及實體內容


 


HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 105
Date: Tue, 27 May 2014 16:23:28 GMT

<html>
    <head>
        <title>Hello World JSP</title>
    </head>
    <body>
        Hello World!

    </body>
</html>

HTTP響應的細節——狀態行

    狀態行格式: HTTP版本號 狀態碼 緣由敘述<CRLF>
      舉例:HTTP/1.1 200 OK
  狀態碼用於表示服務器對請求的處理結果,它是一個三位的十進制數。響應狀態碼分爲5類,以下所示:
  

HTTP響應細節——經常使用響應頭

  HTTP響應中的經常使用響應頭(消息頭)
  Location: 服務器經過這個頭,來告訴瀏覽器跳到哪裏
  Server:服務器經過這個頭,告訴瀏覽器服務器的型號
  Content-Encoding:服務器經過這個頭,告訴瀏覽器,數據的壓縮格式
  Content-Length: 服務器經過這個頭,告訴瀏覽器回送數據的長度
  Content-Language: 服務器經過這個頭,告訴瀏覽器語言環境
  Content-Type:服務器經過這個頭,告訴瀏覽器回送數據的類型
  Refresh:服務器經過這個頭,告訴瀏覽器定時刷新
  Content-Disposition: 服務器經過這個頭,告訴瀏覽器如下載方式打數據
  Transfer-Encoding:服務器經過這個頭,告訴瀏覽器數據是以分塊方式回送的
  Expires: -1  控制瀏覽器不要緩存
  Cache-Control: no-cache 
  Pragma: no-cache

Http協議工程運用

緩存機制

http請求自帶緩存機制,當緩存中存在請求的數據時再也不請求(即便沒有網絡返回碼也是200)或者不作數據傳輸處理具體以下:

  從緩存取
獲取資源形式 狀態碼 發送請求到服務器
強緩存 200(from cache) 否,直接從緩存取
協商緩存 從緩存取 304(not modified) 是,正如其名,經過服務器來告知緩存是否可用

緩存機制:http://www.javashuo.com/article/p-nhkwogbj-cy.html

okhttp攔截器

http://www.javashuo.com/article/p-femliszd-gp.html

Http通訊在Android中的使用

  初始化 定義HttpURLConnection , 經過BufferReader 按行讀取傳輸的數據 ,最後將數據賦值給一個StringBuilder

    HttpURLConnection connection = (HttpURLConnection)url.openConnection();

  InputStream in = connection.getInputStream();

    BufferedReader reader =  new BufferedReader(new InputStreamReader(in));

package com.iflytek.internetcommunicate;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private TextView text;
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

// button : push send an request for get infomation of www.baidu.com
        Button sendRequest = (Button) findViewById(R.id.ConnectInternet);
// text : dis the info in text
         text = (TextView)findViewById(R.id.DisInfo);
        sendRequest.setOnClickListener(this);
    }

    public void onClick(View v){
        if(v.getId()==R.id.ConnectInternet){
           sendRequestWithHttp();
        }
    }

    private void sendRequestWithHttp(){
        //開啓線程發起網絡請求
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                BufferedReader reader=null;
                try{
                    URL url =new URL("http://www.baidu.com");
                    // connection的初始化,而且調用openConnection()方法,打開鏈接
                    connection =(HttpURLConnection)url.openConnection();
                    connection.setRequestMethod("get");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    // inputstream 接受connect傳輸的數據
                    InputStream in = connection.getInputStream();

                    //經過reader讀取inputstream中的數據
                    reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while((line= reader.readLine())!=null){
                        response.append(line);
                    }
                    showResponse(response.toString());
                }catch(Exception e){
                    e.printStackTrace();
                }finally {
                    if(reader!=null){
                        try {
                            reader.close();
                        }catch (IOException e){
                            e.printStackTrace();
                        }
                    }
                    if(connection!=null){
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }
    private void showResponse(final  String response){
        //android 不容許子線程 修改UI操做,必須切換到主線程才能對 UI進行修改
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                text.setText(response);
            }
        });
    }
}
HttpURLConnection


參考:

http://www.cnblogs.com/IPrograming/archive/2012/03/17/Java_Socket_3.htm

相關文章
相關標籤/搜索