一、参数介绍
#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>
int select(int nfds,fd_set* readfds,fd_set* writefds,fd_set* exceptfds,struct timeval* timeout);
-参数:
nfds:指定被监听文件的文件描述符的总数。通常被设置为select监听的所有文件描述符中的最大值加1,因为文件描述符是从1开始计数的。
readfds:可读文件描述符的集合
writefds:可写文件描述符的集合
exceptfds:异常事件文件描述符的集合
timeout:用来设置select函数的超时时间。
struct timeval{
long tv_sec; /*秒数*/
long tv_usec; /*微秒*/
}
-NULL 则select将一直阻塞,直到某个文件描述符就绪
-tv_sec = 0 tv_usec = 0, 不阻塞
-tv_sec > 0 tc_usec > 0, 阻塞对应的时间
-返回值:
- -1:失败
- >0(n):检测的集合中有n个文件描述符发生了变化
- 0:超时时间内没有任何文件描述符就绪
void FD_ZERO(FD_SET* fdset);//fd_set一共有1024bit,全部初始化为0
void FD_SET(int fd,fd_set* fdset);//将参数文件描述符fd 对应的标志位,设置为1
void FD_CLR(int fd,fd_set* fdset); //将参数文件描述符fd对应的标志位设置为0
int FD_ISSET(int fd,fd_set* fdset);//判断fd对应的标志位是0还是1,返回值:fd对应的标志位的值,0,返回0,1,返回1
二、代码实现
1.服务器端
代码如下(示例):
#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/select.h>
int main()
{
//创建socket
int lfd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in saddr;
saddr.sin_port = htons(9999);
saddr.sin_family=AF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
//绑定
bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
//监听
listen(lfd, 5);
//创建一个fd_set集合,存放的是需要检测的文件描述符
fd_set rdset,tmp;
FD_ZERO(&rdset);
FD_SET(lfd, &rdset);
int maxfd = lfd;
while(1)
{
tmp = rdset;
//调用select系统函数,让内核帮检测那些文件描述符有数据
int ret = select(maxfd + 1, &tmp, NULL, NULL, NULL);
if(ret == -1)
{
perror("select");
exit(0);
}else if(ret == 0)
{
continue;
}else if(ret>0)
{
//说明检测到了有文件描述符的对应的缓冲区的数据发生了改变
if(FD_ISSET(lfd,&tmp))
{//表示有新的客户端连接进来了
struct sockaddr_in caddr;
int len = sizeof(caddr);
int cfd = accept(lfd, (struct sockaddr *)&caddr, &len);
//将新的文件描述符加入到集合中
FD_SET(cfd, &rdset);
maxfd = maxfd > cfd ? maxfd : cfd;
}
for (int i = lfd + 1; i <= maxfd; i++)
{
if(FD_ISSET(i,&tmp))
{//说明这个文件描述符对应的客户端发来了数据
char buf[1024] = {0};
int len = read(i, buf, sizeof(buf));
if(len==-1)
{
perror("read");
}else if(len==0)
{
printf("client closed...\n");
close(i);
FD_CLR(i, &rdset);
}else if(len>0)
{
printf("read buf=%s\n", buf);
write(i, buf, strlen(buf) + 1);
}
}
}
}
}
close(lfd);
return 0;
}
2.客户端
代码如下(示例):
#include<stdio.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main()
{
//1.创建套接字
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd==-1)
{
perror("socket");
exit(-1);
}
//2.连接服务器
struct sockaddr_in saddr;
inet_pton(AF_INET, "182.61.11.197", &saddr.sin_addr.s_addr);
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9999);
//连接服务器
int ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if(ret==-1)
{
perror("connet");
exit(-1);
}
//3.通信
char recvbuf[1024] = {0};
int i = 0;
int num = 0;
while (1)
{
char sendbuf[1024] = {0};
sprintf(sendbuf, "send data %d", num++);
write(fd, sendbuf, strlen(sendbuf) + 1);
//接收
int len = read(fd, sendbuf, sizeof(sendbuf));
if(len==-1)
{
perror("read");
return -1;
}else if(len>0)
{
printf("read buf = %s\n", sendbuf);
}else{
printf("服务器已经断开连接...\n");
break;
}
usleep(1000);
}
//关闭连接
close(fd);
return 0;
}