`

传统IO与NIO的Socket编程

    博客分类:
  • Java
阅读更多

        网络编程时,我们常见到同步(Sync)和异步(Async),阻塞(blocking)和非阻塞(non-blocking)四种调用模式:

       ①同步:

        客户端发一个调用,再没有得到结果之前,该调用不返回,通俗来讲,就是必须做完前一件事情才可以 做下一件事情;

       ②异步:

        当客户端发生一个异步请求的调用的时候,调用者不能立刻得到结果,实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者,例如ajax请求;

       ③阻塞

        通俗的讲,做某件事情,知道完成,除非超时,如果没有完成,继续等待;当阻塞调用的时候,在调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,CPU不会给线程分配时间片,即线程暂停运行),函数只有在得到结果折后才会被 返回;

       ④非阻塞

       指在不能得到结果之前,该函数不会阻塞当前线程,会立刻返回;

      还是等快递的例子:如果用忙轮询的方法,每隔5分钟到A楼一层(内核缓冲区)去看快递来了没有。如果没来,立即返回。而快递来了,就放在A楼一层,等你去取。

 

 传统IO的Socket的单线程通信,用非常经典的食堂例子来讲解,端口号相当于食堂大门,线程相当于服务员,在这个状态下,一个客户需要有一个服务员来服务,这样显然是不合理的,假如有100个顾客的话,就需要100服务员,这样非常浪费系统资源,代码如下:

package IoSocket;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Created by Taoyongpan on 2017/10/23.
 * 传统的IO是阻塞IO,每多一个用户就要创建一个新的线程,单线程模式
 */
public class TraditionalSocketDemo {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器启动。。。。");
        while (true){
            //接收客户端的连接 ,套接字
            Socket socket = serverSocket.accept();
            System.out.println("有新的客户端连接");
            InputStream in = null;
            try {
                in = socket.getInputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] b = new byte[1024];
            while (true){
                int data = 0;
                data = in.read(b);
                if (data!=-1){
                    String info = new String(b,0,data);
                    System.out.println(info);
                }else {
                    break;
                }
            }
        }
    }
}

 当程序运行的时候:



 这时用命令窗口创建一个用户,我这里面的端口号是8888,我们创建客户的语句是:telnet localhost 8888,如图所示:

 输入 CTRL+]的命令 进入字符串发送页面。原来的页面只可以发送字符;

 send +自己所要发送的内容,如上图所示;

因为这个代码写的是单线程模式的,当我们再创建一个新的客户的时候,就会陷入等待,只有关闭上一个现成的时候,新建客户的消息的才可以发送,如下图所示:



 

 

我们也可以创建一个线程池,来实现多线程,代码如下:

package IoSocket;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by Taoyongpan on 2017/10/24.
 * 传统的IO是阻塞IO,每多一个用户就要创建一个新的线程
 */
public class TraditionSocketDemo1 {
    public static void main(String[] args) throws IOException {
        //多线程方法,创建一个线程池
        ExecutorService es = Executors.newCachedThreadPool();
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器启动。。。。");
        while (true){
            //接收客户端的连接 ,套接字
            Socket socket = serverSocket.accept();
            System.out.println("有新的客户端连接");
            es.execute(new Runnable() {
                @Override
                public void run() {
                    InputStream in = null;
                    try {
                        in = socket.getInputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    byte[] b = new byte[1024];
                    while (true){
                        int data = 0;
                        try {
                            data = in.read(b);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        if (data!=-1){
                            String info = new String(b,0,data);
                            System.out.println(info);
                        }else {
                            break;
                        }
                    }
                }
            });

        }
    }
}

 重复运行上面的测试步骤就可以进行操作:

测试如下图所示:



 

NIO是非阻塞的IO,相对于传统IO,新增了selector、channel和buffer,还用食堂的例子来讲解,我们的channel就像食堂的大门,一个食堂的服务员可以服务多个客户,这个过程用selector来调度,例如在 客户A点菜的时候,接待了客户B,代码如下:

package IoSocket;

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

/**
 * Created by Taoyongpan on 2017/10/23.
 * nio,增加了selector,channel ,buffer,非阻塞
 */
public class NioSocketDemo {

    private Selector selector;//通道选择器

    public static void main(String[] args) throws IOException {
        NioSocketDemo nioSocketDemo = new NioSocketDemo();
        nioSocketDemo.initServer(8888);
        nioSocketDemo.listenSelector();
    }
    public void initServer(int port) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);//设置成非阻塞
        serverSocketChannel.socket().bind(new InetSocketAddress(port));
        this.selector = Selector.open();
        //注册监听器
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);//注册监听连接请求
        System.out.println("服务已启动。。。");
    }

    public void listenSelector() throws IOException {
        //循环监听selector
        while (true){
            //等待客户连接
            //select模型,多路服用
            this.selector.select();
            this.selector.selectedKeys().iterator();
            Iterator<SelectionKey> it = this.selector.selectedKeys().iterator();
            while (it.hasNext()){
                SelectionKey skey = it.next();
                it.remove();//把当前的元素remove掉
                //处理请求
                handler(skey);
            }
        }
    }

    private void handler(SelectionKey skey) throws IOException {
        if (skey.isAcceptable()){
            //处理客户端连接事件
            ServerSocketChannel serverChannel = (ServerSocketChannel)skey.channel();
            SocketChannel socketChannel = serverChannel.accept();
            System.out.println("新客户连接上来了");
            socketChannel.configureBlocking(false);//设置为非阻塞
            //接收客户端发送的信息,需要给通道设置读的权限
            socketChannel.register(selector,SelectionKey.OP_READ);
        }else if (skey.isReadable()){
            //处理读的事件
            SocketChannel socketChannel = (SocketChannel) skey.channel();
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//初始化一个缓存
            int data = socketChannel.read(byteBuffer);
            if (data>0){
                String info = new String(byteBuffer.array(),"GBK").trim();
                System.out.println("客户端消息"+info);
            }else {
                System.out.println("客户端关闭了");
                skey.cancel();//把这个连接清除掉
            }
        }
    }
}

 这个的运行效果和传统IO的多线程的运行结果是一样的,这里就不再进行展示;

  • 大小: 20.9 KB
  • 大小: 90.5 KB
  • 大小: 70 KB
  • 大小: 71.7 KB
  • 大小: 98.9 KB
  • 大小: 79.1 KB
分享到:
评论

相关推荐

    NIO socket编程小例子 加法服务器

    在Java编程领域,NIO(Non-blocking Input/Output)是一种重要的网络编程模型,与传统的IO模型相比,它提供了更高的性能和更低的系统资源消耗。本示例中的"加法服务器"是一个利用NIO Channel实现的简单应用,它展示...

    NioSocket,包括server端和client端

    在Java编程中,NIO(New Input/Output)提供了一种不同于传统IO模型的I/O操作方式,其核心特点是能够进行多路复用,即一个线程可以同时处理多个连接,这使得NioSocket在高并发场景下具有较好的性能表现。 服务器端...

    NIO与传统IO代码区别实例

    在Java编程领域,IO(Input/Output)和NIO(Non-blocking Input/Output)是两种不同的I/O模型,它们在处理数据输入和输出时有着显著的差异。本教程旨在帮助NIO初学者理解这两种模型的核心概念及其实际应用,通过具体...

    nio socket编程java代码示例,客户端发送消息,服务端接收

    NIO与传统的IO模型不同,它提供了对多路复用器的支持,如Java的Selector类,可以同时监控多个通道的状态变化,从而提高了系统在高并发环境下的性能。在Socket编程中,NIO使得服务器可以处理更多的连接请求,而无需为...

    Java IO, NIO and NIO.2

    Java IO、NIO以及NIO.2是Java中用于处理输入/输出操作的三种主要机制。本书《Java IO, NIO and NIO.2》旨在深入浅出地介绍这些机制,同时书中内容均为英文。接下来将详细介绍这些知识点。 **Java IO** Java IO是...

    java nio 实现socket

    #### 一、NIO与传统IO的区别及优势 在探讨如何使用Java NIO实现Socket通信之前,我们需要先理解NIO(Non-blocking I/O,非阻塞I/O)与传统阻塞I/O之间的区别。 **传统阻塞I/O模型**:在传统的Java IO编程中,当...

    NIO编程技术指南_预览版

    **NIO(New Input/Output)编程技术指南** 在Java世界中,NIO(New Input/Output)是一种从Java 1.4...《NIO与Socket编程技术指南》_高洪岩.pdf这本书将为你提供全面的NIO知识和实践指导,帮助你掌握这一关键技术。

    nio的socket

    在NIO中,Socket通信不再局限于传统的`java.net.Socket`和`java.net.ServerSocket`,而是通过`java.nio.channels.SocketChannel`和`java.nio.channels.ServerSocketChannel`进行。 1. **SocketChannel**:这是NIO中...

    socket通信NIO代理模式demo实例

    NIO(Non-blocking I/O)是Java提供的一个高效I/O模型,相较于传统的IO模型,NIO具有非阻塞、多路复用等特性,能够更好地处理大量并发连接。本实例"socket通信NIO代理模式demo"将展示如何利用NIO来构建一个高性能的...

    nio.rar_NIO_NIO-socket_java nio_java 实例_java.nio

    Java NIO(New IO)是Java 1.4版本引入的一个新特性,它为Java应用程序提供了非阻塞I/O操作的能力,与传统的IO模型(基于流的I/O和基于缓冲区的I/O)相比,NIO具有更高的效率和灵活性。在Java NIO中,数据是以通道...

    Java源码:Socket编程.rar_java socket _java编程_socket java_socket编程 jav

    Java Socket编程是网络编程中的重要组成部分,主要用于实现客户端与服务器之间的通信。在Java中,Socket是基于TCP协议的,提供了一种可靠的、基于字节流的双向通信方式。本资料包含的"Java源码:Socket编程"是一个...

    Mina NIO Socket

    在Java世界中,网络编程是一个不可或缺的部分,而Mina NIO(Non-blocking I/O)Socket库则是Java开发者实现高性能、高并发网络服务的重要工具。本文将深入探讨Mina NIO Socket的核心概念、工作原理以及在实际项目中...

    java网络编程socket编程等

    总之,Java网络编程与Socket编程是Java开发者必须掌握的技术之一。理解其原理,熟练运用相关API,能帮助我们开发出高效、稳定的网络应用程序。在实际项目中,根据需求选择合适的通信方式,结合多线程、NIO等技术,...

    JAVA Socket编程实现文件上传

    Java Socket编程是网络编程的基础,它提供了在两个应用程序之间建立通信连接的能力。在这个场景中,我们讨论的是如何使用Java的Socket来实现文件上传功能,即从客户端将文件发送到服务器,然后保存到服务器的数据库...

    采用NIO实现一个Socket服务器

    它与传统的BIO(Blocking IO)模型不同,NIO提供了更高效的数据读写方式,特别适合于高并发、低延迟的网络应用,如Socket服务器的构建。本篇将基于给定的标题“采用NIO实现一个Socket服务器”来详细阐述如何使用NIO...

    详细介绍 NIO与Netty编程-实战讲义详细pdf.7z

    **BIO**,即传统的阻塞I/O模型,在Java中表现为`java.io`包中的类,如`Socket`和`ServerSocket`。在BIO中,每个连接都需要一个独立的线程进行处理,当服务端接收客户端连接请求时,会阻塞直到数据读取或写入完成。...

    nio.rar_Java socketA_java nio_java socket a

    Java NIO(New IO)是Java 1.4版本引入的一种新的I/O API,它提供了与标准Java IO API不同的I/O工作方式。...不过,NIO的学习曲线较陡峭,理解和使用起来相比传统的Socket编程需要更多的实践和调试。

Global site tag (gtag.js) - Google Analytics