当前位置导航:炫浪网>>网络学院>>编程开发>>JAVA教程>>JAVA网络编程

Java网络编程从入门到精通(18):Socket类的getter和setter方法(2)

    二、用于获得和设置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 ));
                System.out.println(
" socket2.getReuseAddress(): "
                        
+  socket2.getReuseAddress());
                System.out.println(
" 端口88第二次绑定成功! " );
            }
            
catch  (Exception e1)
            {
                System.out.println(e.getMessage());
            }
        }
    }
}

    上面的代码的运行结果如下:

socket1.getReuseAddress():true
error:Address already in use: JVM_Bind
socket2.getReuseAddress():true
端口88第二次绑定成功!

    使用SO_REUSEADDR选项时有两点需要注意:

    1.  必须在调用bind方法之前使用setReuseAddress方法来打开SO_REUSEADDR选项。因此,要想使用SO_REUSEADDR选项,就不能通过Socket类的构造方法来绑定端口。

    2.  必须将绑定同一个端口的所有的Socket对象的SO_REUSEADDR选项都打开才能起作用。如在例程4-12中,socket1和socket2都使用了setReuseAddress方法打开了各自的SO_REUSEADDR选项。

共4页 首页 上一页 1 2 3 4 下一页 尾页 跳转到
相关内容
赞助商链接