select限制之文件描述符限制
1、一个进能够打开的最大文件描述符限制。可以通过两种方式修改
ulimit -n :获取最大文件描述符个数
ulimit -n 2048:修改为2048个
该限制的测试代码:
客户端程序:
/*
1、select受最大文件描述符限制。测试程序如下
2、select的fd_set集合容量的限制(FD_SIZE),在头文件中限制。
*/
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include <sys/time.h> #include <sys/resource.h>
#define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0);
//为何要使用sleep来推迟ERR_EXIT(). 客户端除去 0 、1、2描述符,创建了1021个描述符。在创建1022个套接字时,失败了,失败之后进程退出,发送许多FIN给服务器端。服务器端已完成连接队列中维护了1021个条目。正好有FIN之后,可以空出套接字处理第1021个条目。如果延迟客户端的退出服务器端就只有1020个了。
int main(void)
{
int count=0;
while(1)
{ int sock;
if((sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
{
sleep(5);//推迟客户端的close(便于准确查看服务器端到底能接受多少连接).按理说服务器端只能接受1020个,但是中间有客户端口关闭使得服务端口能够重复利用,使得服务器端也能使用1021个描述符(0,1,2,3(监听套接口)),如果不推迟,创建第1022个套接口时,客户端退出进程,前面的1021个套接口要发送FIN,close和accept交替
ERR_EXIT("socket");
}
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(5188);
servaddr.sin_addr.s_addr=inet_addr("127.0.0.1"); if(connect(sock,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
ERR_EXIT("connect");//创建第1022个套接字失败。 0,1,2已经打开。 1024个
struct sockaddr_in localaddr;
socklen_t addrlen=sizeof(localaddr);
if(getsockname(sock,(struct sockaddr *)&localaddr,&addrlen)<0)
ERR_EXIT("getsockname");
printf("ip=%s port=%d\n",inet_ntoa(localaddr.sin_addr),ntohs(localaddr.sin_port));
printf("count=%d\n",++count);
}
return 0; }
服务器端程序:
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include<sys/wait.h>
#define ERR_EXIT(m)\
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
ssize_t readn(int fd,void *buf,size_t count)
{
size_t nleft=count;
ssize_t nread;
char *bufp=(char*)buf;
while(nleft>0)
{
if((nread=read(fd,bufp,nleft))<0)
{
if(errno==EINTR)
continue;
else
return -1;
}
else if(nread==0)
return (count-nleft);
bufp+=nread;
nleft-=nread;
}
return count;
}
ssize_t writen(int fd, const void *buf, size_t count)
{
size_t nleft=count;
ssize_t nwritten;
char *bufp=(char*)buf;
while(nleft>0)
{
if((nwritten=write(fd,bufp,nleft))<=0)
{
if(errno==EINTR)
continue;
return -1;
}else if(nwritten==0)
continue;
bufp+=nwritten;
nleft-=nwritten;
}
return count; }
ssize_t recv_peek(int sockfd,void *buf,size_t len)
{
while(1)
{
int ret=recv(sockfd,buf,len,MSG_PEEK);//从sockfd读取内容到buf,但不去清空sockfd,偷窥
if(ret==-1&&errno==EINTR)
continue;
return ret;
}
}
//偷窥方案实现readline避免一次读取一个字符
ssize_t readline(int sockfd,void * buf,size_t maxline)
{
int ret;
int nread;
size_t nleft=maxline;
char *bufp=(char*)buf;
while(1)
{
ret=recv_peek(sockfd,bufp,nleft);//不清除sockfd,只是窥看
if(ret<0)
return ret;
else if(ret==0)
return ret;
nread=ret;
int i;
for(i=0;i<nread;i++)
{
if(bufp[i]=='\n')
{
ret=readn(sockfd,bufp,i+1);//读出sockfd中的一行并且清空
if(ret!=i+1)
exit(EXIT_FAILURE);
return ret;
}
}
if(nread>nleft)
exit(EXIT_FAILURE);
nleft-=nread;
ret=readn(sockfd,bufp,nread);
if(ret!=nread)
exit(EXIT_FAILURE);
bufp+=nread;//移动指针继续窥看
}
return -1;
}
void handle_sigchld(int sig)
{ while(waitpid(-1,NULL, WNOHANG)>0)
; }
void handle_sigpipe(int sig)
{
printf("recevie a sig=%d\n",sig);//打印,不退出服务器进程
}
int main(void)
{
int count=0;//测试描述符限制
signal(SIGCHLD,handle_sigchld);
signal(SIGPIPE,handle_sigpipe);
int listenfd;
if((listenfd=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
ERR_EXIT("socket error");
//本地协议地址赋给一个套接字
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(5188);
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);//表示本机地址 //开启地址重复使用,关闭服务器再打开不用等待TIME_WAIT
int on=1;
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<0)
ERR_EXIT("setsockopt error");
//绑定本地套接字
if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
ERR_EXIT("bind error");
if(listen(listenfd,SOMAXCONN)<0)//设置监听套接字(被动套接字)
ERR_EXIT("listen error"); struct sockaddr_in peeraddr;//对方套接字地址
socklen_t peerlen=sizeof(peeraddr); int client[FD_SETSIZE];//select最大文件描述符,用来保存已连接文件描述符。
int i=0;
for(i=0;i<FD_SETSIZE;i++)
{
client[i]=-1;
}
int conn;//已连接套接字(主动套接字)
int nready;
int maxi=0;//最大不空闲位置
int maxfd=listenfd;
fd_set rset,allset;
FD_ZERO(&rset);
FD_ZERO(&allset);
FD_SET(listenfd,&allset);
while(1)
{
rset=allset;
nready=select(maxfd+1,&rset,NULL,NULL,NULL);//如果是监听套接口(服务器),已完成连接队列不为空时,accept不再阻塞;
if(nready==-1)
{
if(errno==EINTR)
continue;
ERR_EXIT("select error");
}
if(nready==0)
continue;
if(FD_ISSET(listenfd,&rset))//监听口有事件,已完成队列不为空
{
conn=accept(listenfd,(struct sockaddr*)&peeraddr,&peerlen);
if(conn==-1)
ERR_EXIT("accept error");
for(i=0;i<FD_SETSIZE;i++)
{
if(client[i]<0)
{
client[i]=conn;
if(i>maxi)
maxi=i;//更新最大不空闲位置
break;
} }
if(i==FD_SETSIZE)
{
fprintf(stderr,"too many clents\n");
exit(EXIT_FAILURE);
}
printf("ip=%s port=%d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port)); printf("%d\n",++count);//服务器端口应该是1020. 0,1,2和监听的套接口用掉四个 //select的fd_set集合容量的限制
FD_SET(conn,&allset);//将已连接套接字描述符放入allset,用于监测已连接套接口是否有客户端数据到来
if(conn>maxfd)
maxfd=conn;//更新maxfd
if(--nready<=0)
continue;//如果事件已经处理完,就继续循环监听,不再执行以下代码 }
for(i=0;i<=maxi;i++)//小于等于
{
conn=client[i];
if(conn==-1)
continue;
//已经连接套接字是否有事件,不用while(1)循环处理客户端发送,有select监听。
if(FD_ISSET(conn,&rset))
{
int ret;
char recvbuf[1024];
memset(&recvbuf,0,sizeof(recvbuf));
ret=readline(conn,recvbuf,1024);
if(ret==-1)
ERR_EXIT("readline");
else if(ret==0)
{
printf("client close\n");
FD_CLR(conn,&allset);//客户端清理,select就不用去监听
client[i]=-1;
close(conn);//前面程序BUG,对方关闭之后,我们服务器也要关闭套接口。让客户端接收到通知
}
fputs(recvbuf,stdout);
writen(conn,recvbuf,strlen(recvbuf));//write :aaa bbb ,RST,写aaa接收bbb,再bbb,有了SIGPIPE
if(--nready==0)
continue;
}
}
}
return 0;
}
select限制之文件描述符限制的更多相关文章
- 关于信号打断正在读取终端的read与select来监视0文件描述符的问题
首先说一下对于这个问题外的一些话: 我觉得我们应该有种质疑的态度,因为接下来的这个问题就和我们平常所想的不一样. 介绍一下问题: 曾经一直听说信号可以打断一个正在阻塞的进程,但是今天我试了一下关于信号 ...
- Linux下利用文件描述符恢复的成功失败实验
1.测试环境准备[oracle@redhat3 ~]$ uname -aLinux redhat3 2.6.32-573.el6.x86_64 #1 SMP Wed Jul 1 18:23:37 ED ...
- 误删除innodb ibdata数据文件 文件句柄 文件描述符 proc fd
误删除innodb ibdata数据文件 文件句柄 文件描述符 proc fd http://www.cnblogs.com/gomysql/p/3702216.html 提示:如果不小心通过 ...
- 文件描述符、文件表项指针、inode节点的关系
内核使用3种数据结构表示打开的文件,他们之间的关系决定了在文件共享方面一个进程对另一个进程的影响. (1) 每个进程在进程表中都有一个纪录项,纪录项中包含一张打开文件描述符表,每个文件描述符各占一项, ...
- Linux内核笔记--深入理解文件描述符
内核版本:linux-2.6.11 文件描述符(file descriptor)在Linux编程里随处可见,设备读写.网络通信.进程通信,fd可谓是关键中的关键. 深入理解可以增加我们使用它的信心. ...
- Linux 利用进程打开的文件描述符(/proc)恢复被误删文件
Linux 利用进程打开的文件描述符(/proc)恢复被误删文件 在 windows 上删除文件时,如果文件还在使用中,会提示一个错误:但是在 linux 上删除文件时,无论文件是否在使用中,甚至是还 ...
- Linux 文件描述符和重定向
200 ? "200px" : this.width)!important;} --> 介绍 文件描述符是与文件输入.输出相关联的整数,在编写脚本时会经常使用标准的文件描述符 ...
- linux专题一之文件描述符、重定向、管道符、tee命令
本节讨论一下几个问题: 1. 文件描述符. 2. 重定向. 3. 管道符 4. tee的用法. 1. 文件描述符. 在linux系统中一切皆文件.文件夹和设备都是文件.如何用来区别不同的文件呢?这里的 ...
- CentOS最大文件描述符限制更改
系统级的限制:/proc/sys/fs/file-max中设定了系统最大能打开的文件数. 查看该值可以用如下方式: [root@#panda ~]# cat /proc/sys/fs/file-max ...
随机推荐
- JSX 详解
一 jsx 的本质是什么? jsx是语法糖,需要被编译成js才能运行. jsx 看似是html 结构,实质是js结构的语法糖,在代码编译阶段被编译成js结构.所以jsx的本质可描述为看似html结构的 ...
- 【C语言教程】“双向循环链表”学习总结和C语言代码实现!
双向循环链表 定义 双向循环链表和它名字的表意一样,就是把双向链表的两头连接,使其成为了一个环状链表.只需要将表中最后一个节点的next指针指向头节点,头节点的prior指针指向尾节点,链表就能成环儿 ...
- k8s- centos7.8搭建
vmware16.0 centos7.8 1. 使用vmware安装 centos环境 cpu4个 内存4G 网络nat模式 2.配置网络 vim /etc/sysconfig/network-sc ...
- Flutter Webview添加Cookie的正确姿势
场景 h5页面要从cookie里面取数据,所以需要在flutter webview的cookie里面塞一些数据,设置的数据多达十几条:按照网上查的使用方式来设置,通过fiddler抓包发现,只能生效一 ...
- LIS初级推算(最长上升子序列问题)
所谓LIS,就是Longest Increasing Subsequence问题 注意,子序列不一定是连续的,举个例子:对于序列10,9,2,3,5,4,7,9,101,18,其中的LIS就是2,3, ...
- 教师专用录微课及剪辑软件推荐-camtasia中文汉化破解版免费下载及使用教程
教师专用录微课软件,微课制作软件是一款能够制作文字.图形.动画.音视频等的软件,支持对ppt.word.flash的导入和录制,实时同步录制操作区文字.图形.动画.音视频.鼠标轨迹.声音及外部语音等动 ...
- Oracle一些常用操作语句
--创建oracle登录用户 create user CHECKDATAUSER identified by "bsoft" default tablespace PBPG ...
- django基础回顾
1,web项目工作流程 1.1 了解web程序工作流程 1.2 django生命周期2,django介绍 目的:了解Django框架的作用和特点 作用: 简便.快速的开发数据库驱动的网站 Django ...
- 谈谈OKHttp的几道面试题
来吧,今天说说常用的网络框架OKHttp,也是现在Android所用的原生网络框架(Android 4.4开始,HttpURLConnection的底层实现被Google改成了OkHttp),GOGO ...
- Zookeeper源码(启动+选举)
简介 关于Zookeeper,目前普遍的应用场景基本作为服务注册中心,用于服务发现.但这只是Zookeeper的一个的功能,根据Apache的官方概述:"The Apache ZooKeep ...