socket通道

47 篇文章 0 订阅

1)新的 socket 通道类可以运行非阻塞模式并且是可选择的,可以激活大程序(如

网络服务器和中间件组件)巨大的可伸缩性和灵活性。本节中我们会看到,再也没有

为每个 socket 连接使用一个线程的必要了,也避免了管理大量线程所需的上下文交换

开销。借助新的 NIO 类,一个或几个线程就可以管理成百上千的活动 socket 连接了

并且只有很少甚至可能没有性能损失。所有的 socket 通道类(DatagramChannel、

SocketChannel 和 ServerSocketChannel)都继承了位于 java.nio.channels.spi 包中

的 AbstractSelectableChannel。这意味着我们可以用一个 Selector 对象来执行

socket 通道的就绪选择(readiness selection)。

2)请注意 DatagramChannel 和 SocketChannel 实现定义读和写功能的接口而

ServerSocketChannel 不实现。ServerSocketChannel 负责监听传入的连接和创建新

的 SocketChannel 对象,它本身从不传输数据。

3)在我们具体讨论每一种 socket 通道前,您应该了解 socket 和 socket 通道之间

的关系。通道是一个连接 I/O 服务导管并提供与该服务交互的方法。就某个 socket 而

言,它不会再次实现与之对应的 socket 通道类中的 socket 协议 API,而 java.net 中

已经存在的 socket 通道都可以被大多数协议操作重复使用。

全部 socket 通道类(DatagramChannel、SocketChannel 和

ServerSocketChannel)在被实例化时都会创建一个对等 socket 对象。这些是我们所

熟悉的来自 java.net 的类(Socket、ServerSocket 和 DatagramSocket),它们已

经被更新以识别通道。对等 socket 可以通过调用 socket( )方法从一个通道上获取。

此外,这三个 java.net 类现在都有 getChannel( )方法。

4)要把一个 socket 通道置于非阻塞模式,我们要依靠所有 socket 通道类的公有

超级类:SelectableChannel。就绪选择(readiness selection)是一种可以用来查

询通道的机制,该查询可以判断通道是否准备好执行一个目标操作,如读或写。非阻

塞 I/O 和可选择性是紧密相连的,那也正是管理阻塞模式的 API 代码要在

SelectableChannel 超级类中定义的原因。

设置或重新设置一个通道的阻塞模式是很简单的,只要调用 configureBlocking( )方

法即可,传递参数值为 true 则设为阻塞模式,参数值为 false 值设为非阻塞模式。可

以通过调用 isBlocking( )方法来判断某个 socket 通道当前处于哪种模式。

AbstractSelectableChannel.java 中实现的 configureBlocking()方法如下:

 

非阻塞 socket 通常被认为是服务端使用的,因为它们使同时管理很多 socket 通道变

得更容易。但是,在客户端使用一个或几个非阻塞模式的 socket 通道也是有益处的,

例如,借助非阻塞 socket 通道,GUI 程序可以专注于用户请求并且同时维护与一个或

多个服务器的会话。在很多程序上,非阻塞模式都是有用的。

偶尔地,我们也会需要防止 socket 通道的阻塞模式被更改。API 中有一个

blockingLock( )方法,该方法会返回一个非透明的对象引用。返回的对象是通道实现

修改阻塞模式时内部使用的。只有拥有此对象的锁的线程才能更改通道的阻塞模式。

下面分别介绍这 3 个通道

ServerSocketChannel

ServerSocketChannel 是一个基于通道的 socket 监听器。它同我们所熟悉的

java.net.ServerSocket 执行相同的任务,不过它增加了通道语义,因此能够在非阻塞

模式下运行。

由于 ServerSocketChannel 没有 bind()方法,因此有必要取出对等的 socket 并使用

它来绑定到一个端口以开始监听连接。我们也是使用对等 ServerSocket 的 API 来根

据需要设置其他的 socket 选项。

同 java.net.ServerSocket 一样,ServerSocketChannel 也有 accept( )方法。一旦创

建了一个 ServerSocketChannel 并用对等 socket 绑定了它,然后您就可以在其中一

个上调用 accept()。如果您选择在 ServerSocket 上调用 accept( )方法,那么它会同

任何其他的 ServerSocket 表现一样的行为:总是阻塞并返回一个 java.net.Socket 对

象。如果您选择在 ServerSocketChannel 上调用 accept( )方法则会返回

SocketChannel 类型的对象,返回的对象能够在非阻塞模式下运行。

换句话说:

ServerSocketChannel 的 accept()方法会返回 SocketChannel 类型对象,

SocketChannel 可以在非阻塞模式下运行。

其它 Socket 的 accept()方法会阻塞返回一个 Socket 对象。如果

ServerSocketChannel 以非阻塞模式被调用,当没有传入连接在等待时,

ServerSocketChannel.accept( )会立即返回 null。正是这种检查连接而不阻塞的能力

实现了可伸缩性并降低了复杂性。可选择性也因此得到实现。我们可以使用一个选择

器实例来注册 ServerSocketChannel 对象以实现新连接到达时自动通知的功能。

以下代码演示了如何使用一个非阻塞的 accept( )方法:

@Test
public void serverSocketTest() throws Exception {
    int port = 1001;
    ByteBuffer wrap = ByteBuffer.wrap("SocketDemoTest".getBytes(StandardCharsets.UTF_8));

    ServerSocketChannel open = ServerSocketChannel.open();
    //绑定
    open.socket().bind(new InetSocketAddress(port));
    //设置非阻塞模式
    open.configureBlocking(false);

    while (true) {
        LOGGER.info("waiting connection~~~");
        SocketChannel accept = open.accept();
        if (accept == null) {
            LOGGER.info("null");
            Thread.sleep(2000);
        } else {
            LOGGER.info("incoming connection from :{}", accept.getRemoteAddress());
            //指针0
            wrap.rewind();
            accept.write(wrap);
            accept.close();
        }
    }

}

(1)打开 ServerSocketChannel

通过调用 ServerSocketChannel.open() 方法来打开 ServerSocketChannel.

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

2)关闭 ServerSocketChannel

通过调用 ServerSocketChannel.close() 方法来关闭 ServerSocketChannel.

serverSocketChannel.close();

3)监听新的连接

通过 ServerSocketChannel.accept() 方法监听新进的连接。当 accept()方法返回时

候,它返回一个包含新进来的连接的 SocketChannel。因此, accept()方法会一直阻塞

到有新连接到达。

通常不会仅仅只监听一个连接,在 while 循环中调用 accept()方法. 如下面的例子:

 4)阻塞模式

会在 SocketChannel sc = ssc.accept();这里阻塞住进程。

(5)非阻塞模式

ServerSocketChannel 可以设置成非阻塞模式。在非阻塞模式下,accept() 方法会立

刻返回,如果还没有新进来的连接,返回的将是 null。 因此,需要检查返回的

SocketChannel 是否是 null.如:

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Diligently_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值