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

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

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

    隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
    數據加載中……

    Java網絡編程從入門到精通(29):服務端Socket的選項

    本文為原創,如需轉載,請注明作者和出處,謝謝!

    上一篇:Java網絡編程從入門到精通(28):獲取ServerSocket信息的方法及FTP原理

    ServerSocket類有以下三個選項:

    1.       SO_TIMEOUT 設置accept方法的超時時間。

    2.       SO_REUSEADDR設置服務端同一個端口是否可以多次綁定。

    3.       SO_RECBUF設置接收緩沖區的大小。

    一、SO_TIMEOUT選項

    可以通過SeverSocket類的兩個方法(setSoTimeoutgetSoTimeout)來設置和獲得SO_TIMEOUT選項的值,這兩個方法的定義如下:

    public synchronized void setSoTimeout(int timeout) throws SocketException
    public synchronized int getSoTimeout() throws IOException

    setSoTimeout方法的timeout參數表示accept方法的超時時間,單位是毫秒。在通常情況下,ServerSocket類的accept方法在等待客戶端請求時處于無限等待狀態。如HTTP服務器在沒有用戶訪問網頁時會一直等待用戶的請求。一般不需要對服務端設置等待客戶端請求超時,但在某些特殊情況下,服務端規定客戶端必須在一定時間內向服務端發出請求,這時就要設置等待客戶端請求超時,也就是accept方法的超時時間。當設置客戶端請求超時后,accept方法在等待超時時間后拋出一個SocketTimeoutException異常。下面的代碼演示了如何設置和獲得SO_TIMEOUT選項的值,超時時間通過命令行參數方式傳入AcceptTimeout

    package server;

    import java.net.*;

    public class AcceptTimeout
    {
        
    public static void main(String[] args) throws Exception
        {
            
    if (args.length == 0)
                
    return;
            ServerSocket serverSocket 
    = new ServerSocket(1234);
            
    int timeout = Integer.parseInt(args[0]);
            
            serverSocket.setSoTimeout(Integer.parseInt(args[
    0]));
            System.out.println((timeout 
    > 0? "accept方法將在"
                    
    + serverSocket.getSoTimeout() + "毫秒后拋出異常!" : "accept方法永遠阻塞!");;
            serverSocket.accept();
        }
    }

    執行下面的命令:

    java server.AcceptTimeout 3000

    運行結果:

    accept方法將在3000毫秒后拋出異常!
    Exception in thread 
    "main" java.net.SocketTimeoutException: Accept timed out
        at java.net.PlainSocketImpl.socketAccept(Native Method)
        at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:
    384)
        at java.net.ServerSocket.implAccept(ServerSocket.java:
    450)
        at java.net.ServerSocket.accept(ServerSocket.java:
    421)
        at chapter5.AcceptTimeout.main(AcceptTimeout.java:
    16)

    setSoTimeout方法可以在ServerSocket對象綁定端口之前調用,也以在綁定端口之后調用。如下面的代碼也是正確的:

    ServerSocket serverSocket = new ServerSocket();
    serverSocket.setSoTimeout(
    3000);
    serverSocket.bind(
    new InetSocketAddress(1234));

    二、SO_REUSEADDR選項

    SO_REUSEADDR選項決定了一個端口是否可以被綁定多次。可以通過SeverSocket類的兩個方法(setReuseAddresgetReuseAddress)來設置和獲得SO_TIMEOUT選項的值,這兩個方法的定義如下:

    public void setReuseAddress(boolean on) throws SocketException 
    public boolean getReuseAddress() throws SocketException

    在大多數操作系統中都不允許一個端口被多次綁定。如果一個ServerSocket對象綁定了已經被占用的端口,那么ServerSocket的構造方法或bind方法就會拋出一個BindException異常。

    Java提供這個選項的主要目的是為了防止由于頻繁綁定釋放一個固定端口而使系統無法正常工作。當ServerSocket對象關閉后,如果ServerSocket對象中仍然有未處理的數據,那么它所綁定的端口可能在一段時間內不會被釋放。這就會造成其他的ServerSocket對象無法綁定這個端口。在設置這個選項時,如果某個端口是第一次被綁定,無需調用setReuseAddress方法,而再次綁定這個端口時,必須使用setReuseAddress方法將這個選項設為true。而且這個方法必須在調用bind方法之前調用。下面的代碼演示了如何設置和獲得這個選項的值:

    package server;

    import java.net.*;

    public class TestReuseAddr1
    {
        
    public static void main(String[] args) throws Exception
        {
            ServerSocket serverSocket1 
    = new ServerSocket(1234);
            System.out.println(serverSocket1.getReuseAddress());
            
            ServerSocket serverSocket2 
    = new ServerSocket();
            serverSocket2.setReuseAddress(
    true);
            serverSocket2.bind(
    new InetSocketAddress(1234));
            
            ServerSocket serverSocket3 
    = new ServerSocket();
            serverSocket3.setReuseAddress(
    true);
            serverSocket3.bind(
    new InetSocketAddress(1234));
        }
    }

    運行結果:false

    在上面代碼中第一次綁定端口1234,因此,serverSocket1對象無需設置SO_REUSEADDR選項(這個選項在大多數操作系統上的默認值是false)。而serverSocket2serverSocket3并不是第一次綁定端口1234,因此,必須設置這兩個對象的SO_REUSEADDR值為true。在設置SO_REUSEADDR選項時要注意,必須在ServerSocket對象綁定端口之前設置這個選項。

        也許有的讀者可能有這樣的疑問。如果多個ServerSocket對象同時綁定到一個端口上,那么當客戶端向這個端口發出請求時,該由哪個ServerSocket對象來接收客戶端請求呢?在給出答案之前,讓我們先看看下面的代碼的輸出結果是什么。

    package server;

    import java.net.*;

    public class TestReuseAddr2 extends Thread
    {
        String s;
        
    public void run()
        {
            
    try
            {
                ServerSocket serverSocket 
    = new ServerSocket();
                serverSocket.setReuseAddress(
    true);
                serverSocket.bind(
    new InetSocketAddress(1234));
                Socket socket 
    = serverSocket.accept();
                System.out.println(s 
    + "" + socket);
                socket.close();
                serverSocket.close();
            }
            
    catch (Exception e)
            {
            }
        }
        
    public TestReuseAddr2(String s)
        {
            
    this.s = s;
        }
        
    public static void main(String[] args)
        {
            
    for (int i = 1; i <= 5; i++)
                
    new TestReuseAddr2("ServerSocket" + i).start();
        }
    }

    執行下面的命令:

    java server.TestReuseAddr2


        連續執行5次下面的命令:

    telnet localhost 1234

    執行結果:

    ServerSocket1:Socket[addr=/127.0.0.1,port=11724,localport=1234]
    ServerSocket3:Socket[addr
    =/127.0.0.1,port=11725,localport=1234]
    ServerSocket5:Socket[addr
    =/127.0.0.1,port=11726,localport=1234]
    ServerSocket2:Socket[addr
    =/127.0.0.1,port=11727,localport=1234]
    ServerSocket4:Socket[addr
    =/127.0.0.1,port=11728,localport=1234]

        上面的運行結果只是一種可能,如果多次按著上面的步驟操作,可能得到不同的運行結果。由此可以斷定,當多個ServerSocket對象同時綁定一個端口時,系統會隨機選擇一個ServerSocket對象來接收客戶端請求。但要注意,這個接收客戶端請求的ServerSocket對象必須關閉(如019行如示),才能輪到其他的ServerSocket對象接收客戶端請求。如果不關閉這個ServerSocket對象,那么其他的ServerSocket對象將永遠無法接收客戶端請求。讀者可以將 serverSocket.close()去掉,再執行上面操作步驟,看看會有什么結果。

    三、SO_RCVBUF選項

    可以通過SeverSocket類的兩個方法(setReceiveBufferSizegetReceiveBufferSize)來設置和獲得SO_RCVBUF選項的值,這兩個方法的定義如下:

    public synchronized void setReceiveBufferSize (int size) throws SocketException
    public synchronized int getReceiveBufferSize() throws SocketException

        其中size參數表示接收緩沖區的大小,單位是字節。設置了ServerSocket類的SO_RCVBUF選項,就相當于設置了Socket對象的接收緩沖區大小。這個Socket對象是由accept返回的。下面積代碼演示了如何使用這兩個方法來設置和獲得接收緩沖區的大小:

    package server;

    import java.net.*;

    public class TestReceiveBufferSize
    {
        
    public static void main(String[] args) throws Exception
        {
            ServerSocket serverSocket 
    = new ServerSocket(1234);
            serverSocket.setReceiveBufferSize(
    2048); // 將接收緩沖區設為2K
            while (true)
            {
                Socket socket 
    = serverSocket.accept();
                
    // 如果客戶端請求使用的是本地IP地址,重新將Socket對象的接
                
    // 收緩沖區設為1K            
                if (socket.getInetAddress().isLoopbackAddress())
                    socket.setReceiveBufferSize(
    1024);
                System.out.println(
    "serverSocket:"
                                
    + serverSocket.getReceiveBufferSize());
                System.out.println(
    "socket:" + socket.getReceiveBufferSize());
                socket.close();
            }
        }
    }

    執行如下命令:
    java server.TestReceiveBufferSize
    執行如下三個命令 (192.168.18.100為本機IP地址):
    telnet 192.168.18.100 1234
    telnet localhost 
    1234
    telnet 
    192.168.18.100 1234
    運行結果:
    serverSocket:2048
    socket:
    2048
    serverSocket:
    2048
    socket:
    1024
    serverSocket:
    2048
    socket:
    2048

    從上面的運行結果可以看出,在執行telnet localhost 1234命令后,由于localhost是本地地址,因此程序通過Socket對象的接收緩沖區設為1024,而在執行其他兩條命令后,由于192.168.18.100不是本機地址,所以Socket對象的接收緩沖區仍然保留著serverSocket的值:2048。因此,我們可以得出一個結論,設置ServerSocket對象的接收緩沖區就相當于設置了所有從accept返回的Socket對象的接收緩沖區,只要不單獨對某個Socket對象重新設置,這些Socket對象的接收緩沖區就會都保留這個值。

    無論在ServerSocket對象綁定到端口之前還是之后設置SO_RCVBUF選項都有效,但如果要設置大于64K的接收緩沖區時,就必須在ServerSocket對象綁定端口之前設置SO_RCVBUF選項。如下面的代碼將接收緩沖區的大小設為100K

    ServerSocket serverSocket = new ServereSocket();
    serverSocket. setReceiveBufferSize(
    100 * 1024);  // 將接收緩沖區的大小設為100K。
    serverSocket.bind(new InetSocketAddress(1234));

       一般情況下,并不需要設置這個選項,它的默認值(一般為8K)足可以滿足大多數情況。但有時為了適應特殊的需要,必須更改接收緩沖區的值。如在一些網絡游戲中,需要實時地向服務器傳送各種動作、指令信息。這就需要將接收緩沖區設小一點。這樣可以在一定程度上增加游戲客戶端的靈敏度。如果需要傳送大量的數據,如HTTPFTP等協議。這就需要較大的接收緩沖區。

    四、設置ServerSocket的性能偏好 

    Java SE5.0及以上版本中為ServerSocket類增加了一個setPerformancePreferences方法。這個和方法和Socket類中的setPerformancePreferences的作用一樣,用來設置連接時間、延遲和帶寬的相對重要性。setPerformancePerferences方法的定義如下:

    public void setPerformancePreferences(int connectionTime, int latency, int bandwidth)

    下一篇:Java網絡編程從入門到精通(30):定制accept方法





    Android開發完全講義(第2版)(本書版權已輸出到臺灣)

    http://product.dangdang.com/product.aspx?product_id=22741502



    Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


    新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

    posted on 2009-08-12 14:50 銀河使者 閱讀(3201) 評論(1)  編輯  收藏 所屬分類: java 原創網絡編程

    評論

    # re: Java網絡編程從入門到精通(29):服務端Socket的選項  回復  更多評論   

    現在已經很少接觸了,跟著學習
    2009-08-12 15:14 | 凡人修仙傳最新
    主站蜘蛛池模板: 日韩欧毛片免费视频| 在线观看亚洲精品国产| 日韩色视频一区二区三区亚洲| 免费一级国产生活片| 国产免费爽爽视频在线观看| 亚洲乱码中文论理电影| 亚洲国产黄在线观看| 久草视频在线免费| 色多多A级毛片免费看| 亚洲经典在线观看| 无码欧精品亚洲日韩一区夜夜嗨 | 久久免费精品一区二区| 亚洲精品美女网站| 亚洲中文字幕在线乱码| 成人毛片免费在线观看| 在线看片免费人成视频播| 亚洲欧美日韩综合俺去了| 久久精品国产亚洲夜色AV网站| 日韩免费视频一区| 久久综合给合久久国产免费 | 中文日韩亚洲欧美制服| 日韩亚洲人成在线综合日本| 永久免费av无码网站大全| 久久久久久毛片免费播放| 一区二区免费国产在线观看| 亚洲国产精品综合久久20| 久久91亚洲人成电影网站| 国产精品久久久久影院免费| 最近中文字幕电影大全免费版| yellow视频免费看| 亚洲精品无码高潮喷水A片软| 久久亚洲精精品中文字幕| 在线精品亚洲一区二区三区| 国产成人aaa在线视频免费观看| 亚洲成人在线免费观看| 免费黄色电影在线观看| 一个人看的www视频免费在线观看| 亚洲AV无码之国产精品| 久久精品国产亚洲AV久| 亚洲综合在线成人一区| 亚洲AV第一页国产精品|