客户端Socket与服务端ServerSocket串联实现网络通信

作者:Q.E.D. 时间:2023-08-11 00:01:17 

引导语

上一小节我们学习了 Socket,本文我们来看看服务端套接字 API:ServerSocket,本文学习完毕之后,我们就可以把客户端 Socket 和服务端 ServerSocket 串联起来,做一个真实的网络通信的 demo 了。

1、类属性

ServerSocket 的主要作用,是作为服务端的套接字,接受客户端套接字传递过来的信息,并把响应回传给客户端,其属性非常简单,如下:

private boolean created = false;// 已创建
private boolean bound = false;// 绑定
private boolean closed = false;// 已关闭
// 底层的功能都依靠 SocketImpl 来实现
private SocketImpl impl;

ServerSocket 和 Socket 一样,底层都是依靠 SocketImpl 的能力,而 SocketImpl 底层能力的实现基本上都是 native 方法实现的。

2、初始化

初始化大概可以分成两类:无参构造器和有参构造器。

无参构造器做的事情比较简单,只指定了 SocketImpl 为 SocksSocketImpl 类;有参构造器有几种初始化的形式,我们一起来看一下参数最多的构造器的源码。

public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
   // 默认是 SocksSocketImpl 实现
   setImpl();
   // 端口必须大于 0,小于 65535
   if (port < 0 || port > 0xFFFF)
       throw new IllegalArgumentException(
                  "Port value out of range: " + port);
   // 最大可连接数如果小于1,那么采取默认的 50
   if (backlog < 1)
     backlog = 50;
   try {
       // 底层 navtive 方法
       bind(new InetSocketAddress(bindAddr, port), backlog);
   } catch(SecurityException e) {
       close();
       throw e;
   } catch(IOException e) {
       close();
       throw e;
   }
}

入参 port 指的是 ServerSocket 需要绑定本地那个端口。

入参 backlog 指的是服务端接受客户端连接队列的最大长度,这里需要注意的是,这里并不是限制客户端连接的个数,我们在 JDK8 版本下做过实验,我们把服务端的 backlog 设置成 1,并且变慢服务端的处理速度,当服务端并发请求过来时,并不是第二个请求过来就拒绝连接,我们在实际工作中,最好也不要用 backlog 来限制客户端连接的个数。

还有点需要注意的是 backlog 小于 1 时,backlog 会被设置成默认的 50。

入参 InetAddress 表示 ip 地址。

3、bind

bind 方法主要作用是把 ServerSocket 绑定到本地的端口上,只有当我们使用无参构造器初始化 ServerSocket 时,才会用到这个方法,如果使用有参构造器的话,在初始化时就已经绑定到本地的端口上了。

配合无参构造器,一般我们这么用:

// 进行初始化
ServerSocket serverSocket = new ServerSocket();
// 进行绑定
serverSocket.bind(new InetSocketAddress("localhost", 7007));

4、accept

accept 方法主要是用来 ServerSocket 接受来自客户端的套接字的,如果此时没有来自客户端的请求时,该方法就会一直阻塞,如果有通过 setSoTimeout 方法设置超时时间,那么 accept 只会在超时间内阻塞,过了超时时间就会抛出异常。

bind 和 accept 方法底层都是 native 方法实现,我们就不看源码了。

5、面试题

5.1、说说你对 Socket 和 ServerSocket 的理解?

答:两者我们都可以称为套接字,底层基于 TCP/UDP 协议,套接字对底层协议进行了封装,让我们使用时更加方便,Socket 常被使用在客户端,用于向服务端请求数据和接受响应,ServerSocket 常用于在服务端,用于接受客户端的请求并进行处理,两者其底层使用都是依靠 SocketImpl 的子类的 native 方法。

5.2、说说对 SocketOptions 中的 SO_TIMEOUT 的理解?

答:SocketOptions 类有很多属性设置,比如 SO_TIMEOUT 、SO_LINGER 等等,这些问题说一下自己的理解即可,可以参考 《Socket 源码及面试题》 中对各种属性的解析。

5.3、在构造 Socket 的时候,我可以选择 TCP 或 UDP 么?应该如何选择?

答:可以的,Socket 有三个参数的构造器,第三个参数表示你想使用 TCP 还是 UDP。

5.4、TCP 有自动检测服务端是否存活的机制么?有没有更好的办法?

答:有的,我们可以通过 setKeepAlive 方法来激活该功能,如果两小时内,客户端和服务端的套接字之间没有任何通信,TCP 会自动发送 keepalive 探测给服务端,预测服务端有三种情况:

  • 服务端使用预期的 ACK 回复,说明一切正常;

  • 服务端回复 RST,表示服务端处于死机或者重启状态,终止连接;

  • 没有得到服务端的响应(会尝试多次),表示套接字已经关闭了。

但我们并不建议使用这种方式,我们可以自己起一个定时任务,定时的访问服务端的特殊接口,如果服务端返回的数据和预期一致,说明服务端是存活的。

来源:https://blog.csdn.net/qq_34272760/article/details/120662058

标签:Socket,ServerSocket,网络通信
0
投稿

猜你喜欢

  • Java 二分法检索算法代码实现详解

    2022-01-05 19:13:24
  • Spring-boot JMS 发送消息慢的解决方法

    2023-02-06 07:50:54
  • Android开发组件化架构设计原理到实战

    2023-06-14 12:51:13
  • C语言时间函数之strftime()详解

    2023-06-26 02:42:32
  • Java 中责任链模式实现的三种方式

    2023-11-08 14:32:31
  • 详解kotlin中::双冒号的使用

    2022-09-04 10:17:23
  • 安卓(Android)开发之自定义饼状图

    2022-04-06 11:13:11
  • SpringBoot2整合activiti6环境搭建过程解析

    2023-11-09 02:27:03
  • Android4.2中全屏或者取消标题栏的方法总结

    2023-06-14 16:17:06
  • Android 7.0系统webview 显示https页面空白处理方法

    2021-10-22 09:36:49
  • Android实现抽奖转盘实例代码

    2021-08-22 20:03:35
  • Android开发中Activity的生命周期及加载模式详解

    2021-07-28 02:33:44
  • java面试题之try中含return语句时代码的执行顺序详解

    2023-11-24 07:34:16
  • C#中多态、重载、重写区别分析

    2022-06-27 22:49:55
  • 基于SSM框架+Javamail发送邮件的代码实例

    2022-04-28 11:59:04
  • Android MaterialAlertDialogBuilder修改按钮属性

    2021-12-20 06:56:19
  • java 域对象共享数据的实现

    2022-04-26 15:22:14
  • C#实现简单的汽车租赁系统

    2022-08-17 00:51:52
  • Java解析DICOM图之如何获得16进制数据详解

    2023-06-15 17:37:29
  • Android引入OpenCV的示例

    2022-04-26 08:19:33
  • asp之家 软件编程 m.aspxhome.com