Java网络编程精解之ServerSocket用法详解三

Java网络编程:介绍Java提供的网络编程接口,如Socket,ServerSocket,URL等,并通过实例说明它们的用法。 一、Java网络编程简介 网络编程的重要性 Java网络编程的优点 网络编程中的基本概念和术语介绍(如IP地址、端口号、协议等) 二、Java网络编程核心组件 Socket Socket的定义和作用 创建Socket对象 使用Socket进行通信 Socket类的主要方法与属性 Socket的实例演示 ServerSocket ServerSocket的定义和作用 创建ServerSocket对象 使用ServerSocket接收客户端连接 ServerSocket类的主要方法和属性 ServerSocke 阅读详情
3.7  关闭服务器

前面介绍的EchoServer服务器都无法关闭自身,只有依靠操作系统来强行终止服务器程序。这种强行终止服务器程序的方式尽管简单方便,但是会 导致服务器中正在执行的任务被突然中断。如果服务器处理的任务不是非常重要,允许随时中断,则可以依靠操作系统来强行终止服务器程序;如果服务器处理的任 务非常重要,不允许被突然中断,则应该由服务器自身在恰当的时刻关闭自己。

本节介绍的EchoServer服务器就具有关闭自己的功能。它除了在8000端口监听普通客户程序EchoClient的连接外,还会在8001 端口监听管理程序AdminClient的连接。当EchoServer服务器在8001端口接收到了AdminClient发送的“shutdown” 命令时,EchoServer就会开始关闭服务器,它不会再接收任何新的EchoClient进程的连接请求,对于那些已经接收但是还没有处理的客户连 接,则会丢弃与该客户的通信任务,而不会把通信任务加入到线程池的工作队列中。另外,EchoServer会等到线程池把当前工作队列中的所有任务执行 完,才结束程序。

如例程3-10所示是EchoServer的源程序,其中关闭服务器的任务是由shutdown- Thread线程来负责的。

例程3-10  EchoServer.java(具有关闭服务器的功能) 

package multithread4;

import java.io.*;

import java.net.*;

import java.util.concurrent.*;

public class EchoServer {

private int port=8000;

private ServerSocket serverSocket;

private ExecutorService executorService;     //线程池

private final int POOL_SIZE=4;       //单个CPU时线程池中工作线程的数目



private int portForShutdown=8001;      //用于监听关闭服务器命令的

端口

private ServerSocket serverSocketForShutdown;

private boolean isShutdown=false;     //服务器是否已经关闭

private Thread shutdownThread=new Thread(){     //负责关闭服务器的线程

public void start(){

this.setDaemon(true);       //设置为守护线程(

也称为后台线程)

super.start(); 

}

public void run(){

while (!isShutdown) {

Socket socketForShutdown=null;

try {

socketForShutdown= serverSocketForShutdown.accept();

BufferedReader br = new BufferedReader(

new InputStreamReader(socketForShutdown.getInputStream()));

String command=br.readLine();

if(command.equals("shutdown")){

long beginTime=System.currentTimeMillis(); 

socketForShutdown.getOutputStream().write("服务器正在关闭/r/n".getBytes());

isShutdown=true;

//请求关闭线程池

//线程池不再接收新的任务,但是会继续执行完工作队列中现有的任务

executorService.shutdown();  



//等待关闭线程池,每次等待的超时时间为30秒

while(!executorService.isTerminated())

executorService.awaitTermination(30,TimeUnit.SECONDS); 



serverSocket.close(); //关闭与EchoClient客户通信的ServerSocket 

long endTime=System.currentTimeMillis(); 

socketForShutdown.getOutputStream().write(("服务器已经关闭,"+

"关闭服务器用了"+(endTime-beginTime)+"毫秒/r/n").getBytes());

socketForShutdown.close();

serverSocketForShutdown.close();



}else{

socketForShutdown.getOutputStream().write("错误的命令/r/n".getBytes());

socketForShutdown.close();

}  

}catch (Exception e) {

e.printStackTrace();

} 

} 

}

};

public EchoServer() throws IOException {

serverSocket = new ServerSocket(port);

serverSocket.setSoTimeout(60000);    //设定等待客户连接的超过时间为60秒

serverSocketForShutdown = new ServerSocket(portForShutdown);

//创建线程池

executorService= Executors.newFixedThreadPool( 

Runtime.getRuntime().availableProcessors() * POOL_SIZE);



shutdownThread.start();     //启动负责关闭服务器的线程

System.out.println("服务器启动");

}



public void service() {

while (!isShutdown) {

Socket socket=null;

try {

socket = serverSocket.accept();

//可能会抛出SocketTimeoutException和SocketException

socket.setSoTimeout(60000);     //把等待客户发送数据的超时时间设为60秒 

executorService.execute(new Handler(socket));

//可能会抛出RejectedExecutionException

}catch(SocketTimeoutException e){

//不必处理等待客户连接时出现的超时异常

}catch(RejectedExecutionException e){

try{

if(socket!=null)socket.close();

}catch(IOException x){}

return;

}catch(SocketException e) {

//如果是由于在执行serverSocket.accept()方法时,

//ServerSocket被ShutdownThread线程关闭而导致的异常,就退出service()方法

if(e.getMessage().indexOf("socket closed")!=-1)return;

}catch(IOException e) {

e.printStackTrace();

}

}

}

public static void main(String args[])throws IOException {

new EchoServer().service();

}

}

/** 负责与单个客户通信的任务,代码与3.6.1节的例程3-5的Handler类相同 */

class Handler implements Runnable{…}

shutdownThread线程负责关闭服务器。它一直监听8001端口,如果接收到了AdminClient发送的“shutdown”命令, 就把isShutdown变量设为true。shutdownThread线程接着执行executorService.shutdown()方法,该方 法请求关闭线程池,线程池将不再接收新的任务,但是会继续执行完工作队列中现有的任务。shutdownThread线程接着等待线程池关闭:

while(!executorService.isTerminated())

executorService.awaitTermination(30,TimeUnit.SECONDS);  //等待30秒

当线程池的工作队列中的所有任务执行完毕,executorService.isTerminated()方法就会返回true。

shutdownThread线程接着关闭监听8000端口的ServerSocket,最后再关闭监听8001端口的ServerSocket。

shutdownThread线程在执行上述代码时,主线程正在执行EchoServer的service()方法。

shutdownThread线程一系列操作会对主线程造成以下影响。

◆如果shutdownThread线程已经把isShutdown变量设为true,而主线程正准备执行service()方法的下一轮while(!isShutdown){…}循环时,由于isShutdown变量为true,就会退出循环。

◆如果shutdownThread线程已经执行了监听8 000端口的ServerSocket的close()方法,而主线程正在执行该 ServerSocket的accept()方法,那么该方法会抛出SocketException。EchoServer的service()方法捕获 了该异常,在异常处理代码块中退出service()方法。

◆如果shutdownThread线程已经执行了executorService.shutdown()方法,而主线程正在执行 executorService.execute(…)方法,那么该方法会抛出Rejected- ExecutionException。 EchoServer的service()方法捕获了该异常,在异常处理代码块中退出service()方法。

◆如果shutdownThread线程已经把isShutdown变量设为true,但还没有调用监听8 000端口的ServerSocket 的close()方法,而主线程正在执行ServerSocket的accept()方法,主线程阻塞60秒后会抛出 SocketTimeoutException。在准备执行service()方法的下一轮while(!isShutdown){…}循环时,由于 isShutdown变量为true,就会退出循环。

◆由此可见,当shutdownThread线程开始执行关闭服务器的操作时,主线程尽管不会立即终止,但是迟早会结束运行。

如例程3-11所示是AdminClient的源程序,它负责向EchoServer发送“shutdown”命令,从而关闭EchoServer。

例程3-11  AdminClient.java

package multithread4;

import java.net.*;

import java.io.*;

public class AdminClient{

public static void main(String args[]){

Socket socket=null;

try{

socket=new Socket("localhost",8001);

//发送关闭命令

OutputStream socketOut=socket.getOutputStream();

socketOut.write("shutdown/r/n".getBytes());



//接收服务器的反馈

BufferedReader br = new BufferedReader(

new InputStreamReader(socket.getInputStream()));

String msg=null;

while((msg=br.readLine())!=null)

System.out.println(msg);

}catch(IOException e){

e.printStackTrace();

}finally{

try{

if(socket!=null)socket.close();

}catch(IOException e){e.printStackTrace();}

}

}

}

下面按照以下方式运行EchoServer、EchoClient和AdminClient,以观察EchoServer服务器的关闭过程。EchoClient类的源程序参见本书第1章的1.5.2节的例程1-3。

(1)先运行EchoServer,然后运行AdminClient。EchoServer与AdminClient进程都结束运行,并且在AdminClient的控制台打印如下结果:

服务器正在关闭

服务器已经关闭,关闭服务器用了60毫秒    

(2)先运行EchoServer,再运行EchoClient,然后再运行AdminClient。EchoServer程序不会立即结束,因为 它与EchoClient的通信任务还没有结束。在EchoClient的控制台中输入“bye”, EchoServer、EchoClient和 AdminClient进程都会结束运行。

(3)先运行EchoServer,再运行EchoClient,然后再运行AdminClient。EchoServer程序不会立即结束,因为 它与EchoClient的通信任务还没有结束。不要在EchoClient的控制台中输入任何字符串,过60秒后,EchoServer等待 EchoClient的发送数据超时,结束与EchoClient的通信任务,EchoServer和AdminClient进程结束运行。如果在 EchoClient的控制台再输入字符串,则会抛出“连接已断开”的SocketException。

3.8  小结

在EchoServer的构造方法中可以设定3个参数。

◆参数port:指定服务器要绑定的端口。

◆参数backlog:指定客户连接请求队列的长度。

◆参数bindAddr:指定服务器要绑定的IP地址。 

ServerSocket的accept()方法从连接请求队列中取出一个客户的连接请求,然后创建与客户连接的Socket对象,并将它返回。如 果队列中没有连接请求,accept()方法就会一直等待,直到接收到了连接请求才返回。SO_TIMEOUT选项表示ServerSocket的 accept()方法等待客户连接请求的超时时间,以毫秒为单位。如果SO_TIMEOUT的值为0,表示永远不会超时,这是SO_TIMEOUT的默认 值。可以通过ServerSocket的setSo- Timeout()方法来设置等待连接请求的超时时间。如果设定了超时时间,那么当服务器等待的时 间超过了超时时间后,就会抛出SocketTimeoutException,它是Interrupted- Exception的子类。

许多实际应用要求服务器具有同时为多个客户提供服务的能力。用多个线程来同时为多个客户提供服务,这是提高服务器的并发性能的最常用的手段。本章采用3种方式来重新实现EchoServer,它们都使用了多线程:

(1)为每个客户分配一个工作线程;

(2)创建一个线程池,由其中的工作线程来为客户服务;

(3)利用java.util.concurrent包中现成的线程池,由它的工作线程来为客户服务。

第一种方式需要频繁地创建和销毁线程,如果线程执行的任务本身很简短,那么有可能服务器在创建和销毁线程方面的开销比在实际执行任务上的开销还要 大。线程池能很好地避免这一问题。线程池先创建了若干工作线程,每个工作线程执行完一个任务后就会继续执行下一个任务,线程池减少了创建和销毁线程的次 数,从而提高了服务器的运行性能。

 
C#构建高精度预测模型:从数据预处理到模型部署的实战指南 【代码】C#构建高精度预测模型:从数据预处理到模型部署的实战指南。 阅读详情

相关推荐

计算机图形学入门30:动画与模拟介绍

计算机图形学入门,动画与模拟,物理模拟,质点弹簧系统,运动学,粒子系统,动作捕捉。

YanisWu的博客 1485

Java网络编程精解学习笔记(第三章 serverSocket详解)

1.构造ServerSocket ServerSocket的构造方法有以下几种重载方法: ServerSocket() ServerSocket(int port) ServerSocket(int port, int backlog) ServerSocket(int port, int backlog, InetAddress bindAddr) 参数port表示端口,backlo

cg3410的博客 2048

【Gazebo安装指南】Ubuntu22.04LTS环境下的高效配置与常见问题解决

本文提供了在Ubuntu 22.04 LTS系统上高效安装和配置Gazebo仿真环境的详细指南。针对Gazebo Classic版本,文章对比了通过ROS 2仓库和Ubuntu官方仓库两种主流安装方法,并重点解决了安装过程中常见的软件包定位、模型下载及图形驱动等问题,帮助用户快速搭建稳定的机器人仿真开发环境。

weixin_29279101的博客 437

socket time out

可以设置SocketServer中的setSoTimeout()和Socket中的setSoTimeout() 设置SocketServer中的setSoTimeout(10000),表示服务端启动后,如果10秒内没有内请求这个服务端,超过10秒后服务端将不再处理请求。 但是Socket的setSoTimeout(10000)是什么意思呢?这个超时方法是干什么用的  setSotimeo

kwinters的专栏 4066

深入解析USBlyzer抓包工具:从设备描述符到数据交互实战

本文深入解析了USBlyzer抓包工具在USB协议分析中的应用。从设备描述符的抓取与解读,到设置地址、配置描述符的实战分析,再到数据交互阶段的抓包技巧,文章通过具体案例详细展示了如何使用USBlyzer透视USB总线通信,是排查设备驱动问题、逆向分析通信协议和学习USB规范的实用指南。

weixin_29171087的博客 741

「Unity3D」Addressable版本冲突解析:SBP与Addressables兼容性问题实战指南

本文深入解析Unity3D中Addressable与SBP(Scriptable Build Pipeline)版本冲突问题,提供实战解决方案。当遇到「Build Task CreateBuiltInShadersBundle failed」错误时,可通过版本匹配、临时资源引用或构建参数调整解决。文章详细分析兼容性原理,并给出版本组合指南与最佳实践,帮助开发者高效处理资源构建问题。

weixin_29001683的博客 410

搭建服务器ServerSocket与搭建客户端Socket

ServerSocket 搭建服务器 用于创建服务器 , 创建完毕后,会绑定一个端口号。 ServerSocKet serversocket = new ServerSocket(int port); 创建一个基于TCP/IP协议的服务器,并绑定指定的端口号。 注意:参数port的范围是: 0-65535 (建议1025-65535) 然后此服务器可以等待客户端连接 Socket socket = server.accept(); 此方法会导致线程的阻塞!直到一个新的客户端连接成功,return

weixin_44607024的博客 3467

gtsam 学习十(ISAM2 理论)

翻译自:iSAM2: Incremental Smoothing and Mapping Using the Bayes Tree 摘要 提出了一种新型的贝斯树处理稀疏矩阵,在转化为因子图,可以更好的求解平方根信息和映射问题。 文中提出了三个概念 使用概率密度项进行矩阵分解 介绍如何将矩阵分解转换为贝叶斯数和条件概率密度 基于贝叶斯树提供了一种新的系数非线性优化:ISAM2(进行重新排序和重新线性化,避免了批量更新) 问题描述 文章聚焦与如何用增量实时解决非线性问题, 利用增量即新的测量值实时更新估

weixin_37781153的博客 8409

三. ServerSocket 用法详解(一)

 本篇文章观点和例子来自 《Java网络编程精解》, 作者为孙卫琴, 出版社为电子工业出版社。      在客户/服务器通信模式中, 服务器端需要创建监听端口的 ServerSocket, ServerSocket 负责接收客户连接请求. 本章首先介绍 ServerSocket 类的各个构造方法, 以及成员的用法, 接着介绍服务器如何用多线程来处理与多个客户的通信任务.      本章

lin49940的专栏 4万+

测试人必看!正交表与Allpairs工具对比:如何选择最适合你的组合测试方案?

本文深入对比了正交表、PICT与Allpairs三种主流组合测试方案,帮助测试人员根据项目场景做出最佳选择。文章分析了各自的核心原理、优劣势及适用场景,特别强调了在涉及复杂约束时PICT工具的强大功能,并提供了从原理学习到CI/CD集成的实战选型指南。

weixin_29224309的博客 268

通俗易懂的图解二叉搜索树、AVL树和红黑树

搜索是一种很常见的需求,当数据较多时,如何找到目标对象时,即需要搜索查找。 那么如何快速找到目标呢,最朴素的思想就是暴力查找,一个一个对比。 显然,当数据量增大时,我们需要优化查找方法获取更快的查找速度,我们可以通过维护一个有序数组,从而实现二分查找,查找速度从O(n)降为O(longn)。 但是数组并不便于插入和删除,链表便成为了最好的选择。 既然是采用二分查找,那么不如直接按照查找的步骤维护一种数据结构,于是二叉搜索树出现了。 二叉搜索树的性质为: 若左子树不为空,则左子树上所有节点值都小于根结点值;

暗色光的博客 758

Socket和ServerSocket的简单介绍及例子

一、Socket 类 socket可以使一个应用从网络中读取和写入数据,不同计算机上的两个应用可以通过连接发送和接受字节流,当发送消息时,你需要知道对方的ip和端口,在java中,socket指的是java.net.Socket类。 在java.net.Socket中,可以看到socket有多种构造函数 以public Socket(String host, int port)为例,host为远程机器名称或ip地址,port为端口号。若连接本地的Server,其端口号为8080,可以写成如下格式..

学Java,找哪吒 9802

SAP Business Technology Platform 支持的技术栈

SAP Business Technology Platform(简称 BTP)是 SAP 提供的一个综合技术平台,旨在帮助企业实现业务转型和创新。BTP 融合了数据库管理、应用开发、集成、分析和智能技术,为企业提供从基础架构到端到端应用的全面服务。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1568

java网络编程精解_Java网络编程精解之ServerSocket用法详解三(3)

ServerSocket的accept()方法从连接请求队列中取出一个客户的连接请求,然后创建与客户连接的Socket对象,并将它返回。如果队列中没有连接请求,accept()方法就会一直等待,直到接收到了连接请求才返回。SO_TIMEOUT选项表示ServerSocket的accept()方法等待客户连接请求的超时时间,以毫秒为单位。如果SO_TIMEOUT的值为0,表示永远不会超时,这是SO_...

weixin_39639643的博客 735

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java网络编程精解之ServerSocket用法详解一

第3章 ServerSocket用法详解 第10章 Java语言的反射机制 第13章 基于MVC和RMI的分布 ServerSocket用法详解一 Java语言的反射机制一 基于MVC和RMI的分布式应用一 ServerSocket用法详解二 Java语言的反射机制二 基于M...

轻轻草原 1952

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Java网络编程精解之ServerSocket用法详解一2

3.2  接收和关闭与客户的连接ServerSocket的accept()方法从连接请求队列中取出一个客户的连接请求,然后创建与客户连接的Socket对象,并将它返回。如果队列中没有连接请求,accept()方法就会一直等待,直到接收到了连接请求才返回。接下来,服务器从Socket对象中获得输入流和输出流,就能与客户交换数据。当服务器正在进行发送数据的操作时,如果客户端断开了连接,那么

KEVIN_LONG的专栏 2794

Java网络编程(三)ServerSocket用法浅学

文章目录第三章 ServerSoclet用法解析前言3.1 ServerSocket的构造器3.1.1 端口绑定3.1.2 如何设置客户端的连接请求队列长度3.1.3 设定绑定的IP地址3.1.4 默认构造函数的作用3.2 接收和关闭客户端的连接3.3 关闭ServerSocket3.4 获取ServerSocket的信息3.5 ServerSocket选项3.5.1 SO_TIMEOUT选项3.5.2 SO_RESUEADDR选项3.5.3 SO_RCVBUF选项3.5.4 设定连接时间、延迟、带宽的相对

LH is programming hard 1301

java网络编程精解_Java网络编程精解之ServerSocket用法详解一

在客户/服务器通信模式中,服务器端需要创建监听特定端口的ServerSocket,ServerSocket负责接收客户连接请求。本章首先介绍ServerSocket类的各个构造方法,以及成员方法的用法,接着介绍服务器如何用多线程来处理与多个客户的通信任务。本章提供线程池的一种实现方式。线程池包括一个工作队列和若干工作线程。服务器程序向工作队列中加入与客户通信的任务,工作线程不断从工作队列中取出任务...

weixin_42357054的博客 372

java网络编程精解pdf_Java网络编程精解笔记3:ServerSocket详解

ServerSocket用法详解1.C/S模式中,Server需要创建特定端口的ServerSocket.->其负责接收client连接请求.2.线程池->包括一个工作队列和若干工作线程->工作线程不断的从工作队列中取出任务并执行.-->java.util.concurrent->线程池3.server可利用多线程来处理与多个客户的通信任务.1.构造ServerSoc...

weixin_39642687的博客 191

三. ServerSocket 用法详解(一) .

本篇文章观点和例子来自 《Java网络编程精解》, 作者为孙卫琴, 出版社为电子工业出版社。       在客户/服务器通信模式中, 服务器端需要创建监听端口的 ServerSocket, ServerSocket 负责接收客户连接请求. 本章首先介绍 ServerSocket 类的各个构造方法, 以及成员的用法, 接着介绍服务器如何用多线程来处理与多个客户的通信任务.       本章提

wangxi969696的专栏 1万+

ServerSocket用法详解

在客户/服务器通信模式中,服务器端需要创建监听特定端口的ServerSocket,ServerSocket负责接收客户连接请求。本章首先介绍ServerSocket类的各个构造方法,以及成员方法的用法,接着介绍服务器如何用多线程来处理与多个客户的通信任务。 本章提供线程池的一种实现方式。线程池包括一个工作队列和若干工作线程。服务器程序向工作队列中加入与客户通信的任务,工作线程不断从工作队列中取出

疯狂的猫 8万+

Java网络编程 Socket、ServerSocket 详解,方法介绍及完整代码示例

Java网络编程 Socket、ServerSocket 详解,方法介绍及完整代码示例

csdn_bajie 3805

Java网络编程精解之ServerSocket用法详解二2

在ThreadPool类的构造方法中,会创建并启动若干工作线程,工作线程的数目由构造方法的参数 poolSize决定。WorkThread类表示工作线程,它是ThreadPool类的内部类。工作线程从工作队列中取出一个任务,接着执行该任务, 然后再从工作队列中取出下一个任务并执行它,如此反复。工作线程从工作队列中取任务的操作是由ThreadPool类的getTask()方法实现的,它的处理

KEVIN_LONG的专栏 1614
上一篇: Java网络编程精解之ServerSocket用法详解二2
下一篇: 珍惜我所拥有的,放弃不属于我的!
kevin_long
博客等级 码龄20年 30粉丝 45原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值