BIO调试

概念: 同步异步与阻塞非阻塞的理解

同步异步针对调用方,阻塞非阻塞针对服务方

调用方发送请求不需要等待就是异步,反之同步

服务方收到请求立即返回响应,再进行处理就是非阻塞,反之阻塞

阻塞非阻塞在于没有数据时是否等待,想象BIO客户端连接及数据读取

阻塞非阻塞都是针对单线程说的,todo

阻塞一个线程只能处理一个请求BIO,非阻塞一个线程可以处理多个请求NIO 

BIO NIO对比

NIO解决了网络请求与响应的IO阻塞问题,与同步异步有点类似,但非异步,是非阻塞

基本概念 

工作原理

 

基本介绍

 

同步阻塞

一个客户端连接,服务端启动一个线程处理

工作原理 

 

 

模拟客户端发送请求遇到问题

问题1

mac 使用telnet模拟客户端发送请求,要先安装telnet,安装telnet先安装 Homebrew,先完成以下两个步骤

问题2

发送send 失败,无法识别内容,未解决

解决方案

问题1

步骤1

mac环境下,如何解决brew command not found错误

mac 终端下,执行以下命令,即可安装brew:

/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"

步骤2

​​​​​​mac os 下安装及使用 telnet 命令进行 socket 测试_是龙台呀-CSDN博客_mac使用telnet测试端口

关于阻塞

两个地方

1.未建立客户端连接,服务端 阻塞连接

2.建立了客户端连接,没有数据,阻塞读取数据

阻塞分析

1.第一次启动socket服务端,阻塞在连接处 

如下图,看日志,阻塞在连接处

3.客户端建立连接并发送数据

分析日志,分为以下几个部分

1.第一次启动服务端打印,主线程

2.客户端建立,客户端连接上

3.又是主线程信息,说明客户端建立连接后,立马回到主线程,继续监听客户端连接

4.子线程,读取数据

 5.看上面4中日志,读取完成,又阻塞在读取数据处,说明建立了客户端连接,会一直轮询读取该客户端是否发送请求,一直监听.....

代码

服务端

@Slf4j
public class BioService {

    static ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

    public static void main(String[] args) {
	try {
	    ServerSocket serverSocket = new ServerSocket(6666);
	    log.info("创建socket服务完成,服务器启动了...");

	    /*服务器轮询监听*/
	    while (true) {
		log.info("serverSocket 主线程 ThreadId: {},ThreadName: {}", Thread.currentThread().getId(),
				Thread.currentThread().getName());

		log.info("监听,等待客户端连接,未连接上...");
		log.info("阻塞1,未连接上客户端...");
		final Socket socket = serverSocket.accept();
		log.info("连接到一个客户端...");

		cachedThreadPool.submit(new Runnable() {
		    @Override
		    public void run() {
			handle(socket);
		    }
		});
	    }
	} catch (IOException e) {
	    e.printStackTrace();
	}

    }

    public static void handle(Socket socket) {
	try {
	    log.info("serverSocket 线程信息 ThreadId: {},ThreadName: {}", Thread.currentThread().getId(),
			    Thread.currentThread().getName());
	    log.info("准备读取客户端请求,获取输入流...");
	    InputStream in = socket.getInputStream();
	    byte[] bytes = new byte[1024];
	    while (true) {
		/*把输入流读入二进制数组*/
		log.info("准备读取客户端请求,读取输入流...");
		log.info("阻塞2,已连接上客户端,未发送数据...");
		int read = in.read(bytes);
		if (read != -1) {
		    log.info("read client content: {}", new String(bytes, 0, read));
		} else {
		    break;
		}
	    }
	} catch (IOException e) {
	    e.printStackTrace();
	} finally {
	    try {
		/*关闭客户端连接*/
		socket.close();
	    } catch (IOException e) {
		e.printStackTrace();
	    }
	}
    }
}

客户端

public class SocketClient {

    public static void main(String[] args) {
	try {
	    //1.建立客户端socket连接,指定服务器位置及端口
	    Socket socket = new Socket("localhost", 6666);
	    //2.得到socket读写流
	    OutputStream os = socket.getOutputStream();
	    PrintWriter pw = new PrintWriter(os);
	    //输入流
	    InputStream is = socket.getInputStream();
	    BufferedReader br = new BufferedReader(new InputStreamReader(is));
	    //3.利用流按照一定的操作,对socket进行读写操作
	    String info = "用户名:shenke,用户密码:123456";
	    pw.write(info);
	    pw.flush();
	    socket.shutdownOutput();
	    //接收服务器的相应
	    String reply = null;
	    while (!((reply = br.readLine()) == null)) {
		System.out.println("接收服务器的信息:" + reply);
	    }
	    //4.关闭资源
	    br.close();
	    is.close();
	    pw.close();
	    os.close();
	    socket.close();
	} catch (UnknownHostException e) {
	    e.printStackTrace();
	} catch (IOException e) {
	    e.printStackTrace();
	}
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值