JAVA NET PROGRAM LEARN NOTE

构造ServerSocket

ServerSocket的构造方法有一下几种重载形式:

ServerSocket()throws IOException

ServerSocket(int port)throws IOException

ServerSocket(int port,int backlog)throws IOException

ServerSocket(int port,int backlog,InetAddress ibndAddr)throws IOException

参数port指定服务器要绑定的端口(服务器要监听的端口),参数backlog指定客户连接请求队列的长度,参数bindAddr指定服务器要绑定的IP地址。

无法绑定port端口会抛出IOException,确切地抛出BindException,是IOException的子类。BindException一般是由以下原因造成的:

端口已经被其他服务器进程占用;

在某些操作系统中,如果没有以超级用户的身份来运行服务器程序,那么操作系统不允许服务器绑定到1~1023之间的端口。

如果把参数port设为0,表示由操作系统来为服务器分配一个任意可用的端口。由操作系统分配的端口也称为匿名端口。

ServerSocket构造方法的backlog参数用来显示设置连接请求队列的长度,它将覆盖操作系统限定的队列最大长度。值得注意得是,在以下几种情况中,仍然会采用操作系统限定的队列的最大长度:

backlog参数的值大于操作系统限定的队列的最大长度;

backlog参数的值小于或等于0;

在ServerSocket构造方法中没有设置backlog参数。


默认构造方法的作用

ServerSocket有一个不带参数的构造方法。通过该方法创建的ServerSocket不与任何端口绑定,接下来还需要通过bind()方法与特定端口绑定。

这个默认构造方法的用途是,允许服务器在绑定到特定端口之前,先设置ServerSocket的一些选项。因为一旦服务器与特定端口绑定,有些选项就不能在改变了。SO_REUSEADDR选项必须在服务器绑定端口之前设置才有效。

ServerSocket的isBound()方法判断ServerSocket是否已经与一个端口绑定,只要ServerSocket已经与一个端口绑定,即使它已经被关闭,isBound()方法也会放回true。

如果需要确定一个ServerSocket已经与特定端口绑定,并且还没有被关闭,则可以采用以下方式:

boolean isOpen = serverSocket.isBound()&&!serverSocket.isClosed();


ServerSocket的以下两个get方法分别获得服务器绑定的IP地址,以及绑定的端口:

public InetAddress getInetAddress()

public int getLocalPort()

ServerSocket选项

ServerSocket有以下3个选项:

SO_TIMEOUT:表示等待客户连接超时时间。

设置该选项:public void setSoTimeout(int timeout)throws SocketException

读取该选项:public int getSoTimeout()throws IOException

如果SO_TIMEOUT的值为0,表示永远不会超时,这是SO_TIMEOUT的默认值。

SO_REUSEADDR:表示是否允许重用服务器所绑定的地址。

设置该选项:public void setResuseAddress(boolean on )throws SocketException

读取该选项:public boolean getResuseAddress() throws SocketException

当ServerSocket关闭时,如果网络上还有发送到这个ServerSocket的数据,这个ServerSocket不会立刻释放本地端口,而是会等待一段时间,确保接收到了网络上发送过来的延迟数据,然后再释放端口。

serverSocket.setReuseAddress(true)方法必须在ServerSocket还没有绑定到一个本地端口之前调用,否则执行serverSocket。setResuseAddress(true)方法无效。此外,两个共用同一个端口的进程必须都调用serverSocket.setResuseAddress(true)方法,才能使得一个进程关闭ServerSocket后,另一个进程的ServerSocket还能够立刻重用相同端口。

SO_RCVBUF:表示接受数据的缓冲区的大小。

设置该选项: public void setReceiveBufferSize(int size) throws SocketException

读取该选项:public int getReceiveBufferSize()throws SocketException

无论在ServerSocket绑定到特定端口之前或之后,调用setReceiveBufferSize()方法都有效。例外情况下是如果要设置大于64Kb的缓冲区,则必须在SErverSocket绑定到特定端口之前进行设置才有效。

设定连接时间、延迟和带宽的相对重要性

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


创建多线程的服务器

可以用并发性能来衡量一个服务器同时相应多个客户的能力。一个具有好的并发性能的服务器,必须符合两个条件:

能同时接收并处理多个客户连接;

对于每个客户,都会迅速给予响应。

服务器同时处理的客户连接数目越多,并且对每个客户做出相应的速度越快,就表明并发性能越高。

为每个客户分配一个工作线程

public void service(){
    while(true){
        Socket socket = null;
        try{
             socket = serverSocket.accept();  //接收客户连接
             Thread workThread = new Thread(new Handler(socket));     // 创建一个工作线程
             workThread.start();    //启动工作线程      
         }catch(IOException e){
              e.printStackTrace();
          }
      }
   }
以上工作线程workThread执行Handler的run()方法。Handler类实现了Runnable接口,它的run()方法负责与单个客户通信,与客户通信结束后,就会断开连接,执行Handler的run()方法的工作线程也会自然终止。

创建线程池

线程池具有以下优点:

减少创建和销毁线程的次数,每个工作线程都可以一直被重用,能执行多个任务。

可以根据系统的承载能力,方便地调整线程池中线程的数目,防止因为消耗过量系统资源而导致系统崩溃。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值