前传02 | 线程模型

本文围绕Java NIO展开,介绍了Socket模型实现网络通信的步骤,包括创建、监听、处理连接和读写请求等。阐述了IO多路复用的select、poll、epoll机制及优缺点。还讲述了线程模型的发展,如多线程、线程池、selector版设计。重点讲解了Reactor模型的理论、工作机制及三种实现变种,最后提及Netty基于主从Reactors多线程模型的设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Socket模型

使用 Socket 模型实现网络通信时,需要经过创建 Socket、监听端口、处
理连接和读写请求等多个步骤。
在这里插入图片描述

首先,当我们需要让服务器端和客户端进行通信时,可以在服务器端通过以下三步,来创建监听客户端连接的监听套接字(Listening Socket):

  1. 调用 socket 函数,创建一个套接字。我们通常把这个套接字称为主动套接字(Active
    Socket);
  2. 调用 bind 函数,将主动套接字和当前服务器的 IP 和监听端口进行绑定;
  3. 调用 listen 函数,将主动套接字转换为监听套接字,开始监听客户端的连接。
  4. 调用accept 函数,在完成上述三步之后,服务器端就可以接收客户端的连接请求了。为了能及时地收到客户端的连接请求,我们可以运行一个循环流程,在该流程中调用 accept 函数,用于接收客户端连接请求。
  5. 最后,服务器端可以通过调用 recv 或 send 函数,在刚才返回的已连接套接字上,接收并处理读写请求,或是将数据发送给客户端。

单线程模型:

listenSocket = socket(); //调用socket系统调用创建一个主动套接字
bind(listenSocket); //绑定地址和端口
listen(listenSocket); //将默认的主动套接字转换为服务器使用的被动套接字,也就是监听套接字
while (1) { //循环监听是否有客户端连接请求到来
  connSocket = accept(listenSocket); //接受客户端连接
  recv(connsocket); //从客户端读取数据,只能同时处理一个客户端
  send(connsocket); //给客户端返回数据,只能同时处理一个客户端
}

多线程模型,使用多线程来提升服务器端的并发客户端处理能力。

listenSocket = socket(); //调用socket系统调用创建一个主动套接字
bind(listenSocket); //绑定地址和端口
listen(listenSocket); //将默认的主动套接字转换为服务器使用的被动套接字,即监听套接字
while (1) { //循环监听是否有客户端连接到来
  connSocket = accept(listenSocket); //接受客户端连接,返回已连接套接字
  pthread_create(processData, connSocket); //创建新线程对已连接套接字进行处理
}
//处理已连接套接字上的读写请求
processData(connSocket){
  recv(connsocket); //从客户端读取数据,只能同时处理一个客户端
  send(connsocket); //给客户端返回数据,只能同时处理一个客户端
}

二、IO多路复用(Reactor的技术实现)

功能差异:

select机制与使用
Linux 针对每一个套接字都会有一个文件描述符,也就是一个非负整数,用来唯一标识该套接字。所以,在多路复用机制的函数中,Linux 通常会用文件描述符作为参数。有了文件描述符,函数也就能找到对应的套接字,进而进行监听、读写等操作。

select函数:

select 机制中的一个重要函数就是 select 函数。
int select (int __nfds, fd_set *__readfds, fd_set *__writefds, fd_set *__excep, int *__timeout)

参数说明:
1)监听的文件描述符数量,__nfds
2)被监听描述符的三个集合,__readfds、__writefds和*__exceptfds
__readfds:读数据事件
__writefds:写数据事件
__exceptfds:异常事件
3)监听时阻塞等待的超时时长,*__timeout

# fd_set 结构体
## __fd_mask类型是 long int 类型的别名,
## __FD_SETSIZE 和 __NFDBITS 这两个宏定义的大小默认为 1024 和 32
typedef struct {
  …
  __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
  …
} fd_set

所以,fd_set 结构体的定义,其实就是一个 long int 类型的数组,该数组中一共有 32 个
元素(1024/32=32),每个元素是 32 位(long int 类型的大小),而每一位可以用来表
示一个文件描述符的状态。
在这里插入图片描述

使用 select 函数,进行并发客户端处理的关键步骤和主要函数调用:

int sock_fd,conn_fd; //监听套接字和已连接套接字的变量
sock_fd = socket() //创建套接字
bind(sock_fd) //绑定套接字
listen(sock_fd) //在套接字上进行监听,将套接字转为监听套接字
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值