我的应用程序只有1个用于recv()和send()的Unix TCP套接字。套接字是非阻塞的。鉴于此,在send()/ recv()之前执行select()是否有优势?
如果底层TCP管道尚未准备好进行I / O,则send()/ recv()应立即返回EWOULDBLOCK或EAGAIN。那么,做一个select()有什么意义呢?看起来,在这种情况下,它可能只会导致额外的系统调用开销。我错过了什么吗?
编辑:忘记提及:该应用程序是单线程的。
答案 0 :(得分:2)
如果你的套接字是非阻止,那么你需要select
(或者最好是poll
,它没有FD_SETSIZE
限制和相关的危险)阻止你代替send
和recv
中将要发生的阻塞(如果套接字不是非阻塞)。否则你会旋转,使用100%的CPU时间来做任何事情。在大多数情况下,您可以轻松地阻止套接字并取消select
/ poll
。但是,有一个有趣的案例需要考虑:如果您的程序在send
中被阻止,并且套接字另一端的程序也在{{1}中被阻止,则阻止IO 可能死锁(或相反)。使用非阻塞IO和send
/ select
,您可以自然地检测到这种情况,并在无法编写输出时处理挂起的输入。
答案 1 :(得分:1)
你可以在循环中执行recv(),但是你会消耗大量的CPU时间。
最好等待select()以避免额外的CPU开销。如果您需要执行后台任务,请为select()添加超时,以便即使没有网络流量也可以定期唤醒。
答案 2 :(得分:0)
如果你的应用程序是letency敏感的,那么可能有理由在没有select()的情况下在一个紧密的recv()循环中旋转,并给它一个专用的CPU(否则调度程序将惩罚它,你最终会有大量的延迟)。如果您的应用程序无法承受,但仍然可以通过一个线程来为此套接字提供服务,那么只需在读取端进行套接字阻塞,让调度程序在数据可用时唤醒您的线程。在发送方面再次取决于你需要什么,或者使套接字阻塞或旋转。
只有当你的应用程序是单线程的并且逻辑是“receive-process-reply”时,你绝对需要一个非阻塞的读/写套接字,选择器和一个写队列,以便你在数据到达时接收进程,对队列进行陷阱响应,注册可写性,在可写时将队列刷新到套接字,从可写性中取消注册。可读性应始终注册。