Socket多线程与高并发

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、BIO(block input output)阻塞式的输入和输出

在这里插入图片描述

  1. 按照此代码可以写一个简单的服务端接收代码
    在这里插入图片描述
  2. cmd连接服务端
    在这里插入图片描述
  3. 发送消息到服务端
    在这里插入图片描述
  4. 服务端接收
    在这里插入图片描述
  5. 问题
    1. c10k问题(10w个线程会大大的占用服务器内存),解决通过NIO模式来解决。
    2. 需要等待一个线程完成后再执行另一个客户端,当连接数过多最后一个连接等待时间将会特别长。

提示:以下是本篇文章正文内容,下面案例可供参考

二、NIO(non-blocking input output)非阻塞式输入输出

  1. 编写测试代码
    在这里插入图片描述
    在这里插入图片描述
    NIO主要是因为配置了非阻塞:
    在这里插入图片描述
    实现原理:创建一个list,通过while轮询,检查是否有连接到服务端,入股有就存放到list中,然后再统一便利list处理所有客户端数据。

2.1 NIO问题

如果用一个list存放,当有10w个连接时将每次遍历10万次list

2.2 多路复用器

在这里插入图片描述

改造原来的代码,插入以下代码:

底层原理:
epoll:linux内核创建了一个epoll实例集合对象。
在这里插入图片描述
在这里插入图片描述

package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

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;
import java.util.Set;
@SpringBootTest
public class NIOSelectorApplicationTests {
    
    @Test
    public void nioTest() throws IOException {
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(9002));
        // 设置位非阻塞主要的代码
        serverSocket.configureBlocking(false);
        // 引入多路复用器
        Selector selector = Selector.open();
        // 注册多路复用器
        SelectionKey selection = serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务启动成功。。。。");
        while(true){
            // 阻塞等待需要处理的事件发生
            selector.select();
            // 获取Selector中注册的全部事件。
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            // 便利SelectionKey对事件进行处理
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                // 如果时OP_READ事件,则进行连接获取和事件注册。
                if(key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    // 此处只注册了读操作,如果要给客户端发数据可以注册写事件
                    SelectionKey register = socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("连接成功。。。。");
                }else if(key.isReadable()){ // 这里只写了读操作
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer byteBuffer = ByteBuffer.allocate(128);
                    // 非阻塞模式下read方法不会阻塞否则会阻塞
                    int read = socketChannel.read(byteBuffer);
                    // 如果有数据把数据打印出来
                    if(read > 0){
                        String readStr = new String(byteBuffer.array());
                        System.out.println("接收到的数据:"+readStr);
                    }else { // 如果客户端断开,就把socket从列表中移除
                        System.out.println("客户端断开连接。。。");
                    }
                }
                // 从事件删除本次处理的连接,防止重复处理
                iterator.remove();
            }
        }
    }

}

epoll最关键的三大函数
在这里插入图片描述
提示:redis底层也是使用了epoll

三、使用Netty

编写一个简单的netty
在这里插入图片描述
在这里插入图片描述

其他知识

linux查看函数或者命令的帮助文档,可输入:man
在这里插入图片描述
在这里插入图片描述

提示:这里可以添加本文要记录的大概内容:

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值