select 读数据

本文探讨 BSD Socket 中 select() 系统调用的使用方法及其如何实现消息驱动机制,包括 FD_ACCEPT、FD_READ 和 FD_CLOSE 的实现,并介绍如何在非阻塞 connect 中运用 select 进行监测。

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

本文出自:   作者:   (2001-09-13   09:00:00)    
  发信站:   华南网木棉站   (Tue   Aug     4   15:43:41   1998),   转信      
   
  【   原文由   cpu   所发表   】      
       
  用过   WinSock   API   网友们知道:WinSock   编程中有一很方便的地方便是其      
  息驱动机制,不管是底层   API   的   WSAAsyncSelect()   还是   MFC   的异步Socket类:      
  CAsyncSocket,都提供了诸如   FD_ACCEPT、FD_READ、FD_CLOSE   之类的消息      
  供编程人员捕捉并处理。FD_ACCEPT   通知进程有客户方Socket请求连接,      
  FD_READ通知进程本地Socket有东东可读,FD_CLOSE通知进程对方Socket已      
  关闭。那么,BSD   Socket   是不是真的相形见拙呢?      
       
  非也!   'cause   cpu   love   unix   so.      
       
  BSD   UNIX中有一系统调用芳名select()完全可以提供类似的消息驱动机制。      
  cpu郑重宣布:WinSock的WSAAsyncSeclet()不过是此select()的fork版!      
       
  bill也是fork出来的嘛,xixi.      
       
  select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组,      
  每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他      
  文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,      
  当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执      
  行了select()的进程哪一Socket或文件可读,下面具体解释:      
       
  #include     <sys/types.h>      
  #include     <sys/times.h>      
  #include     <sys/select.h>      
       
  int   select(nfds,   readfds,   writefds,   exceptfds,   timeout)      
  int   nfds;      
  fd_set   *readfds,   *writefds,   *exceptfds;      
  struct   timeval   *timeout;      
       
  ndfs:select监视的文件句柄数,视进程中打开的文件数而定,一般设为呢要监视各文件      
              中的最大文件号加一。      
  readfds:select监视的可读文件句柄集合。      
  writefds:   select监视的可写文件句柄集合。      
  exceptfds:select监视的异常文件句柄集合。      
  timeout:本次select()的超时结束时间。(见/usr/sys/select.h,      
                  可精确至百万分之一秒!)      
       
  当readfds或writefds中映象的文件可读或可写或超时,本次select()      
  就结束返回。程序员利用一组系统提供的宏在select()结束时便可判      
  断哪一文件可读或可写。对Socket编程特别有用的就是readfds。      
  几只相关的宏解释如下:      
       
  FD_ZERO(fd_set   *fdset):清空fdset与所有文件句柄的联系。      
  FD_SET(int   fd,   fd_set   *fdset):建立文件句柄fd与fdset的联系。      
  FD_CLR(int   fd,   fd_set   *fdset):清除文件句柄fd与fdset的联系。      
  FD_ISSET(int   fd,   fdset   *fdset):检查fdset联系的文件句柄fd是否      
                                                                  可读写,>0表示可读写。      
  (关于fd_set及相关宏的定义见/usr/include/sys/types.h)      
       
  这样,你的socket只需在有东东读的时候才读入,大致如下:      
       
  ...      
  int           sockfd;      
  fd_set     fdR;      
  struct     timeval   timeout   =   ..;      
  ...      
  for(;;)   {      
                  FD_ZERO(&fdR);      
                  FD_SET(sockfd,   &fdR);      
                  switch   (select(sockfd   +   1,   &fdR,   NULL,   &timeout))   {      
                                  case   -1:      
                                                  error   handled   by   u;      
                                  case   0:      
                                                  timeout   hanled   by   u;      
                                  default:      
                                                  if   (FD_ISSET(sockfd))   {      
                                                                  now   u   read   or   recv   something;      
                                                                  /*   if   sockfd   is   father   and        
                                                                  server   socket,   u   can   now      
                                                                  accept()   */      
                                                  }      
                  }      
  }      
       
  所以一个FD_ISSET(sockfd)就相当通知了sockfd可读。      
  至于struct   timeval在此的功能,请man   select。不同的timeval设置      
  使使select()表现出超时结束、无超时阻塞和轮询三种特性。由于      
  timeval可精确至百万分之一秒,所以Windows的SetTimer()根本不算      
  什么。你可以用select()做一个超级时钟。      
       
  FD_ACCEPT的实现?依然如上,因为客户方socket请求连接时,会发送      
  连接请求报文,此时select()当然会结束,FD_ISSET(sockfd)当然大      
  于零,因为有报文可读嘛!至于这方面的应用,主要在于服务方的父      
  Socket,你若不喜欢主动accept(),可改为如上机制来accept()。      
       
  至于FD_CLOSE的实现及处理,颇费了一堆cpu处理时间,未完待续。      
       
  --      
  讨论关于利用select()检测对方Socket关闭的问题:      
       
  仍然是本地Socket有东东可读,因为对方Socket关闭时,会发一个关闭连接      
  通知报文,会马上被select()检测到的。关于TCP的连接(三次握手)和关      
  闭(二次握手)机制,敬请参考有关TCP/IP的书籍。      
       
  不知是什么原因,UNIX好象没有提供通知进程关于Socket或Pipe对方关闭的      
  信号,也可能是cpu所知有限。总之,当对方关闭,一执行recv()或read(),      
  马上回返回-1,此时全局变量errno的值是115,相应的sys_errlist[errno]      
  为"Connect   refused"(请参考/usr/include/sys/errno.h)。所以,在上      
  篇的for(;;)...select()程序块中,当有东西可读时,一定要检查recv()或      
  read()的返回值,返回-1时要作出关断本地Socket的处理,否则select()会      
  一直认为有东西读,其结果曾几令cpu伤心欲断针脚。不信你可以试试:不检      
  查recv()返回结果,且将收到的东东(实际没收到)写至标准输出...      
  在有名管道的编程中也有类似问题出现。具体处理详见拙作:发布一个有用      
  的Socket客户方原码。      
       
  至于主动写Socket时对方突然关闭的处理则可以简单地捕捉信号SIGPIPE并作      
  出相应关断本地Socket等等的处理。SIGPIPE的解释是:写入无读者方的管道。      
  在此不作赘述,请详man   signal。      
       
  以上是cpu在作tcp/ip数据传输实验积累的经验,若有错漏,请狂炮击之。      
       
  唉,昨天在hacker区被一帮孙子轰得差点儿没短路。ren   cpu(奔腾的心)   z80      
       
  补充关于select在异步(非阻塞)connect中的应用,刚开始搞socket编程的时候      
  我一直都用阻塞式的connect,非阻塞connect的问题是由于当时搞proxy   scan      
  而提出的呵呵      
  通过在网上与网友们的交流及查找相关FAQ,总算知道了怎么解决这一问题.同样      
  用select可以很好地解决这一问题.大致过程是这样的:      
       
  1.将打开的socket设为非阻塞的,可以用fcntl(socket,   F_SETFL,   O_NDELAY)完      
  成(有的系统用FNEDLAY也可).      
       
  2.发connect调用,这时返回-1,但是errno被设为EINPROGRESS,意即connect仍旧      
  在进行还没有完成.      
       
  3.将打开的socket设进被监视的可写(注意不是可读)文件集合用select进行监视,      
  如果可写,用      
                  getsockopt(socket,   SOL_SOCKET,   SO_ERROR,   &error,   sizeof(int));      
  来得到error的值,如果为零,则connect成功.      
       
  在许多unix版本的proxyscan程序你都可以看到类似的过程,另外在solaris精华      
  区->编程技巧中有一个通用的带超时参数的connect模块.       
     
### 如何在 Element UI 的 `el-select` 组件中实现数据字典选择 在前端开发中,使用数据字典是一种常见的需求,尤其是在表单设计场景下。通过将数据字典绑定到 `el-select` 下拉框组件上,可以方便用户快速选择预定义选项。 #### 数据字典的概念 数据字典通常是一个键值对集合,其中键表示唯一标识符,而值则代表显示给用户的可名称[^1]。例如: ```javascript const dataDict = [ { value: '0', label: '未激活' }, { value: '1', label: '已激活' } ]; ``` 上述代码片段展示了一个简单的数据字典结构,它由对象数组组成,每个对象包含两个属性:`value` 和 `label`。这种形式的数据可以直接用于 `el-select` 绑定。 #### 实现方式 为了使 `el-select` 支持动态加载数据字典并允许用户选择特定项,可以通过以下方法完成配置: ##### 1. 使用 `v-model` 双向绑定选中的值 `el-select` 提供了内置的双向绑定功能,能够实时更新所选值的状态。以下是基本用法示例: ```vue <template> <div> <!-- el-select 配置 --> <el-select v-model="selectedValue" placeholder="请选择"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> </div> </template> <script> export default { data() { return { selectedValue: '', // 当前选中的值 options: [ // 数据字典列表 { value: '0', label: '未激活' }, { value: '1', label: '已激活' } ] }; } }; </script> ``` 在此模板中,`options` 数组存储的是数据字典的内容,而 `selectedValue` 则保存当前被选中的值[^2]。 ##### 2. 动态获取远程数据字典 如果数据字典来源于服务器端 API,则可通过异步请求来填充 `options` 属性。下面展示了如何结合 Axios 获取远端数据字典的例子: ```javascript import axios from 'axios'; export default { data() { return { selectedValue: '', options: [] }; }, created() { this.fetchDataDictionary(); }, methods: { async fetchDataDictionary() { try { const response = await axios.get('/api/data-dictionary'); this.options = response.data.map(item => ({ value: item.id, label: item.name })); } catch (error) { console.error('Failed to fetch data dictionary:', error); } } } }; ``` 此脚本会在组件初始化阶段调用 `fetchDataDictionary()` 方法从指定 URL 加载数据字典,并将其转换成适合 `el-select` 使用的形式[^3]。 #### 注意事项 - **性能优化**:当数据量较大时,建议启用分页或者模糊查询等功能减少一次性渲染的压力。 - **错误处理**:对于网络异常情况应有妥善提示机制以免影响用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值