socket(二)--Tcp同步非阻塞式

本文介绍了Java NIO中的ServerSocketChannel、SocketChannel、Selector和Buffer等关键类,阐述了如何利用这些类实现TCP同步非阻塞通信。通过示例展示了服务端和客户端的代码实现,强调了在实际应用中写事件通常不需要注册,以避免不必要的CPU空转。
摘要由CSDN通过智能技术生成

socket(二)–Tcp同步非阻塞式

一、简介

同步阻塞式通信,工作线程一次只能处理一个连接请求,服务完成后,才可处理下一个连接请求。针对这种情况,有两种解决方案:

  1. 采用多线程编程,即是:主线程负责接收连接请求,连接成功后,服务的过程(即是数据交互的过程)交由其它多个线程处理;
  2. 采用非阻塞式通信,主要由java.nio包中的类实现。实现方式是,工作线程采用轮询的方式,不停监控连接事件、读事件、写事件,当某事件发生时,就进行相应事件的处理。

这里对第2种方式的tcp同步非阻塞通信方式进行介绍。

二、关键类

2.1 ServerSocketChannel

ServerSocketChannel是ServerSocket的替代类,支持阻塞和非阻塞两种方式,默认是阻塞式的。

2.2 SocketChannel

SocketChannel是Socket的替代类,同样支持阻塞和非阻塞两种式,默认是阻塞式的。

2.3 Selector

监听器,用于监听连接就绪事件、读就绪事件、写就绪事件。方法有:

keys():注册的所有事件;
selectedKeys():已经发生的事件;
2.4 SelectionKey

事件的句柄,当某事件的selectionKey对象位于Selector对象的selectedKeys()集合中时,表示事件发生。
具体事件有:

SelectionKey.OP_ACCEPT:接收连接就绪事件,表示至少有一个连接进来;
SelectionKey. OP_CONNECT:连接就绪事件,表示与服务连接成功;
SelectionKey.OP_READ:读就绪事件,表示输入流有数据了,可进行数据读;
SelectionKey.OP_WRITE:写就绪事件,表示可以向输出流写数据了。
2.5 Buffer

由于数据输入输出比较耗时,buffer用于缓冲,buffer有三个属性:

capacity:即容量,表示缓冲区可以保存多少数据;
limit:即极限,表示当前缓冲区的终点,读取操作只有在极限范围内。极限可以修改,可用于重用缓冲区,是非负整数,不能大于容量;
position:即位置,表示下一次读写的位置,是非负整数,不能大于极限。

另外buffer提供了改变上述属性的方法:

clear():极限设为容量,位置设为0;
flip():极限设为位置,位置设为0;
rewind():位置设为0;
compact():压缩,即删除0到位置间的数据,然后将位置与极限之前的数据移动,使位置再次为0;

三、示例

这里以创建服务端和客户端,两者可自由发送消息给对方为例。解释请查看注释。

3.1 服务端代码
import org.apache.commons.lang.StringUtils;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

public class TcpNioServerSocketChannelPaperMain {
   
    public static void main(String[] args) throws Exception {
   
        //指定端口
        int port = 7001;
        //指定编码
        Charset charset = Charset.forName("utf-8");

        //创建服务
        ServerSocketChannel server = ServerSocketChannel.open();
        //指定为非阻塞,默认为阻塞式
        server.configureBlocking(false);
        //绑定端口
        server.socket().bind(new InetSocketAddress(port));
        System.out.println("服务启动");

        //读缓冲
        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
        //写缓冲

        //创建监听器
        Selector selector = Selector.open();
        //注册连接就绪事件
        server.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
   
            //阻塞等待最多1000毫秒获取事件,有事件时会立即返回,另外还有select()和selectNow().分别表示一直等和立即返回
            if (selector.select(1000) < 1) {
   
                continue;
            }

            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> it = keys.iterator();
            while (it.hasNext()) {
   
                SelectionKey key = it.next();
                it
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值