我们知道用socket进行通信时,发送数据和接收数据所使用的recv/send函数会阻塞进程,只有收到或发送数据后才能返回值,导致是socket通信只能实现服务器和客户端交替收发数据,而使用select可以很好地解决这个问题。
诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。可是使用Select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。
select函数的原型:int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval*timeout); 关于select函数的用法和作用,大家看看这个帖子
http://blog.youkuaiyun.com/piaojun_pj/article/details/5991968/
这个帖子已经讲的很详细了,大家可以看一看,关于select如何解决socket的异步通信问题,个人的理解:select的作用在于,以轮询的方式 同时对“自己有无发送数据” “对方有无发送数据”同时进行监控。而每次检测的时间限制为 struct timeval * timeout 中自己设置的时间,在检测的这段时间内,进程/线程会阻塞。这样就可以不断地交替对“ 是否发送了数据”和“是否接收到数据”进行不断交替检测,这样,进程就不会被recv或是send阻塞,从而实现了异步通信。
代码如下:
服务器 server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <iostream>
#include <stdlib.h>
#include <netinet/in.h>
#define PORT 7000
#define QUEUE 20
int main() {
fd_set rfds;
struct timeval tv;
int retval, maxfd;
int listenfd= socket(AF_INET, SOCK_STREAM, 0);
//设置地址可重复方式
int opt = SO_REUSEADDR;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof