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 ...
随机推荐
- 租房数据分析,knn算法使用
import numpy as np import pandas as pd import matplotlib.pyplot as plt data = pd.read_excel('jiemo.x ...
- lambda函数小结
C++中的lambda函数 lambda函数是函数式编程中的概念,由C++11引入,成为现代C++中重要的特性. 所谓lambda函数就是匿名函数,语法结构: [capture list] (para ...
- 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU硬件那些事(2.4)- 串行NOR Flash下载算法(Keil MDK工具篇)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是Keil MDK工具下i.MXRT的串行NOR Flash下载算法设计. 在i.MXRT硬件那些事系列之<在串行NOR Flash ...
- linux mount挂载命令
[root@localhost src]# mount 查询系统中已经挂载的设备 [root@localhost src]# mount -a 依据配置文件 /etc/fstab的内容,自动挂载
- Spring Boot入门系列(二十一)如何优雅的设计 Restful API 接口版本号,实现 API 版本控制!
前面介绍了Spring Boot 如何快速实现Restful api 接口,并以人员信息为例,设计了一套操作人员信息的接口.不清楚的可以看之前的文章:https://www.cnblogs.com/z ...
- python中实现格式化输入(史上最简单、最高效的实现方法,不借助任何模块)
今天我在写python作业时突然想到格式化输入一段文字,譬如只需读取输入的前几个字符就行,而不幸的是,python中的输入并没有c中的read().getchar()函数,于是我网上搜了一下,网上的解 ...
- java 常用快捷键及命令积累
ctl + shift + o--->导入所需包,删掉没有被引用的包 ctl + / --->添加多行注释 ctl + \--->删除多行注释
- springboot配置定时任务并发执行
@Configuration public class ScheduleConfig implements SchedulingConfigurer { @Override public void c ...
- Redis学习笔记(八)——持久化
一.介绍 Redis的所有的数据都存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为"半持久化模式"):也可以把每一次数据变化都写入到一个append only file(a ...
- 使用Node.js给图片加水印的方法
一.准备工作: 首先,确保你本地已经安装好了node环境. 然后,我们进行图像编辑操作需要用到一个Node.js的库:images. 这个库的地址是:https://github.com/zhangy ...