Java網絡編程從入門到精通(18):Socket類的getter和setter方法(2) – JAVA編程語言程序開發技術文章


二、用於獲得和設置Socket選項的getter和setter方法
Socket選擇可以指定Socket類發送和接受數據的方式。在JDK1.4中共有8個Socket選擇可以設置。這8個選項都定義在java.net.SocketOptions接口中。定義如下:



    public final static int TCP_NODELAY = 0x0001;


    public final static int SO_REUSEADDR = 0x04;


    public final static int SO_LINGER = 0x0080;


    public final static int SO_TIMEOUT = 0x1006;


    public final static int SO_SNDBUF = 0x1001;


    public final static int SO_RCVBUF = 0x1002;


    public final static int SO_KEEPALIVE = 0x0008;


    public final static int SO_OOBINLINE = 0x1003;


    有趣的是,這8個選項除瞭第一個沒在SO前綴外,其他7個選項都以SO作為前綴。其實這個SO就是Socket Option的縮寫;因此,在Java中約定所有以SO為前綴的常量都表示Socket選項;當然,也有例外,如TCP_NODELAY。在Socket類中為每一個選項提供瞭一對get和set方法,分別用來獲得和設置這些選項。



1. TCP_NODELAY


public boolean getTcpNoDelay() throws SocketException
public void setTcpNoDelay(boolean on) throws SocketException
在默認情況下,客戶端向服務器發送數據時,會根據數據包的大小決定是否立即發送。當數據包中的數據很少時,如隻有1個字節,而數據包的頭卻有幾十個字節(IP頭+TCP頭)時,系統會在發送之前先將較小的包合並到軟大的包後,一起將數據發送出去。在發送下一個數據包時,系統會等待服務器對前一個數據包的響應,當收到服務器的響應後,再發送下一個數據包,這就是所謂的Nagle算法;在默認情況下,Nagle算法是開啟的。


這種算法雖然可以有效地改善網絡傳輸的效率,但對於網絡速度比較慢,而且對實現性的要求比較高的情況下(如遊戲、Telnet等),使用這種方式傳輸數據會使得客戶端有明顯的停頓現象。因此,最好的解決方案就是需要Nagle算法時就使用它,不需要時就關閉它。而使用setTcpToDelay正好可以滿足這個需求。當使用setTcpNoDelay(true)將Nagle算法關閉後,客戶端每發送一次數據,無論數據包的大小都會將這些數據發送出去。


2.  SO_REUSEADDR


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



通過這個選項,可以使多個Socket對象綁定在同一個端口上。其實這樣做並沒有多大意義,但當使用close方法關閉Socket連接後,Socket對象所綁定的端口並不一定馬上釋放;系統有時在Socket連接關閉才會再確認一下是否有因為延遲面未到達的數據包,這完全是在底層處理的,也就是說對用戶是透明的;因此,在使用Socket類時完全不會感覺到。


這種處理機制對於隨機綁定端口的Socket對象沒有什麼影響,但對於綁定在固定端口的Socket對象就可能會拋出“Address already in use: JVM_Bind”例外。因此,使用這個選項可以避免個例外的發生。



package mynet;


import java.net.*;
import java.io.*;


public class Test
{
    public static void main(String[] args)
    {
        Socket socket1 = new Socket();
        Socket socket2 = new Socket();
        try
        {
            socket1.setReuseAddress(true);
            socket1.bind(new InetSocketAddress(“127.0.0.1”, 88));
            System.out.println(“socket1.getReuseAddress():”
                    + socket1.getReuseAddress());
            socket2.bind(new InetSocketAddress(“127.0.0.1”, 88));
        }
        catch (Exception e)
        {
            System.out.println(“error:” + e.getMessage());
            try
            {
                socket2.setReuseAddress(true);
                socket2.bind(new InetSocketAddress(“127.0.0.1”, 88));
       &

發佈留言