开发者社区> 问答> 正文

java socket 的通信问题?

客户端和服务端分别在两个局域网内怎么通过java socket 通信?

展开
收起
蛮大人123 2016-06-06 10:55:52 4705 0
1 条回答
写回答
取消 提交回答
  • 我说我不帅他们就打我,还说我虚伪
    // 创建一个选择器,可用close()关闭,isOpen()表示是否处于打开状态,他不隶属于当前线程
    Selector selector = Selector.open();
    // 创建ServerSocketChannel,并把它绑定到指定端口上
    ServerSocketChannel server = ServerSocketChannel.open();
    server.bind(new InetSocketAddress("127.0.0.1", 7777));
    // 设置为非阻塞模式, 这个非常重要
    server.configureBlocking(false);
    // 在选择器里面注册关注这个服务器套接字通道的accept事件
    // ServerSocketChannel只有OP_ACCEPT可用,OP_CONNECT,OP_READ,OP_WRITE用于SocketChannel
    server.register(selector, SelectionKey.OP_ACCEPT);
    while (true) {
        // 测试等待事件发生,分为直接返回的selectNow()和阻塞等待的select(),另外也可加一个参数表示阻塞超时
        // 停止阻塞的方法有两种: 中断线程和selector.wakeup(),有事件发生时,会自动的wakeup()
        // 方法返回为select出的事件数(参见后面的注释有说明这个值为什么可能为0).
        // 另外务必注意一个问题是,当selector被select()阻塞时,其他的线程调用同一个selector的register也会被阻塞到select返回为止
        // select操作会把发生关注事件的Key加入到selectionKeys中(只管加不管减)
        if (selector.select() == 0) { //
            continue;
        }
    
        // 获取发生了关注时间的Key集合,每个SelectionKey对应了注册的一个通道
        Set<SelectionKey> keys = selector.selectedKeys();
        // 多说一句selector.keys()返回所有的SelectionKey(包括没有发生事件的)
        for (SelectionKey key : keys) {
            // OP_ACCEPT 这个只有ServerSocketChannel才有可能触发
            if (key.isAcceptable()) {
                // 得到与客户端的套接字通道
                SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
                // 同样设置为非阻塞模式
                channel.configureBlocking(false);
                // 同样将于客户端的通道在selector上注册,OP_READ对应可读事件(对方有写入数据),可以通过key获取关联的选择器
                channel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(1024));
            }
            // OP_READ 有数据可读
            if (key.isReadable()) {
                SocketChannel channel = (SocketChannel) key.channel();
                // 得到附件,就是上面SocketChannel进行register的时候的第三个参数,可为随意Object
                ByteBuffer buffer = (ByteBuffer) key.attachment();
                // 读数据 这里就简单写一下,实际上应该还是循环读取到读不出来为止的
                channel.read(buffer);
                // 改变自身关注事件,可以用位或操作|组合时间
                key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
            }
            // OP_WRITE 可写状态 这个状态通常总是触发的,所以只在需要写操作时才进行关注
            if (key.isWritable()) {
                // 写数据掠过,可以自建buffer,也可用附件对象(看情况),注意buffer写入后需要flip
                // ......
                // 写完就吧写状态关注去掉,否则会一直触发写事件
                key.interestOps(SelectionKey.OP_READ);
            }
    
            // 由于select操作只管对selectedKeys进行添加,所以key处理后我们需要从里面把key去掉
            keys.remove(key);
        }
    }

    此为服务器端代码。

    2019-07-17 19:27:53
    赞同 1 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
Spring Cloud Alibaba - 重新定义 Java Cloud-Native 立即下载
The Reactive Cloud Native Arch 立即下载
JAVA开发手册1.5.0 立即下载