赞
踩
select函数可以实现非阻塞方式的程序。它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。
**int select(int maxfdp,fd_set readfds,fd_set writefds,fd_set errorfds,struct timevaltimeout);
头文件:#include <sys/select.h>
maxfdp是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1。
readfds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。
writefds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。
errorfds同上面两个参数的意图,用来监视文件错误异常。
timeout是select的超时时间,这个参数至关重要,它可以使select处于三种状态。
第一:若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;
第二:若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;
第三:timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。
返回值:
负值:select错误;
正值:某些文件可读写或出错;
0:等待超时,没有可读写或错误的文件。
原文链接:https://blog.csdn.net/mayue_web/article/details/89021273
服务器
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define SIZE 1024
int main()
{
int ret;
int fd[SIZE] = {0};
//创建socket(文件)
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
//IPV4地址族 流式套接字(TCP) 具体的协议类型(默认0)
if (-1 == sockfd)
{
perror("socket");
exit(1);
}
int opt = 1;
setsockopt(sockfd,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
//设置地址可以被复用(方便调试)
struct sockaddr_in server_addr; //保存服务器本身的信息
struct sockaddr_in client_addr; //保存客户端的信息
memset(&server_addr, 0, sizeof(server_addr)); //清空结构体
server_addr.sin_family = PF_INET; //地址族 同socket第一个参数
server_addr.sin_port = 7000;
//端口号(大于1024 小于65536) 客户地址可以被复用(方便调试)
//查满手册,包含头文件 man inet_addr
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
//ip地址 ifconfig> 获取 127.0.0.1回环ip(用于测试)
//绑定信息
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) ;
if (-1 == ret)
{
perror("bind");
exit(1);
}
//设置监听队列
ret = listen(sockfd, 10);
if (-1 == ret)
{
perror("listen");
exit(1);
}
fd_set readfd, tmpfd; //集合
FD_ZERO(&readfd); //清空集合
FD_SET(sockfd, &readfd); //把sockfd添加到集合
int maxfd = sockfd;
int length = sizeof(struct sockaddr_in);
int i;
char buf[128] = {0};
while (1)
{
tmpfd = readfd; //select每次会清空集合
ret = select(maxfd + 1, &tmpfd, NULL, NULL, NULL);
//最后一个NULL表示阻塞
if (-1 == ret)
{
perror("select");
exit(1);
}
if (FD_ISSET(sockfd, &tmpfd)) //判断是否有客户端发起连接
{
printf("有客户端发起连接...\n");
for (i = 0; i < SIZE; i++)
{
if (0 == fd[i])
{
break;
}
}
fd[i] = accept(sockfd, (struct sockaddr *)&client_addr, &length) ;
if (-1 == fd[i])
{
perror("accept");
exit(1);
}
printf("接受客户端%d的连接!\n", fd[i]);
if (fd[i] > maxfd)
{
maxfd = fd[i];
}
FD_SET(fd[i], &readfd);
}
else //有客户端发消息
{
for (i = 0; i < SIZE; i++)
{
if (FD_ISSET(fd[i], &tmpfd)) //判断哪个文件描述符可读
{
ret = recv(fd[i], buf, sizeof(buf), 0);
if (-1 == ret)
{
perror("recv");
exit(1);
}
if (0 == ret)
{
printf("客户端%d异常下线\n", fd[i]);
close(fd[i]); //关闭TCP连接
FD_CLR(fd[i], &readfd); //从集合中清除
fd[i] = 0;
break;
}
if (!strcmp(buf, "bye"))
{
printf("客户端%d下线!\n", fd[i]);
close(fd[i]); //关闭TCP连接
FD_CLR(fd[i], &readfd); //从集合中清除
fd[i] = 0;
break;
}
printf("收到%d客户端消息%s\n", fd[i], buf);
memset(buf, 0, sizeof(buf));
break;
}
}
}
}
return 0;
}
客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sockfd = socket(PF_INET, SOCK_STREAM, 0)
if (-1 == sockfd)
{
perror("socket");
exit(1);
}
//客户端向服务器发起连接
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
//跟服务器保持一致
server_addr.sin_family = PF_INET;
server_addr.sin_port = 7000;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
int ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (-1 == ret)
{
perror("connect");
exit(1);
}
char buf[128] = {0};
while (1)
{
scanf("%s", buf);
ret = send(sockfd, buf, strlen(buf), 0); //write
if (-1 == ret)
{
perror("send");
exit(1);
}
if (!strcmp(buf, "bye"))
{
break;
}
}
close(sockfd); //关闭TCP连接
return 0;
}
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。