Java分别用BIO、NIO实现简单的客户端服务器通信

这篇具有很好参考价值的文章主要介绍了Java分别用BIO、NIO实现简单的客户端服务器通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:
Java I/O模型发展以及Netty网络模型的设计思想

BIO

Java BIO是Java平台上的BIO(Blocking I/O)模型,是Java中用于实现同步阻塞网络编程的一种方式。 在Java中,使用BIO模型需要通过Socket和ServerSocket类来完成网络连接和数据传输,但是由于BIO是同步阻塞的,所以会导致线程阻塞和资源浪费的问题。
因此,在高并发的网络编程场景中,通常会选择使用NIO(Non-blocking I/O)模型或者Netty等框架来实现。

Java分别用BIO、NIO实现简单的客户端服务器通信,手撕代码,网络编程,nio,服务器,rpc
服务端类代码

package com.yu.io.bio;

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

public class BIOServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8081);
        while (true) {
            System.out.println("wait connect...");
            Socket clientSocket = serverSocket.accept();
            System.out.println(clientSocket.getPort() + "connected");
            System.out.println("start read...");

            byte[] readArr = new byte[1024];
            int read = clientSocket.getInputStream().read(readArr);
            if (read != -1) {
                System.out.println("read info : " + new String(readArr,0,read));
            }
            System.out.println("end read...");
            byte[] resBytes = "server response".getBytes();
            clientSocket.getOutputStream().write(resBytes);
            System.out.println("response info : " + new String(readArr,0,read));
            clientSocket.getOutputStream().flush();
        }
    }
}

客户端类代码

package com.yu.io.bio;

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

public class BIOClient {
    public static void main(String[] args) throws IOException {
        Socket clientSocket = new Socket("127.0.0.1",8081);
        byte[] resBytes = "client response".getBytes();
        clientSocket.getOutputStream().write(resBytes);
        System.out.println("response info : " + new String(resBytes));
        clientSocket.getOutputStream().flush();
        byte[] readArr = new byte[1024];
        int read = clientSocket.getInputStream().read(readArr);
        if (read != -1) {
            System.out.println("read info : " + new String(readArr,0,read));
        }
    }
}

NIO

Java NIO 能够支持非阻塞网络编程,可以理解为new io 或者no blok io 我更喜欢称之为new io,因为他不仅仅实现了非阻塞的网络编程方式,同时也封装了常用的网络编程api,更重要的是引入了多路复用器Selector的概念

Java分别用BIO、NIO实现简单的客户端服务器通信,手撕代码,网络编程,nio,服务器,rpc

下面的代码只是展示NIO非阻塞的实现,并没有展示NIO的真正用法

NIO演示(无Selector)

服务端类代码

package com.yu.io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;

public class NIOServer {

    public static List<SocketChannel> socketChannelList = new ArrayList<>();
    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(8081));
        serverSocketChannel.configureBlocking(false);
        System.out.println("server start...");
        while (true) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            if (socketChannel != null) {
                System.out.println(socketChannel.socket().getPort() + " connected");
                socketChannel.configureBlocking(false);
                socketChannelList.add(socketChannel);
            }
            List<SocketChannel> rmChannelList = new ArrayList<>();
            for (SocketChannel channel : socketChannelList) {
                try {
                    doChannel(rmChannelList, channel);
                } catch (IOException ioException) {
                    //有客户端断开连接
                    System.out.println(channel.socket().getPort() + " disconnected");
                    channel.close();
                    rmChannelList.add(channel);
                }
            }
            socketChannelList.removeAll(rmChannelList);
        }
    }

    private static void doChannel(List<SocketChannel> rmChannelList, SocketChannel channel) throws IOException {
        ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);
        int read = channel.read(readByteBuffer);
        String readStr = new String(readByteBuffer.array());
        if (read > 0) {
            System.out.println(channel.socket().getPort() + " : " + readStr);
            if (readStr.contains("hello")) {
                ByteBuffer sendByteBuffer = ByteBuffer.wrap("hello! I am robot.".getBytes());
                channel.write(sendByteBuffer);
                System.out.println("me : " + new String(sendByteBuffer.array()));
            }
            if (readStr.contains("old")) {
                ByteBuffer sendByteBuffer = ByteBuffer.wrap("I am 1 years old.".getBytes());
                channel.write(sendByteBuffer);
                System.out.println("me : " + new String(sendByteBuffer.array()));
            }
            if (readStr.contains("bey")) {
                ByteBuffer sendByteBuffer = ByteBuffer.wrap("see you.".getBytes());
                channel.write(sendByteBuffer);
                System.out.println("me : " + new String(sendByteBuffer.array()));
            }
        }
        if (read == -1) {
            rmChannelList.add(channel);
        }
    }
}

客户端类代码

package com.yu.io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NIOClient {
    public static void main(String[] args) throws IOException {
        SocketChannel clientSocketChannel = SocketChannel.open();
        clientSocketChannel.connect(new InetSocketAddress("127.0.0.1",8081));
        clientSocketChannel.configureBlocking(false);
        String sendStr = "hello! I am client " + clientSocketChannel.socket().getPort() + ".";
        ByteBuffer sendByteBuffer = ByteBuffer.wrap(sendStr.getBytes());
        clientSocketChannel.write(sendByteBuffer);
        System.out.println("me : " + new String(sendByteBuffer.array()));
        int msgSize = 0;
        while (msgSize < 10) {
            ByteBuffer readByteBuffer = ByteBuffer.allocate(1024);
            int read = clientSocketChannel.read(readByteBuffer);
            String readStr = new String(readByteBuffer.array());
            if (read > 0) {
                System.out.println("robot : " + readStr);
                msgSize ++;
                ByteBuffer resByteBuffer = null;
                if (readStr.contains("hello")) {
                    resByteBuffer = ByteBuffer.wrap("how old are you?.".getBytes());
                    clientSocketChannel.write(resByteBuffer);
                    System.out.println("me : " + new String(resByteBuffer.array()));
                    resByteBuffer.clear();
                }
                if (readStr.contains("old")) {
                    resByteBuffer = ByteBuffer.wrap("en, place say hello!".getBytes());
                    clientSocketChannel.write(resByteBuffer);
                    System.out.println("me : " + new String(resByteBuffer.array()));
                    resByteBuffer.clear();
                }
            }
        }
        ByteBuffer resByteBuffer = ByteBuffer.wrap("bey bey!".getBytes());
        clientSocketChannel.write(resByteBuffer);
        System.out.println("me : " + new String(resByteBuffer.array()));
        resByteBuffer.clear();
        clientSocketChannel.close();
    }
}

NIO演示(Selector)

无Selector的NIO演示中,显然会出现空转的情况,以及无效连接的处理问题,这些问题都会影响性能。
NIO提供Selector多路复用器,优化上述问题
以下demo实现服务器与客户端通信,相互发消息。并由服务器转发给其他客户端(广播功能)

服务端类代码

server main类

import java.io.IOException;

public class NIOServerMain {
    public static void main(String[] args) throws IOException {
        NIOSelectorServer server = new NIOSelectorServer();
        server.start();
    }
}

server run类

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;

public class NIOSelectorServer {

    public void start() throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(8081));
        serverSocketChannel.configureBlocking(false);
        //注册到selector多路复用器中
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("server start...");
        run(selector);
    }

    /**
     * 遍历多路复用器的事件,处理事件
     */
    private void run(Selector selector) throws IOException {
        while (true) {
            //阻塞等待事件
            selector.select();

            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectedKey = iterator.next();
                try {
                    if (selectedKey.isAcceptable()) {
                        doAccept(selector, selectedKey);
                    }
                    if (selectedKey.isReadable()) {
                        doReadChannel(selectedKey, selector);
                    }
                } catch (IOException ioException) {
                    //有客户端断开连接
                    disConnect(selectedKey, "exception");
                }
                iterator.remove();
            }
        }
    }

    /**
     * 处理连接事件
     */
    private void doAccept(Selector selector, SelectionKey selectedKey) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel)selectedKey.channel();
        SocketChannel socketChannel = serverChannel.accept();
        socketChannel.configureBlocking(false);
        socketChannel.register(selector, SelectionKey.OP_READ);
        System.out.println(socketChannel.socket().getPort() + " connected");
    }

    /**
     * 处理接收信息事件
     */
    private void doReadChannel(SelectionKey selectedKey, Selector selector) throws IOException {
        SocketChannel channel = (SocketChannel)selectedKey.channel();
        ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);
        int read = channel.read(readByteBuffer);
        String readStr = "";
        readByteBuffer.flip();
        readStr += StandardCharsets.UTF_8.decode(readByteBuffer);
        if (read > 0) {
            System.out.println(channel.socket().getPort() + " : " + readStr.length() + " - "+ readStr);
            //转发消息(其他客户端)
            broadcast(selectedKey, selector, readStr);
            if (readStr.contains("hello")) {
                sendMsg(channel, "hello! I am robot.");
            }
            if (readStr.contains("old")) {
                sendMsg(channel, "I am 1 years old.");
            }
            if (readStr.contains("bye")) {
                sendMsg(channel, "see you.");
            }
        }
        if (read == -1) {
            //有客户端断开连接
            disConnect(selectedKey, "read = -1");
        }
    }

    /**
     * 连接异常的处理
     */
    private void disConnect(SelectionKey selectedKey, String type) throws IOException {
        SocketChannel channel = (SocketChannel)selectedKey.channel();
        System.out.println(channel.socket().getPort() + " disconnected. " + type);
        selectedKey.cancel();
        channel.close();
    }

    /**
     * 发送消息
     */
    private void sendMsg(SocketChannel channel, String s) throws IOException {
        ByteBuffer sendByteBuffer = ByteBuffer.wrap(s.getBytes());
        channel.write(sendByteBuffer);
        System.out.println("me : " + new String(sendByteBuffer.array()));
    }

    /**
     * 广播
     * 转发消息(给其他客户端)
     */
    private void broadcast(SelectionKey  fromSelectedKey, Selector selector, String readStr) throws IOException {
        Iterator<SelectionKey> selectionKeyIterator = selector.keys().iterator();
        while (selectionKeyIterator.hasNext()) {
            SelectionKey otherKey = selectionKeyIterator.next();
            if (otherKey == fromSelectedKey) {
                continue;
            }
            if (!(otherKey.channel() instanceof SocketChannel)) {
                continue;
            }
            SocketChannel otherChannel = (SocketChannel)otherKey.channel();
            sendMsg(otherChannel, "(转发自 "+ ((SocketChannel)fromSelectedKey.channel()).socket().getPort() + ")" + readStr);
        }
    }
}

客户端代码

一共构造了两个客户端(消息客户端和looker客户端), looker客户端优先启动,随后启动消息客户端,消息客户端与服务器的通信会被转发给looker客户端

look client main类

import java.io.IOException;

public class NIOClientLookMain {
    public static void main(String[] args) throws IOException, InterruptedException {
        NIOSelectorClient client = new NIOSelectorLookClient();
        client.start(8081, 100);
    }
}

msg client main类

import java.io.IOException;

public class NIOClientMain {
    public static void main(String[] args) throws IOException, InterruptedException {
        NIOSelectorClient lookClient = new NIOSelectorClient();
        lookClient.start(8081, 10);
    }
}

client run类

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.nio.charset.StandardCharsets;
import java.util.Iterator;

public class NIOSelectorClient {
    protected int port;
    protected int size;
    public void start(int port, int size) throws IOException, InterruptedException {
        this.port = port;
        this.size = size;
        SocketChannel clientSocketChannel = SocketChannel.open();
        clientSocketChannel.connect(new InetSocketAddress("127.0.0.1",port));
        clientSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();
        clientSocketChannel.register(selector, SelectionKey.OP_READ);
        //发送开始数据
        sendMsg(clientSocketChannel, "hello! I am client " + clientSocketChannel.socket().getLocalPort() + ".");
        run(selector);
        sendMsg(clientSocketChannel, "bye bye!");
        clientSocketChannel.close();
    }

    /**
     * 遍历多路复用器的事件,处理事件
     */
    protected void run(Selector selector) throws IOException, InterruptedException {
        int msgSize = 0;
        while (msgSize < size) {
            int length=selector.select();
            if(length ==0){
                continue;
            }
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while(iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                if(selectionKey.isReadable()){
                    boolean readChannel = false;
                    try {
                        readChannel = doReadChannel(selectionKey, selector);
                    } catch (IOException e) {
                        selectionKey.cancel();
                        System.out.println("robot disconnect, restart connect...");
                        while (true){
                            try {
                                reConnect();
                                return;
                            } catch (IOException ioException) {
                                System.out.println("restart connecting(5s) ");
                                //ioException.printStackTrace();
                                Thread.sleep(5000);
                            }
                        }
                    }
                    if (readChannel) {
                        msgSize ++;
                    }
                }
                iterator.remove();
            }
        }
    }

    protected boolean doReadChannel(SelectionKey selectedKey, Selector selector) throws IOException {
        SocketChannel channel = (SocketChannel)selectedKey.channel();
        ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);
        int read = channel.read(readByteBuffer);
        String readStr = "";
        readByteBuffer.flip();
        readStr += StandardCharsets.UTF_8.decode(readByteBuffer);
        if (read > 0) {
            System.out.println("robot : " + readStr);
            if (readStr.contains("hello")) {
                sendMsg(channel, "how old are you?.");
            }
            if (readStr.contains("old")) {
                sendMsg(channel, "en, place say hello!");
            }
            return true;
        }
        return false;
    }

    protected void sendMsg(SocketChannel channel, String sendStr) throws IOException {
        ByteBuffer sendByteBuffer = ByteBuffer.wrap(sendStr.getBytes());
        channel.write(sendByteBuffer);
        System.out.println("me : " + new String(sendByteBuffer.array()));
    }

    protected void reConnect() throws IOException, InterruptedException {
        NIOSelectorClient client = new NIOSelectorClient();
        client.start(port, size);
    }
}

look client run类文章来源地址https://www.toymoban.com/news/detail-697245.html

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.nio.charset.StandardCharsets;

public class NIOSelectorLookClient extends NIOSelectorClient{
    @Override
    public void start(int port, int size) throws IOException, InterruptedException {
        this.port = port;
        this.size = size;
        SocketChannel clientSocketChannel = SocketChannel.open();
        clientSocketChannel.connect(new InetSocketAddress("127.0.0.1",port));
        clientSocketChannel.configureBlocking(false);
        Selector selector = Selector.open();
        clientSocketChannel.register(selector, SelectionKey.OP_READ);
        //发送开始数据
        sendMsg(clientSocketChannel, "I am looker. " + clientSocketChannel.socket().getLocalPort() + ".");
        run(selector);
    }

    @Override
    protected boolean doReadChannel(SelectionKey selectedKey, Selector selector) throws IOException {
        SocketChannel channel = (SocketChannel)selectedKey.channel();
        ByteBuffer readByteBuffer = ByteBuffer.allocate(2048);
        int read = channel.read(readByteBuffer);
        String readStr = "";
        readByteBuffer.flip();
        readStr += StandardCharsets.UTF_8.decode(readByteBuffer);
        if (read > 0) {
            System.out.println("robot : " + readStr.length() + " - "+ readStr);
            if (readStr.contains("bye")) {
                sendMsg(channel, "bye.");
            }
            return true;
        }
        return false;
    }

    @Override
    protected void reConnect() throws IOException, InterruptedException {
        NIOSelectorClient client = new NIOSelectorLookClient();
        client.start(port, size);
    }
}

到了这里,关于Java分别用BIO、NIO实现简单的客户端服务器通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java代码构建简单http服务器和客户端

    初识http a、超文本传输 、应用层的面向对象的协议,概念介绍网上资源一大堆,关键是基于TCP/IP通信协议来传递数据。 b、一开始接触web项目,都是先接触的servlet,tomcat服务器默认实现的一套http规范,提供了基础服务和组件环境,直接拿到请求、构建正文、响应客户端 然而

    2024年02月10日
    浏览(50)
  • c语言实现简单的tcp客户端

    功能:实现一个简单的tcp客户端,连接本地端口8888的tcp服务端,并发送一条报文。  

    2024年02月14日
    浏览(48)
  • 因项目只做socket客户端,不想用workerman或者swoole框架,简单实现ws PHP客户端

    docs/Client.md · master · mirrors / Textalk / websocket-php · GitCode

    2024年02月13日
    浏览(63)
  • 10. Linux下实现简单的http客户端请求

    本文Linux下实现简单的http客户端请求 HTTP(超文本传输协议)是一种用于在网络上进行数据通信的协议。HTTP 协议定义了客户端和服务器之间如何交换信息,包括请求和响应格式、使用的方法、状态码等。 在 HTTP 协议中,资源(Resource)指的是由 URL (统一资源定位符)所标识

    2024年02月16日
    浏览(49)
  • 计算机网络 简单FTP客户端软件的实现

    文件传送协议FTP(File Transfer Protocol)是TCP/IP体系的一个重要协议,它采用Internet标准文件传输协议FTP的用户界面,向用户提供了一组用来管理计算机之间文件传输的应用程序。FTP是基于客户—服务器(C/S)模型而设计的,在客户端和FTP建立两个TCP连接。 FTP 的独特的优势同时

    2024年02月12日
    浏览(54)
  • 使用socket.io简单实现多客户端可编辑表格

    之前看了B站小野森森老师的可编辑表格的视频深受启发,今天使用React简单实现一下。 当处于编辑状态的时候,自己和其他人可以看到; 编辑内容后,自己及其他人可以同步看到修改后的内容; 后端服务,使用socket.io起一个后端服务,用于监听连接和发送数据; 前端准备:

    2024年02月06日
    浏览(49)
  • 基于C# Socket实现的简单的Redis客户端

         Redis 是一款强大的高性能键值存储数据库,也是目前 NOSQL 中 最流行 比较流行的一款数据库,它在广泛的应用场景中扮演着至关重要的角色,包括但不限于缓存、消息队列、会话存储等。在本文中,我们将介绍如何基于 C# Socket 来实现一个简单的Redis客户端类 RedisClien

    2024年02月05日
    浏览(54)
  • 【网络原理】使用Java基于TCP搭建简单客户端与服务器通信

    TCP服务器与客户端的搭建需要借助以下API ServerSocket 是创建TCP服务端Socket的API。 ServerSocket 构造方法 : 方法签名 方法说明 ServerSocket(int port) 创建一个服务端流套接字Socket,并绑定到指定端口 ServerSocket 方法: 方法签名 方法说明 Socket accept() 开始监听指定端口(创建时绑定的端

    2024年03月12日
    浏览(80)
  • C++实现一个简单的客户端与服务端的通信(笔记附代码)

    目录 前言 一、Socket的客户端与服务端的通讯原理 二、各接口介绍 1.WSAStartup:异步启动套接字命令 2.Socket创建套接字 3.bind:绑定套接字 4.listen:监听 5.accept:接受连接请求 6. connet:发送连接请求  7.send:发送数据 8.recv:接收数据函数  9.closesocket, WSACleanup:释放socket 三、代码块的

    2024年02月06日
    浏览(52)
  • C#实现简单TCP服务器和客户端网络编程

    在C#中进行网络编程涉及许多类和命名空间,用于创建和管理网络连接、传输数据等。下面是一些主要涉及的类和命名空间: System.Net 命名空间: 这个命名空间提供了大部分网络编程所需的类,包括: IPAddress :用于表示IP地址。 IPEndPoint :表示IP地址和端口号的组合。 Socke

    2024年02月11日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包