1 select

A:select能监听的文件描写叙述符个数受限于FD_SETSIZE,一般为1024。单纯改变进程打开

的文件描写叙述符个数并不能改变select监听文件个数

B:解决1024下面client时使用select是非常合适的,但假设链接client过多,select採用的是轮询模型,会大大减少server响应效率。不应在select上投入很多其它精力

2
依赖的头文件

#include <sys/select.h>

/* According to earlier standards */

#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:
监控的文件描写叙述符集里最大文件描写叙述符加1,由于此參数会告诉内核检測前多少个文件描写叙述符的状态

readfds:监控有读数据到达文件描写叙述符集合。传入传出參数

writefds:监控写数据到达文件描写叙述符集合,传入传出參数

exceptfds:监控异常发生达文件描写叙述符集合,如带外数据到达异常。传入传出參数

timeout:定时堵塞监控时间,3中情况

  1. NULL,永远等下去

  2. 设置timeval,等待固定时间

  3. 设置timeval里时间均为0,检查描写叙述字后马上返回,轮询。

struct timeval {

long tv_sec; /* seconds */

long tv_usec; /*
microseconds
 微秒;一百万分之中的一个秒*/

};

void FD_CLR(int fd,fd_set *set);
把文件描写叙述符集合里fd清零

int FD_ISSET(int fd,fd_set *set);
測试文件描写叙述符集合里fd是否置1

void FD_SET(int fd,fd_set *set);
把文件描写叙述符集合里fd位置1

void FD_ZERO(fd_set *set);   
把文件描写叙述符集合里全部位清0

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdG90b3R1enVvcXVhbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

select模型

案例说明:

Server.c

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

#include<netinet/in.h>

#include<arpa/inet.h>

#include<ctype.h>

#include<unistd.h>

#include"wrap.h"

#define MAXLINE 80

#define SERV_PORT 8000

int main(void)

{

int i,maxi,maxfd,listenfd,connfd,sockfd;

/*

* nready为select之后返回的被监控管理的数量,

* 最大的被管理的文件最大的被管理的文件描写叙述符的

* 数量是1024

*/

/*FD_SETSIZE默觉得1024*/

int nready,client[FD_SETSIZE]; /* FD_SETSIZE默觉得1024 */

ssize_t n;

fd_set rset,allset;

char buf[MAXLINE];

/*以下表示的是ip地址的长度*/

char str[INET_ADDRSTRLEN];   /*#define IN*/

socklen_t cliaddr_len;

struct sockaddr_in cliaddr,servaddr;

/*整个server仅仅有一个listenfd文件描写叙述符*/

//1、建立一个socket,案例中是针对TCP的

listenfd = Socket(AF_INET,SOCK_STREAM,0);

bzero(&servaddr,sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

servaddr.sin_port = htons(SERV_PORT);

//2、Bind

Bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

//3、正在链接的时候最大支持128个,当accept之后就无论了

Listen(listenfd,20); /*默认最大128*/

maxfd = listenfd;    /*初始化*/

maxi = -1;           /*client[]的下标*/

for(i = 0;i < FD_SETSIZE;i++){

client[i] = -1;  /*用-1初始化client*/

}

//将管理的文件描写叙述符集合的内容设置成为0

FD_ZERO(&allset);

//将listenfd纳入allset中进行管理

FD_SET(listenfd,&allset);   /*构造select监控文件描写叙述符集*/

for(;;){

/*每次循环时都又一次设置select监控信号集。这里相当于rset的一个备份*/

rset = allset;

//第一个參数是最大描写叙述的最大值+1

nready = select(maxfd+1,&rset,NULL,NULL,NULL);

if(nready < 0) {

perr_exit("select error");

}

//推断listenfd是否已经纳入管理

if(FD_ISSET(listenfd,&rset)) {

cliaddr_len = sizeof(cliaddr);

connfd = Accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len);

//打印ip地址和port号

printf("received from %s at PORT %d\n",

inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,str,sizeof(str)),

ntohs(cliaddr.sin_port));

for(i = 0;i < FD_SETSIZE;i++) {

if(client[i] < 0) {

client[i] = connfd;/*保存accept返回的文件描写叙述符到client[]里*/

break;

}

}

}   /*达到select能监控的文件个数上限1024*/

if(i == FD_SETSIZE) {

fputs("to many clients\n",stderr);

exit(1);

}

/*加入一个新的文件描写叙述符到监控信号集里*/

FD_SET(connfd,&allset);

if(connfd > maxfd)

maxfd = connfd; /*select第一个參数须要*/

if(i > maxi)

maxi = i;  /*更新client[]最大下标值*/

if(--nready == 0)

/*假设没有很多其它的就绪文件描写叙述符,继续回到上面select

* 负责处理未完毕的就绪文件描写叙述符*/

continue;

}

for(i = 0;i< maxi;i++) {

if((sockfd = client[i]) < 0)

continue;

if(FD_ISSET(sockfd,&rset)) {

if((n=Read(sockfd,buf,MAXLINE)) == 0) {

/*当client关闭链接时,server端也关闭链接*/

Close(sockfd);

/*解除select监控文件描写叙述符*/

FD_CLR(sockfd,&allset);

client[i] = -1;

} else {

int j;

for(j = 0; j< n;j++) {

buf[j] = toupper(buf[j]);

}

Write(sockfd,buf,n);

}

if(--nready == 0)

break;

}

}

Close(listenfd);

return 0;

}

Client.c

#include <stdio.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include"wrap.h"

#define MAXLINE 80

#define SERV_PORT 8000

int main(void) {

struct sockaddr_in servaddr;

char buf[MAXLINE];

int sockfd,n;

//1.Socket

sockfd = Socket(AF_INET,SOCK_STREAM,0);

//设置ip和port号等相关信息

bzero(&servaddr,sizeof(servaddr));

servaddr.sin_family = AF_INET;

inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);

servaddr.sin_port = htons(SERV_PORT);

//2.建立连接

Connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

while(fgets(buf,MAXLINE,stdin) != NULL) {

//3.Write数据

Write(sockfd,buf,strlen(buf));

n = Read(sockfd,buf,MAXLINE);

if(n == 0) {

printf("the other side has been closed.\n");

} else {

Write(STDOUT_FILENO,buf,n);

}

}

Close(sockfd);

return 0;

}

Wrap.h

#ifndef __WRAP_H_

#define __WRAP_H_

void perr_exit(const char *s);

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);

void Bind(int fd, const struct sockaddr *sa, socklen_t salen);

void Connect(int fd, const struct sockaddr *sa, socklen_t salen);

void Listen(int fd, int backlog);

int Socket(int family, int type, int protocol);

ssize_t Read(int fd, void *ptr, size_t nbytes);

ssize_t Write(int fd, const void *ptr, size_t nbytes);

void Close(int fd);

ssize_t Readn(int fd, void *vptr, size_t n);

ssize_t Writen(int fd, const void *vptr, size_t n);

static ssize_t my_read(int fd, char *ptr);

ssize_t Readline(int fd, void *vptr, size_t maxlen);

#endif

Wrap.c

#include <stdlib.h>

#include <errno.h>

#include <sys/socket.h>

void perr_exit(const char *s)

{

perror(s);

exit(1);

}

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)

{

int n;

again:

if ( (n = accept(fd, sa, salenptr)) < 0) {

if ((errno == ECONNABORTED) || (errno == EINTR))

goto again;

else

perr_exit("accept error");

}

return n;

}

void Bind(int fd, const struct sockaddr *sa, socklen_t salen)

{

if (bind(fd, sa, salen) < 0)

perr_exit("bind error");

}

void Connect(int fd, const struct sockaddr *sa, socklen_t salen)

{

if (connect(fd, sa, salen) < 0)

perr_exit("connect error");

}

void Listen(int fd, int backlog)

{

if (listen(fd, backlog) < 0)

perr_exit("listen error");

}

int Socket(int family, int type, int protocol)

{

int n;

if ( (n = socket(family, type, protocol)) < 0)

perr_exit("socket error");

return n;

}

ssize_t Read(int fd, void *ptr, size_t nbytes)

{

ssize_t n;

again:

if ( (n = read(fd, ptr, nbytes)) == -1) {

if (errno == EINTR)

goto again;

else

return -1;

}

return n;

}

ssize_t Write(int fd, const void *ptr, size_t nbytes)

{

ssize_t n;

again:

if ( (n = write(fd, ptr, nbytes)) == -1) {

if (errno == EINTR)

goto again;

else

return -1;

}

return n;

}

void Close(int fd)

{

if (close(fd) == -1)

perr_exit("close error");

}

ssize_t Readn(int fd, void *vptr, size_t n)

{

size_t  nleft;

ssize_t nread;

char   *ptr;

ptr = vptr;

nleft = n;

while (nleft > 0) {

if ( (nread = read(fd, ptr, nleft)) < 0) {

if (errno == EINTR)

nread = 0;

else

return -1;

} else if (nread == 0)

break;

nleft -= nread;

ptr += nread;

}

return n - nleft;

}

ssize_t Writen(int fd, const void *vptr, size_t n)

{

size_t nleft;

ssize_t nwritten;

const char *ptr;

ptr = vptr;

nleft = n;

while (nleft > 0) {

if ( (nwritten = write(fd, ptr, nleft)) <= 0) {

if (nwritten < 0 && errno == EINTR)

nwritten = 0;

else

return -1;

}

nleft -= nwritten;

ptr += nwritten;

}

return n;

}

static ssize_t my_read(int fd, char *ptr)

{

static int read_cnt;

static char *read_ptr;

static char read_buf[100];

if (read_cnt <= 0) {

again:

if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {

if (errno == EINTR)

goto again;

return -1;

} else if (read_cnt == 0)

return 0;

read_ptr = read_buf;

}

read_cnt--;

*ptr = *read_ptr++;

return 1;

}

ssize_t Readline(int fd, void *vptr, size_t maxlen)

{

ssize_t n, rc;

char    c, *ptr;

ptr = vptr;

for (n = 1; n < maxlen; n++) {

if ( (rc = my_read(fd, &c)) == 1) {

*ptr++ = c;

if (c  == '\n')

break;

} else if (rc == 0) {

*ptr = 0;

return n - 1;

} else

return -1;

}

*ptr  = 0;

return n;

}

1高并发server:多路IO之select的更多相关文章

  1. 3高并发server:多路IO之epoll

     1 epoll epoll是Linux下多路复用IO接口select/poll的增强版本号,它能显著提高程序在大量并.发连接中仅仅有少量活跃的情况下的系统CPU利用率,由于它会复用文件描写叙述符 ...

  2. Linux C++ 网络编程学习系列(2)——多路IO之select实现

    select实现多路IO 源码地址:https://github.com/whuwzp/linuxc/tree/master/select 源码说明: server.cpp: 监听127.1:6666 ...

  3. ServerSocketChannel实现多Selector高并发server

    参考hbase RpcServer,编写了一个简洁版多Selector server,对nio怎么用,Selector如何选择事件会有更深入的认识. client端发送消息:内容长度 + 内容,200 ...

  4. 应用层协议实现系列(一)——HTTPserver之仿nginx多进程和多路IO的实现

    近期在尝试自己写一个Httpserver,在粗略研究了nginx的代码之后,决定仿照nginx中的部分设计自己实现一个高并发的HTTPserver,在这里分享给大家. 眼下使用的较多的Httpserv ...

  5. python开发学习-day09(队列、多路IO阻塞、堡垒机模块、mysql操作模块)

    s12-20160312-day09 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...

  6. 高并发之网络IO模型

    你好,我是坤哥 今天我们聊一下高并发下的网络 IO 模型 高并发即我们所说的 C10K(一个 server 服务 1w 个 client),C10M,写出高并发的程序相信是每个后端程序员的追求,高并发 ...

  7. select poll epoll Linux高并发网络编程模型

    0 发展历程 同步阻塞迭代模型-->多进程并发模型-->多线程并发模型-->select-->poll-->epoll-->... 1 同步阻塞迭代模型 bind( ...

  8. 理论铺垫:阻塞IO、非阻塞IO、IO多路复用/事件驱动IO(单线程高并发原理)、异步IO

    完全来自:http://www.cnblogs.com/alex3714/articles/5876749.html 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同 ...

  9. 多路IO复用模型--select, poll, epoll

    select 1.select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述符个数并不能改变select监听文件个数 2.解决1024以下客户端时使用se ...

随机推荐

  1. python 中sshpass的使用

    如何用SSH连接远程服务器有两种方式 1.利用远程软件控制:sshclient.Puttty.secureCRT等 2.终端命令 ssh -p 22 root@服务器ip  密码需要手工交互式输入(2 ...

  2. 洛谷 P3383 【模板】线性筛素数-线性筛素数(欧拉筛素数)O(n)基础题贴个板子备忘

    P3383 [模板]线性筛素数 题目描述 如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内) 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示查询的范 ...

  3. 洛谷 P2415 集合求和【数学公式/模拟】

    给定一个集合s(集合元素数量<=30),求出此集合所有子集元素之和. 输入输出格式 输入格式: 集合中的元素(元素<=1000) 输出格式: 和 输入输出样例 输入样例#1: 2 3 输出 ...

  4. 遇见requestAnimationFrame

    今天,在读javascript异步编程的js事件深入理解部分的时候,了解到了requestAnimationFrame 这个api,在这里记录一下. 原文: setTimeout 和 setInter ...

  5. RPD Volume 168 Issue 4 March 2016 评论5

    Monte Carlo simulation of secondary radiation exposure from high-energy photon therapy using an anth ...

  6. CentOS 安装 Zookeeper 版本任选

    Zookeeper下载地址各种版本自己选择: https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/ Zookeeper 3.4.13版本下载地址 ...

  7. [BZOJ 2342] 双倍回文

    Link:https://www.lydsy.com/JudgeOnline/problem.php?id=2342 Algorithm: 解决回文串问题,一般从对称轴下手. 肯定先跑一边Manach ...

  8. HDOJ 4961 Boring Sum

    Discription Number theory is interesting, while this problem is boring. Here is the problem. Given a ...

  9. [Android]Android 布局中如何让图片和文字居中显示?

    图片文字居中显示 **①组件TextView的属性 drawableTop ``` <LinearLayout android:layout_width="match_parent&q ...

  10. 一年的天数 Exercise06_16

    /** * @author 冰樱梦 * 时间:2018年下半年 * 题目:一年的天数 * */ public class Exercise06_16 { public static void main ...