<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    kingpub

    海內存知己,博客若比鄰

     

    Java Socket編程

    Java Socket編程

    1.Socket傳輸模式


    Sockets有兩種主要的操作方式:面向連接的和無連接的.面向連接的sockets操作就像一部電話,他們必須建立一個連接和一人呼叫.所有的事情在到達時的順序與它們出發時的順序時一樣.無連接的sockets操作就像是一個郵件投遞,,沒有什么保證,多個郵件可能在到達時的順序與出發時的順序不一樣.

    到底用哪種模式是郵應用程序的需要決定的.如果可靠性更重要的話,用面向連接的操作會好一些.比如文件服務器需要他們的數據的正確性和有序性.如果一些數據丟失了,系統的有效性將會失去.一些服務器,比如間歇性地發送一些數據塊.如果數據丟了的話,服務器并不想要再重新發過一次.因為當數據到達的時候,它可能已經過時了.確保數據的有序性和正確性需要額外的操作的內存消耗,額外的費用將會降低系統的回應速率.

    無連接的操作使用數據報協議.一個數據報是一個獨立的單元,它包含了所有的這次投遞的信息.把它想象成一個信封吧,它有目的地址和要發送的內容.這個模式下的socket不需要連接一個目的的socket,它只是簡單地投出數據報.無連接的操作是快速的和高效的,但是數據安全性不佳.

    面向連接的操作使用TCP協議.一個這個模式下的socket必須在發送數據之前與目的地的socket取得一個連接.一旦連接建立了,sockets就可以使用一個流接口:打開-讀-寫-關閉.所有的發送的信息都會在另一端以同樣的順序被接收.面向連接的操作比無連接的操作效率更低,但是數據的安全性更高.

    SUN一直是網絡建設的支持者,所以在Java中支持sockets就不足為奇了.實際上,Java降低了建立一個sockets程序的難度.每一個傳輸模式都被封裝到了不同的類中.面向連接的類將會首先被我們討論.

    Sockets有兩種主要的操作方式:面向連接的和無連接的.面向連接的sockets操作就像一部電話,他們必須建立一個連接和一人呼叫.所有的事情在到達時的順序與它們出發時的順序時一樣.無連接的sockets操作就像是一個郵件投遞,,沒有什么保證,多個郵件可能在到達時的順序與出發時的順序不一樣.

    到底用哪種模式是郵應用程序的需要決定的.如果可靠性更重要的話,用面向連接的操作會好一些.比如文件服務器需要他們的數據的正確性和有序性.如果一些數據丟失了,系統的有效性將會失去.一些服務器,比如間歇性地發送一些數據塊.如果數據丟了的話,服務器并不想要再重新發過一次.因為當數據到達的時候,它可能已經過時了.確保數據的有序性和正確性需要額外的操作的內存消耗,額外的費用將會降低系統的回應速率.

    無連接的操作使用數據報協議.一個數據報是一個獨立的單元,它包含了所有的這次投遞的信息.把它想象成一個信封吧,它有目的地址和要發送的內容.這個模式下的socket不需要連接一個目的的socket,它只是簡單地投出數據報.無連接的操作是快速的和高效的,但是數據安全性不佳.

    面向連接的操作使用TCP協議.一個這個模式下的socket必須在發送數據之前與目的地的socket取得一個連接.一旦連接建立了,sockets就可以使用一個流接口:打開-讀-寫-關閉.所有的發送的信息都會在另一端以同樣的順序被接收.面向連接的操作比無連接的操作效率更低,但是數據的安全性更高.

    SUN一直是網絡建設的支持者,所以在Java中支持sockets就不足為奇了.實際上,Java降低了建立一個sockets程序的難度.每一個傳輸模式都被封裝到了不同的類中.面向連接的類將會首先被我們討論

    2.Java面向連接的類

    Sockets有兩種主要的操作方式:面向連接的和無連接的.面向連接的sockets操作就像一部電話,他們必須建立一個連接和一人呼叫.所有的事情在到達時的順序與它們出發時的順序時一樣.無連接的sockets操作就像是一個郵件投遞,,沒有什么保證,多個郵件可能在到達時的順序與出發時的順序不一樣.

    到底用哪種模式是郵應用程序的需要決定的.如果可靠性更重要的話,用面向連接的操作會好一些.比如文件服務器需要他們的數據的正確性和有序性.如果一些數據丟失了,系統的有效性將會失去.一些服務器,比如間歇性地發送一些數據塊.如果數據丟了的話,服務器并不想要再重新發過一次.因為當數據到達的時候,它可能已經過時了.確保數據的有序性和正確性需要額外的操作的內存消耗,額外的費用將會降低系統的回應速率.

    無連接的操作使用數據報協議.一個數據報是一個獨立的單元,它包含了所有的這次投遞的信息.把它想象成一個信封吧,它有目的地址和要發送的內容.這個模式下的socket不需要連接一個目的的socket,它只是簡單地投出數據報.無連接的操作是快速的和高效的,但是數據安全性不佳.

    面向連接的操作使用TCP協議.一個這個模式下的socket必須在發送數據之前與目的地的socket取得一個連接.一旦連接建立了,sockets就可以使用一個流接口:打開-讀-寫-關閉.所有的發送的信息都會在另一端以同樣的順序被接收.面向連接的操作比無連接的操作效率更低,但是數據的安全性更高.

    SUN一直是網絡建設的支持者,所以在Java中支持sockets就不足為奇了.實際上,Java降低了建立一個sockets程序的難度.每一個傳輸模式都被封裝到了不同的類中.面向連接的類將會首先被我們討論

    在Java中面向連接的類有兩種形式,它們分別是客戶端和服務器端.客戶端這一部分是最簡單的,所以我們先討論它.

    列表9.1列出了一個簡單的客戶端的程序.它向一個服務器發出一個請求,取回一個HTML文檔,并把它顯示在控制臺上.

    9.1一個簡單的socket客戶端

    import java.io.*;
    import java.net.*;
    /**
    * 一個簡單的從服務器取回一個HTML頁面的程序
    * 注意:merlin是本地機器的名字
    */
    public class SimpleWebClient {
    public static void main(String args[])
    {
    try
    {
    // 打開一個客戶端socket連接
    Socket clientSocket1 = new Socket("merlin", 80);
    System.out.println("Client1: " + clientSocket1);
    // 取得一個網頁
    getPage(clientSocket1);
    }
    catch (UnknownHostException uhe)
    {
    System.out.println("UnknownHostException: " + uhe);
    }
    catch (IOException ioe)
    {
    System.err.println("IOException: " + ioe);
    }
    }
    /**
    *通過建立的連接請求一個頁面,顯示回應然后關閉socket
    */
    public static void getPage(Socket clientSocket)
    {
    try
    {
    // 需要輸入和輸出流
    DataOutputStream outbound = new DataOutputStream(
    clientSocket.getOutputStream() );
    DataInputStream inbound = new DataInputStream(
    clientSocket.getInputStream() );
    // 向服務器發出HTTP請求
    outbound.writeBytes("GET / HTTP/1.0 ");
    // 讀出回應
    String responseLine;
    while ((responseLine = inbound.readLine()) != null)
    {
    // 把每一行顯示出來
    System.out.println(responseLine);
    if ( responseLine.indexOf("") != -1 )
    break;
    }
    // 清除
    outbound.close();
    inbound.close();
    clientSocket.close();
    }
    catch (IOException ioe)
    {
    System.out.println("IOException: " + ioe);
    }
    }
    }

    Java面向連接的類

    回憶一個,一個客戶端向一個正在監聽的服務器socket發出一個連接.客戶端的sockets是用Socket類建立的.下面的程序建立了一個客戶端的socket并且連接到了一個主機:

    Socket clientSocket = new Socket("merlin", 80);

    第一個參數是你想要連接的主機的名稱,第二個參數是端口號.一個主機名稱指定了目的的名稱.端口號指定了由哪個應用程序來接收.在我們的情況下,必須指定80,因為它是默認的HTTP協議的端口.另外的知名的端口列在表9.1中,看:

    知名的端品:

    echo 7

    daytime 13

    daytime 13

    ftp 21

    telnet 23

    smtp 25

    finger 79

    http 80

    pop3 110

    因為Socket類是面向連接的,它提供了一個可供讀寫的流接口.java.io包中的類可以用來訪問一個已連接的socket:

    DataOutputStream outbound = new DataOutputStream(
    clientSocket.getOutputStream() );
    DataInputStream inbound = new DataInputStream( clientSocket.getInputStream()
    );

    一旦流建立了,一般的流操作就可以做了:

    outbound.writeBytes("GET / HTTP/1.0 );
    String responseLine;
    while ( (responseLine = inbound.readLine()) != null)
    {
    System.out.println(responseLine);
    }

    以上的小程序請求了一個WEB頁面并且把它顯示出來.當程序完成之后,連接必須關閉.

    outbound.close();
    inbound.close();
    clientSocket.close();

    注意socket流必須首先關閉.所有的的socket流必須在socket關閉之前關閉.這個小程序非常地簡單,但是所有的客戶端程序都必須遵首下面的基本的步驟:

    1.建立客戶端socket連接.

    2.得到socket的讀和寫的流.

    3.利用流.

    4.關閉流.

    5.關閉socket.

    使用一個服務器端的socket只是有一點復雜,它將在下面講到.

    服務器Sockets

    列表9.2是一個服務器應用程序的一部分.

    列表9.2 一個簡單的服務器程序

    /**
    * 一個監聽端口并提供HTML文檔的程序.
    */
    class SimpleWebServer {
    public static void main(String args[])
    {
    ServerSocket serverSocket = null;
    Socket clientSocket = null;
    int connects = 0;
    try
    {
    {
    // 建立一個服務器socket
    serverSocket = new ServerSocket(80, 5);
    while (connects < 5)
    {
    // 等待連接
    clientSocket = serverSocket.accept();
    //服務連接
    ServiceClient(clientSocket);
    connects++;
    }
    serverSocket.close();
    }
    catch (IOException ioe)
    {
    System.out.println("Error in SimpleWebServer: " + ioe);
    }
    }
    public static void ServiceClient(Socket client)
    throws IOException
    {
    DataInputStream inbound = null;
    DataOutputStream outbound = null;
    try
    {
    // 得到IO流
    inbound = new DataInputStream( client.getInputStream());
    outbound = new DataOutputStream( client.getOutputStream());
    //格式化輸出(回應頭和很少的HTML文檔)
    StringBuffer buffer = PrepareOutput();
    String inputLine;
    while ((inputLine = inbound.readLine()) != null)
    {
    //如果到了HTTP請求的尾部,就發送回應
    if ( inputLine.equals("") )
    {
    outbound.writeBytes(buffer.toString());
    break;
    }
    }
    }
    finally
    {
    // 清除
    System.out.println("Cleaning up connection: " + client);
    tln("Cleaning up connection: " + client);
    outbound.close();
    inbound.close();
    client.close();
    client.close();
    }
    }

    服務器Sockets

    服務器并不是主動地建立連接.相反地,他們是被動地監聽一個客戶端的連接請示然后給他們服務.服務器是由類ServerSocket來建立的.下面的程序建立了一個服務器端socket并把它綁定到80端口:

    ServerSocket serverSocket = new ServerSocket(80, 5);

    第一個參數是服務器要監聽的端口.第二個參數是可選的.API文檔中說明了這是一個監聽時間,但是在傳統的socket程序中第二個參數是監聽深度.一個服務器可以同時接收多個連接請求,但是每次只能處理一個.監聽堆是一個無回答的連接請求隊列.上面的請求建立一個連接來處理最后五個請求.如果省略了后面的一個參數,則默認值是50.

    ServerSocket serverSocket = new ServerSocket(80, 5);

    一旦socket建立了并開始監聽連接,進來的連接將會建立并放在監聽堆.accetp()方法把在堆中的連接取出來.

    Socket clientSocket = serverSocket.accept();

    這個方法返回一個用來與來訪者對話的客戶端連接.服務器本身不可能建立對話,相反地,服務器socket會使用accept()方法來產生一個新的socket.服務器socket依舊打開并排列新的連接請求.

    與客戶端socket一樣,下面的一步建立輸入和輸出流:

    DataInputStream inbound = new DataInputStream( clientSocket.getInputStream() ); DataOutputStream outbound = new DataOutputStream( clientSocket.getOutputStream() );

    一般的I/O操作可以在新建的流中運用.在服務器回應前它等待客戶端發送一個空白的行.當會話結束時,服務器關閉流和客戶端socket.如果在隊列中沒有請示將會出現什么情況呢?那個方法將會等待一個的到來.這個行為叫阻塞.accept()方法將會阻塞服務器線程直到一個呼叫到來.當5個連接處理完閉之后,服務器退出.任何的在隊列中的呼叫將會被取消.

    所有的服務器都要有以下的基本的步驟:

    1.建立一個服務器socket并開始監聽.

    2.使用accept()方法取得新的連接.

    3.建立輸入和輸出流.

    4.在已有的協議上產生會話.

    5.關閉客戶端流和socket.

    6.回到第二步或者到第七步.

    7.關閉服務器socket.

    重復和并發服務器

    這個應用程序被當作一個重復的服務器.因為它只有在處理完一個進程以后才會接受另一個連接.更多的復雜服務器是并發的.它為每一個請求分配一個線程,而不是來一個處理一個.所以看起來它在同時處理多人請求.所有的商業的服務器都是并發的服務器.

    Java數據報類

    不像面向連接的類,數據報的客戶端和服務器端的類在表面上是一樣的.下面的程序建立了一個客戶和服務器商的數據報sockets:

    DatagramSocket serverSocket = new DatagramSocket( 4545 );
    DatagramSocket clientSocket = new DatagramSocket();

    服務器用參數4545來指定端口號,由于客戶端將要呼叫服務器,客戶端可以利用可利用的端口.如果省略第二個參數,程序會讓操作系統分配一個可用的端口.客戶端可以請求一個指定的端口,但是如果其它的應用程序已經綁定到這個端口之上,請求將會失敗.如果你的意圖不是作為一個服務器,最好不要指定端口.

    由于流不能由交談得到,那么我么如何與一個數據報Socket進行對話.答案在于數據報類.

    接收數據報

    DatagramPacket類是用來通過DatagramSocket類接收和發送數據的類.packet類包括了連接信息和數據.就如前面所說的一樣,數據報是自身獨立的傳輸單元.DatagramPacket類壓縮了這些單元.下面的程序表示了用一個數據報socket來接收數據:

    DatagramPacket packet = new DatagramPacket(new byte[512], 512); clientSocket.receive(packet);
    clientSocket.receive(packet);

    packet的構建器需要知道將得到的數據放在哪兒.一個512字節的緩存被建立并且作為構建器的第二個參數.每二個構建器參數是緩存的大小.就像ServerSocket類的accept()方法一樣,receive()方法在數據可用之前將會阻塞.

    發送數據報

    發送數據報是非常地簡單地,所有需要的只是一個地址.地址是由InetAddress類來建立的.這個類沒有公共的構建器,但是它有幾個static的方法,可以用來建立這個類的實例.下面的列表列出了建立InetAddress類的實例的方法:

    Public InetAddress Creation Methods

    InetAddress getByName(String host);
    InetAddress[] getAllByName(String host);
    InetAddress getLocalHost();

    得到本地主機的地址是非常地有用的,只有前面兩個方法是用來發送數據包的.getByName()和getAllByName()需要目的主機的地址.第一個方法僅僅只是返回第一個符合條件的東西.第二個方法是必須的,因為一臺計算機可能有多個地址.在這種情況下,這臺計算機被稱為multi-homed.

    所有的建立的方法都被標記為static.它們必須像下面這樣得到調用:

    InetAddress addr1 = InetAddress.getByName("merlin");
    InetAddress addr2[] = InetAddress.getAllByName("merlin");
    InetAddress addr3 = InetAddress.getLocalHost();

    所有的這些調用都可以擲出一個UnknownHostException違例.如果一臺計算機沒有連接上DNS服務器,或者主機的確沒有找到,這個違例就會被擲出.如果一臺計算機沒有一個激活的TCP/IP配置,getLocalHost()也為失敗并擲出一個違例.

    一旦一個地址被確定了,數據報就可以被送出了.下面的程序傳輸了一個字符串給目的socket:

    String toSend = "This is the data to send!");
    byte[] sendbuf = new byte[ toSend.length() ];
    toSend.getBytes( 0, toSend.length(), sendbuf, 0 );
    DatagramPacket sendPacket = new DatagramPacket( sendbuf, sendbuf.length,
    addr, port);
    clientSocket.send( sendPacket );

    首先,字符串必須被轉換成一個字節數組.然后,一個新的DatagramPacket實例必須被建立.注意構建器的最后兩個參數.因為要發送一個包,所以地址和端口必須被給定.一個applet可能可以知道它的服務器的地址,但是服務器如何知道它的客戶機的地址呢.當任何一個包被收到后,返回的地址和端口會被解壓出來,并通過getAddress()和getPort()方法得到.這就是一個服務器如何回應一個客戶端的包:

    DatagramPacket sendPacket = new DatagramPacket( sendbuf, sendbuf.length,
    recvPacket.getAddress(), recvPacket.getPort() );
    serverSocket.send( sendPacket );

    不像面向連接的操作,數據報服務器服務器其實比數據報客戶端更簡單:

    數據報服務器

    一個數據報服務器的基本步驟:

    1.在一個指定的端口上建立一個數據報socket.

    2.用receive方法等待進來的包.

    3.用特定的協議來回應收到的包.

    4.回到第二步或繼續第二步.

    5.關閉數據報socket.

    列表9.3演示了一人簡單的數據報回應服務器.它將回應它收到的包.

    列表9.3.一個簡單的數據報回應服務器

    import java.io.*;
    import java.net.*;
    public class SimpleDatagramServer
    {
    public static void main(String[] args)
    {
    DatagramSocket socket = null;
    DatagramPacket recvPacket, sendPacket;
    try
    {
    socket = new DatagramSocket(4545);
    while (socket != null)
    {
    recvPacket= new DatagramPacket(new byte[512], 512);
    socket.receive(recvPacket);
    sendPacket = new DatagramPacket(
    recvPacket.getData(), recvPacket.getLength(),
    recvPacket.getAddress(), recvPacket.getPort() );
    socket.send( sendPacket );
    }
    }
    catch (SocketException se)
    {
    System.out.println("Error in SimpleDatagramServer: " + se);
    }
    catch (IOException ioe)
    {
    System.out.println("Error in SimpleDatagramServer: " + ioe);


    簡單的WEB服務器

    一個簡單的WEB服務器將由列表9.2這樣構建.當然,還必須要對方法和回應事件進行改進.簡單的服務器不會分析和存儲請求頭.新的WEB服務器將分析和存儲請求,為以后的處理作準備.為了達到這個目的,你必須有一個包含HTTP請求的類.

    HTTPrequest類

    列表9.5列出了一個完整的HTTPrequest類.這個類必須包括一個請求頭所需的所有信息.

    列表9.5.HTTPrequest類.

    import java.io.*;
    import java.util.*;
    import java.net.*;
    import NameValue;
    /**
    * 這個類有一個HTTP請求的所有信息
    */
    public class HTTPrequest
    {
    public String version;
    public String method;
    public String file;
    public Socket clientSocket;
    public DataInputStream inbound;
    public NameValue headerpairs[];
    /**
    * 建立一個這個類的實例
    */
    public HTTPrequest()
    {
    version = null;
    method = null;
    file = null;
    clientSocket = null;
    inbound = null;
    inbound = null;
    headerpairs = new NameValue[0];
    }
    /**
    * 加入一個名稱/值對到核心數組
    */
    public void addNameValue(String name, String value)
    {
    try
    {
    NameValue temp[] = new NameValue[ headerpairs.length + 1 ];
    System.arraycopy(headerpairs, 0, temp, 0, headerpairs.length);
    temp[ headerpairs.length ] = new NameValue(name, value);
    headerpairs = temp;
    }
    catch (NullPointerException npe)
    {
    System.out.println("NullPointerException while adding name-value:
    " + npe);
    }
    }
    /**
    * 以字符串的形式歸還這個類
    */
    public String toString()
    {
    String s = method + " " + file + " " + version + " ";
    for (int x = 0; x < headerpairs.length; x++ )
    s += headerpairs[x] + " ";
    return s;
    }
    }

    NameValue類簡單地存儲了兩個字符串:name 和 value.當一個新的對要被加入時,一個新的數組將被分配.新的數組接受了舊的數組和新的成員.舊的數組然后被一個新建的對象覆蓋了

    posted on 2006-06-08 15:34 xiaofeng 閱讀(174) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     

    導航

    統計

    常用鏈接

    留言簿(2)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    收藏夾

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 日韩成人精品日本亚洲| 亚洲色少妇熟女11p| 日韩一级在线播放免费观看| 国产免费av片在线无码免费看| 中文字幕 亚洲 有码 在线| 在线免费中文字幕| 亚洲国产小视频精品久久久三级| 亚洲国产精品无码久久一线| 亚洲AV日韩综合一区尤物| 日韩免费a级毛片无码a∨| 亚洲AV永久青草无码精品| 亚洲AV成人无码网天堂| 国产成人无码区免费A∨视频网站 国产成人涩涩涩视频在线观看免费 | 亚洲精品高清无码视频| 免费看少妇高潮成人片| 亚洲视频在线观看视频| 一区二区三区免费看| 午夜高清免费在线观看| 亚洲精品色在线网站| 亚洲人成网站在线观看青青| 亚洲国产精品免费视频| 一区二区三区免费在线视频| 成年女人永久免费观看片| 深夜福利在线视频免费| 亚洲精品乱码久久久久久自慰| 曰批视频免费40分钟试看天天| 亚洲人成网站色在线观看| 国产gav成人免费播放视频| 两性色午夜免费视频| 亚洲国产小视频精品久久久三级| a级毛片在线免费| 国产亚洲欧洲精品| 国产在线观看麻豆91精品免费| 亚洲av日韩专区在线观看| 久久综合亚洲色HEZYO国产| 又硬又粗又长又爽免费看| 亚洲AV福利天堂一区二区三| 成年女人毛片免费观看97| 亚洲人av高清无码| 伊人久久大香线蕉亚洲五月天| 91网站免费观看|