首先需要了解的是select函数:
#include<sys/select.h>
#include<sys/time.h>
int select (int maxfd , fd_set *readset ,fd_set *writeset, fd_set *exceptionset , const struct timeval * timeout);
返回:就绪描述字的正数目,0——超时,-1——出错
参数解释:
maxfd: 最大的文件描述符(其值应该为最大的文件描述符字 + 1)
readset: 内核读操作的描述符字集合
writeset:内核写操作的描述符字集合
exceptionset:内核异常操作的描述符字集合
timeout:等待描述符就绪需要多少时间。NULL代表永远等下去,一个固定值代表等待固定时间,0代表根本不等待,检查描述字之后立即返回。
注意:readset,writeset,exceptionset都是值-结果参数,意思就是他们传进入指针进去,函数根据指针可以修改对应的fd_set
fd_set和名字一样,是一个描述符的集合。有下面几个操作:
void FD_ZERO(fd_set *fdset); /* 将所有fd清零 */
void FD_SET(int fd, fd_set *fdset); /* 增加一个fd */
void FD_CLR(int fd, fd_set *fdset); /* 删除一个fd */
int FD_ISSET(int fd, fd_set *fdset); /* 判断一个fd是否有设置 */
我们现在要做一个select使用的server,server监听两个端口(7778和7779)的socket。再使用两个cli,一个client连接到7778端口,另一个client连接到7779端口。
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
//这个服务器同时监听7777和7778两个端口
//绑定监听7779端口的fd
int listenfd1;
struct sockaddr_in serv_addr1;
listenfd1 = socket(AF_INET, SOCK_STREAM, 0);
bzero((char *) &serv_addr1, sizeof(serv_addr1));
serv_addr1.sin_family = AF_INET;
serv_addr1.sin_port = htons(7777);
serv_addr1.sin_addr.s_addr = INADDR_ANY;
bind(listenfd1, (struct sockaddr *) &serv_addr1, sizeof(serv_addr1));
listen(listenfd1, 5);
//绑定监听7778端口的fd
int listenfd2;
struct sockaddr_in serv_addr2;
listenfd2 = socket(AF_INET, SOCK_STREAM, 0);
bzero((char *) &serv_addr2, sizeof(serv_addr2));
serv_addr2.sin_family = AF_INET;
serv_addr2.sin_port = htons(7778);
serv_addr2.sin_addr.s_addr = INADDR_ANY;
bind(listenfd2, (struct sockaddr *) &serv_addr2, sizeof(serv_addr2));
listen(listenfd2, 5);
int maxfd;
//为什么这里设置两个fd_set?每次select的时候函数会把没有事件发生的描述字清零,所以需要两个集合
fd_set allset, rset;
maxfd = listenfd1;
if(listenfd2 > maxfd) {
maxfd = listenfd2;
}
FD_ZERO(&allset);
FD_SET(listenfd1, &allset);
FD_SET(listenfd2, &allset);
int clifd, clilen;
struct sockaddr_in cli_addr;
char buffer[256];
for(;;) {
rset = allset;
select(maxfd + 1, &rset, NULL, NULL, NULL);
//如果是listenfd1 获取消息
if(FD_ISSET(listenfd1, &rset)) {
clilen = sizeof(cli_addr);
clifd = accept(listenfd1, (struct sockaddr *) &cli_addr, &clilen);
bzero(buffer, 256);
read(clifd, buffer, 255);
printf("Listenfd1 Message is:%s\r\n", buffer);
}
//如果是listenfd1 获取消息
if(FD_ISSET(listenfd2, &rset)) {
clilen = sizeof(cli_addr);
clifd = accept(listenfd2, (struct sockaddr *) &cli_addr, &clilen);
bzero(buffer, 256);
read(clifd, buffer, 255);
printf("Listenfd2 Message is:%s\r\n", buffer);
}
close(clifd);
}
close(listenfd1);
close(listenfd2);
return 0;
}