方法阻塞,方法一直阻塞,意味着这个程序卡在这里,一直不向下运行。知道这个阻塞方法执行完毕,有返回值。程序才继续向下执行

方法阻塞,方法一直阻塞,意味着这个程序卡在这里,一直不向下运行。知道这个阻塞方法执行完毕,有返回值。程序才继续向下执行.

  1. while (true) {
  2. // 当注册事件到达时,方法返回,否则该方法会一直阻塞
  3. selector.select();  //这里将一直阻塞,程序不会向下执行。直到这个方法执行完,有返回值后

2.// 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理

NIO SERVER
NIO SERVERpackage com.anders.selector;  

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;  

public class NIOServer {
    // 通道管理器
    private Selector selector;  

    public void initServer(int port) throws Exception {
        // 获得一个ServerSocket通道
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        // 设置通道为 非阻塞
        serverChannel.configureBlocking(false);
        // 将该通道对于的serverSocket绑定到port端口
        serverChannel.socket().bind(new InetSocketAddress(port));
        // 获得一耳光通道管理器
        this.selector = Selector.open();  

        // 将通道管理器和该通道绑定,并为该通道注册selectionKey.OP_ACCEPT事件
        // 注册该事件后,当事件到达的时候,selector.select()会返回,
        // 如果事件没有到达selector.select()会一直阻塞  

        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    }  

    // 采用轮训的方式监听selector上是否有需要处理的事件,如果有,进行处理
    public void listen() throws Exception {
        System.out.println("start server");
        // 轮询访问selector
        while (true) {
            // 当注册事件到达时,方法返回,否则该方法会一直阻塞
            selector.select();
            // 获得selector中选中的相的迭代器,选中的相为注册的事件
            Iterator ite = this.selector.selectedKeys().iterator();
            while (ite.hasNext()) {
                SelectionKey key = (SelectionKey) ite.next();
                // 删除已选的key 以防重负处理
                ite.remove();
                // 客户端请求连接事件
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    // 获得和客户端连接的通道
                    SocketChannel channel = server.accept();
                    // 设置成非阻塞
                    channel.configureBlocking(false);
                    // 在这里可以发送消息给客户端
                    channel.write(ByteBuffer.wrap(new String("hello client").getBytes()));
                    // 在客户端 连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限
                    channel.register(this.selector, SelectionKey.OP_READ);
                    // 获得了可读的事件  

                } else if (key.isReadable()) {
                    read(key);
                }  

            }
        }
    }  

    // 处理 读取客户端发来的信息事件
    private void read(SelectionKey key) throws Exception {
        // 服务器可读消息,得到事件发生的socket通道
        SocketChannel channel = (SocketChannel) key.channel();
        // 穿件读取的缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(10);
        channel.read(buffer);
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("server receive from client: " + msg);
        ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
        channel.write(outBuffer);
    }  

    public static void main(String[] args) throws Throwable {
        NIOServer server = new NIOServer();
        server.initServer(8989);
        server.listen();
    }
}  

Client

package com.anders.selector;  

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.SocketChannel;
import java.util.Iterator;  

public class NIOClient {  

    // 通道管理器
    private Selector selector;  

    /**
     * * // 获得一个Socket通道,并对该通道做一些初始化的工作 * @param ip 连接的服务器的ip // * @param port
     * 连接的服务器的端口号 * @throws IOException
     */
    public void initClient(String ip, int port) throws IOException { // 获得一个Socket通道
        SocketChannel channel = SocketChannel.open(); // 设置通道为非阻塞
        channel.configureBlocking(false); // 获得一个通道管理器
        this.selector = Selector.open(); // 客户端连接服务器,其实方法执行并没有实现连接,需要在listen()方法中调
        // 用channel.finishConnect();才能完成连接
        channel.connect(new InetSocketAddress(ip, port));
        // 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_CONNECT事件。
        channel.register(selector, SelectionKey.OP_CONNECT);
    }  

    /**
     * * // 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理 * @throws // IOException
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public void listen() throws Exception { // 轮询访问selector
        while (true) {
            // 选择一组可以进行I/O操作的事件,放在selector中,客户端的该方法不会阻塞,
            // 这里和服务端的方法不一样,查看api注释可以知道,当至少一个通道被选中时,
            // selector的wakeup方法被调用,方法返回,而对于客户端来说,通道一直是被选中的
            selector.select(); // 获得selector中选中的项的迭代器
            Iterator ite = this.selector.selectedKeys().iterator();
            while (ite.hasNext()) {
                SelectionKey key = (SelectionKey) ite.next(); // 删除已选的key,以防重复处理
                ite.remove(); // 连接事件发生
                if (key.isConnectable()) {
                    SocketChannel channel = (SocketChannel) key.channel(); // 如果正在连接,则完成连接
                    if (channel.isConnectionPending()) {
     channel.finishConnect();
                    } // 设置成非阻塞
    channel.configureBlocking(false);
                    // 在这里可以给服务端发送信息哦
                    channel.write(ByteBuffer.wrap(new String("hello server!").getBytes()));
                    // 在和服务端连接成功之后,为了可以接收到服务端的信息,需要给通道设置读的权限。
                    channel.register(this.selector, SelectionKey.OP_READ); // 获得了可读的事件
                } else if (key.isReadable()) {
                    read(key);
                }
            }
        }
    }  

    private void read(SelectionKey key) throws Exception {
        SocketChannel channel = (SocketChannel) key.channel();
        // 穿件读取的缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(10);  

        channel.read(buffer);
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("client receive msg from server:" + msg);
        ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
        channel.write(outBuffer);  

    }  

    /**
     * * // 启动客户端测试 * @throws IOException
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        NIOClient client = new NIOClient();
        client.initClient("localhost", 8989);
        client.listen();
    }
}  
时间: 2024-12-30 03:48:46

方法阻塞,方法一直阻塞,意味着这个程序卡在这里,一直不向下运行。知道这个阻塞方法执行完毕,有返回值。程序才继续向下执行的相关文章

关于socket阻塞与非阻塞情况下的recv、send、read、write返回值

原帖:http://blog.csdn.net/nodeathphoenix/article/details/23284157 一,管道读写规则 当没有数据可读时 O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止. O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN. 当管道满的时候 O_NONBLOCK disable: write调用阻塞,直到有进程读走数据 O_NONBLOCK enable:调用返回-1,er

windows下编写的Shell脚本在Linux下运行错误的解决方法

出现这种错误的原因:CR/LF问题,在dos/window下按一次回车键实际上输入的是“回车(CR)”和“换行(LF)”,而Linux/unix下按一次回车键只输入“换行(LF)”,所以修改的sh文件在每行都会多了一个CR,所以Linux下运行时就会报错找不到命令. 两种解决方法: 1.将格式转换为UNIX,“编辑->格式转换(CR/LF)->UNIX”,这样Linux下就能按unix的格式保存文件 2.在vim中,输入:set ff=unix,然后:wq,同样也是转换成unix的格式 cat

关于socket阻塞与非阻塞情况下的recv、send、read、write返回值(转载)

1.阻塞模式与非阻塞模式下recv的返回值各代表什么意思?有没有区别?(就我目前了解阻塞与非阻塞recv返回值没有区分,都是 <0:出错,=0:连接关闭,>0接收到数据大小,特别:返回值 <0时并且(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)的情况下认为连接是正常的,继续接收.只是阻塞模式下recv会阻塞着接收数据,非阻塞模式下如果没有数据会返回,不会阻塞着读,因此需要 循环读取 2.阻塞模式与非阻塞模式下writ

当对函数的返回值有多种需求时(执行是否成功,及业务数据的返回值),可采用的方法

(1)bool+out (2)返回值为实体模式: public  class DiskResult    {        private bool successful;        private string result;        private string errorMessage; public bool Successful        {            get            {                return successful;    

Java加载jar文件并调用jar文件当中有参数和返回值的方法

在工作当中经常遇到反编译后的jar文件,并要传入参数了解其中的某些方法的输出,想到Java里面的反射可以实现加载jar文件并调用其中的方法来达到自己的目的.就写了个Demo代码. 以下的类可以编译生成hello.jar文件. 1 package org.lele.fatpanda; 2 3 public class Util 4 { 5 public static String myName; 6 /* 7 * 无参数,无返回值的方法. 8 */ 9 public static void get

C# 7.0 新特性1: 基于Tuple的“多”返回值方法

本文基于Roslyn项目中的Issue:#347 展开讨论. 回顾 首先,提出一个问题,C#中,如何使一个方法可返回"多个"返回值? 我们先来回顾一下C#6.0 及更早版本的做法. 在C#中,通常我们有以下4种方式使一个方法返回多条数据. 使用 KeyValue 组合 1 static void Main(string[] args) 2 { 3 int int1 = 15; 4 int int2 = 25; 5 var result = Add_Multiply(int1, int2

iOS实现调用动态方法名有返回值的方法

需求: 有10个类, 每个类里头都有n个方法(前提是方法名有规律可循,比如 setA0,setA1-)  如果挨个去init类, 然后挨个调用方法,这样你一天就不用干别的了 简单的解决方法可以参考这个: iPhone开发中,动态调用类和方法 虽然说performSelector有返回值,但是在ARC下会有警告,因为方法名是动态的,系统并不知道返回值是什么样的类型.解决方法可以见这篇文章: "performSelector may cause a leak because its selector

JS数组方法的的返回值和是否改变该数组总结

concat() 方法 concat() 方法用于连接两个或多个数组. 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本. 返回值 返回一个新的数组.该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的.如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组. join() 方法  不改变原数组 join() 方法用于把数组中的所有元素放入一个字符串. 元素是通过指定的分隔符进行分隔的. 返回值 返回一个字符串.该字符串是通过把

转载---编写高质量代码:改善Java程序的151个建议(第3章:类、对象及方法___建议47~51)

阅读目录 建议47:在equals中使用getClass进行类型判断 建议48:覆写equals方法必须覆写hashCode方法 建议49:推荐覆写toString方法 建议50:使用package-info类为包服务 建议51:不要主动进行垃圾回收 回到顶部 建议47:在equals中使用getClass进行类型判断 本节我们继续讨论覆写equals的问题,这次我们编写一个员工Employee类继承Person类,这很正常,员工也是人嘛,而且在JavaBean中继承也很多见,代码如下: 1 p