Linux关于并发网络分为Apache模型(Process per Connection (进程连接) ) 和TPC , 还有select模型,以及poll模型(一般是Epoll模型)

Select模型极其作用:这文章讲述的很好,没必要重述已有的东西,就直接给链接

http://blog.csdn.net/turkeyzhou/article/details/8609360

我的理解:

 /* According to POSIX.1-2001 */
#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); void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

对于

   int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
第一个参数 nfds: 第n个文件id的编号 (linux下,一切皆文件) 需要注意的是: nfds = fd+1 (fd 为 FD_SET中的fd)
第二个参数: fd_set *readfds 读取文件编号,如果不需要读取的话 可以设置为NULL
第三 ,四个参数: 同上
第五个参数:为一个定义超时的结构体
        struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};

该结构用来设定多少时间为超时 ,比如

struct timeval ss ;
ss.tv_sec =;
ss.tv_usec =;
//表示设定为3秒后为超时,select将会返回0
对于下面这几个函数:

void FD_CLR(int fd, fd_set *set);

用来清除fd的fd_set  ,比如fd为5  ,则表示set集中所有设定等于5的fd_set 都将被清除

int FD_ISSET(int fd, fd_set *set);

判断是否set 与fd是否绑定,如果没有绑定,则返回false,如果绑定了则返回True

void FD_SET(int fd, fd_set *set);

将fd值 和set绑定

void FD_ZERO(fd_set *set);

将set集全部清除

简单的例子:

判断是否有数据输入,有则直接打印出来

 #include<stdio.h>
#include<string.h>
#include<sys/select.h>
#include<unistd.h>
#include<sys/time.h>
#include<sys/types.h>
#define maxn 6
#define EXIT_FAILURE -1
#define EXIT_SUCCESS 0 int main(int argc , char * argv []){ fd_set mtfd ;
int ffd =;
struct timeval outtime ;
int retval ;
char redbuf[maxn]; FD_ZERO(&mtfd);
FD_SET(ffd , &mtfd); // wait up to 5.5 s
outtime.tv_sec = ;
outtime.tv_usec = ;
retval = select(ffd+ , &mtfd ,NULL , NULL , &outtime);
if(- == retval )
{
printf("error happened ! %d \n" ,__LINE__ );
return EXIT_FAILURE ;
}
else if( == retval ){
printf(" timeout !! %d \n" ,__LINE__ );
return EXIT_FAILURE ;
}
//means that is good ! printf("retval = %d \n", retval); if( FD_ISSET(ffd , &mtfd) ){ memset(redbuf , , sizeof(redbuf));
printf("reading ... !! ");
// read(1 , redbuf ,sizeof(redbuf) ); //use the sys func
fread(redbuf , sizeof(redbuf) ,ffd+ , stdin );
}
// fwrite(redbuf ,strlen(redbuf) , 1 , stdout );
// write(1 , redbuf , strlen(redbuf));
printf("buf = %s buf_len = %d \n" , redbuf , strlen(redbuf)); return EXIT_SUCCESS ;
}

makefile文件:

 .SUFFIXES: .o.c
CC =gcc
SRC = Se_keyboard.c
OBJ = $(SRC: .c =.o)
BIN = Se_keyboard .PHONY: start
start: $(OBJ)
$(CC) -o $(BIN) $(OBJ)
.o.c: $(SRC)
$(CC) -g -Wall $@ -c $<
.PHONY: clean
clean:
rm -f $(OBJ)

虽然知道这么多,但是还是觉得Select并没有什么作用。

Select一般是和Socket搭配使用,相当于线程池的效果,但是线程池有缺点,详情看这儿:

http://blog.csdn.net/tianmohust/article/details/6677985

http://blog.csdn.net/xifeijian/article/details/17385831

关于Select的原理图:

首先来看下一对一的socket的c/s模式

关于socket的一对一的详解

http://www.cnblogs.com/gongxijun/p/4592864.html

看完这个之后,我们现在可以来看看这个图:

下面为举例:

服务器创建一个socket并bind绑定一个本机地址和设定一个端口,然后进入listen监听状态。采用select模型而非传统apache模型(ppc)或者tpc模型 。 不过Select模型就是有这样一个特点

一般我们default默认的SOMAXCONN为128 当然我们可以另外取一个设定(下面我们设定的是2048)作为最大连接数,虽然可以设置更大,但是缺点是,select模型是一个轮询模式,就是每一个都需要遍历一边所有的链接的fd

查看是否在fd_set集合中,这样,当SOMAXCONN取值非常大时,对于每一个客户端,访问时间都会延迟一点点,这样就是效率不是特别高!

下面是一个简单的多路复用的网络并发Select模型

 #include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/time.h>
#include<arpa/inet.h>
#include<sys/select.h>
#include<assert.h> #ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif #ifndef EXIT_FAILURE
#define EXIT_FAILURE -1
#endif #define Max_connect 2048 //usually is SOMAXCONN =128 ,can be change #define maxn 1024
#define Port 5567
#define Ser_addr "192.168.132.128" #define ERROR_EXIT( inf ) \
do{ \
perror( inf ); \
printf("it happened in %d \n", __LINE__); \
exit(-); \
}while(); #define Waring( inf ) \
do{ \
perror( inf ); \
printf("it happened in %d \n", __LINE__); \
}while(); int fds[Max_connect];
int cnt = ; void
print (int fd, const char *str)
{
assert (str != NULL);
printf ("the fd is %d \n", fd);
puts (str);
} int
main (int argv, char *argc[])
{ int ser_sfd = -, i;
struct sockaddr_in ser_addr;
struct sockaddr_in client_addr;
int setfd = , optval, maxsockfd; char rebuf[maxn], wbuf[maxn]; // build a socket with ipv4 ans tcp if ((ser_sfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < )
ERROR_EXIT ("socket...!"); // set the type socket
/*
level ={ SOL_SOCKET ,IPPROTO_TCP}
setsockopt is to cancle the jiangsi process
*/ printf ("ser_sfd = %d \n", ser_sfd);
if (setsockopt (ser_sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval))
< )
ERROR_EXIT ("setsockopt...!"); memset (&client_addr, , sizeof (client_addr));
memset (&ser_addr, , sizeof (ser_addr));
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons (Port);
ser_addr.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (ser_sfd, (struct sockaddr *) &ser_addr, sizeof (ser_addr)) < )
ERROR_EXIT ("bind..!"); if (listen (ser_sfd, Max_connect) < )
ERROR_EXIT ("listen...!"); //user the select moduel
memset (fds, , sizeof (fds));
fd_set fdset, wfd;
maxsockfd = ser_sfd; //max socket fd struct timeval tout; tout.tv_sec = ;
tout.tv_usec = ; while ()
{ FD_ZERO (&fdset); //clear
//FD_ZERO (&wfd); FD_SET (ser_sfd, &fdset); //bind
//FD_SET (ser_sfd, &wfd); struct timeval tout; tout.tv_sec = ;
tout.tv_usec = ; for (i = ; i < cnt; i++)
{
if (fds[i] != )
FD_SET (fds[i], &fdset);
} int tag = select (maxsockfd + , &fdset, NULL, NULL, &tout); if (tag == )
{
Waring ("select wait timeout !");
continue;
}
else if (tag == -)
ERROR_EXIT ("Error select ...!"); //lunxun select
for (i = ; i < cnt; i++)
{ if (FD_ISSET (fds[i], &fdset))
{ int len = recv (fds[i], rebuf, sizeof (rebuf), );
if (len <= )
{ printf ("%d: \n", fds[i]);
close (fds[i]);
FD_CLR (fds[i], &fdset);
Waring ("client is closed !");
continue;
} printf ("the client_ip : %s\n",
inet_ntoa (client_addr.sin_addr)); print (fds[i], rebuf); send (fds[i], rebuf, sizeof (rebuf), ); //hui she
memset (rebuf, , sizeof (rebuf));
}
}
//if have a new connect happened
// memset(&client_addr , 0 ,sizeof(client_addr));
if (FD_ISSET (ser_sfd, &fdset))
{
// memset(&client_addr , 0 ,sizeof(client_addr));
int acplen = sizeof (client_addr);
int acp = accept (ser_sfd, (struct sockaddr *) &client_addr,
&acplen); printf ("accept return acp=%d \n", acp); if (acp < )
{ Waring ("waring accept acp<=0!");
continue;
}
//add to arr
if (cnt < maxn)
fds[cnt++] = acp;
else
{
ERROR_EXIT ("cnt>maxn");
}
if (acp > maxsockfd)
maxsockfd = acp;
}
} for (i = ; i < cnt; i++)
{
close (fds[i]);
} return EXIT_SUCCESS;
}

makefile文件:

 .SUFFIXES: .o.c
CC =gcc
SRC = server.c
OBJ = $(SRC: .c =.o)
BIN = Sez_Server .PHONY: start
start: $(OBJ)
$(CC) -o $(BIN) $(OBJ)
.o.c: $(SRC)
$(CC) -g -Wall $@ -c $<
.PHONY: clean
clean:
rm -f $(OBJ)

客户端:

 #include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<assert.h>
#include<unistd.h>
#ifndef EXIT_FAILURE
#define EXIT_FAILURE - //exit failure
#endif
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS // exit sucessful
#endif #define Port
#define IPADDR "192.168.132.128"
#define maxn #define ERROR_EXIT( inf ) \
do{ \
perror( inf ); \
printf("it's happened in %d \n",__LINE__); \
}while() ; //use the function to connect the server !! int
main (int argv, char *argc[])
{ int sfd = -;
char rbuf[maxn], wbuf[maxn];
// int sfd=- ; //socket_fd
int confd = -; //connect_fd
struct sockaddr_in soaddr;
if ((sfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < )
{
ERROR_EXIT ("socket");
return EXIT_FAILURE;
} //memset a struct
memset (&soaddr, , sizeof (soaddr)); //int the struct sockaddr_in soaddr.sin_family = AF_INET;
soaddr.sin_port = htons (Port);
soaddr.sin_addr.s_addr = inet_addr (IPADDR); if ((confd =
connect (sfd, (struct sockadrr *) &soaddr, sizeof (soaddr))) < )
{
ERROR_EXIT ("connect");
return EXIT_FAILURE;
} printf ("connect is sucessful !\n"); while (fgets (wbuf, sizeof (rbuf), stdin) != NULL)
{
write (sfd, wbuf, strlen (wbuf));
read (sfd, rbuf, sizeof (rbuf));
fputs (rbuf, stdout);
} close (sfd);
close (confd);
return EXIT_SUCCESS;
}

makefile文件:

  1.  .SUFFIXES: .o.c
    CC =gcc
    SRC = client.c
    OBJ = $(SRC: .c =.o)
    BIN = Se_client .PHONY: start
    start: $(OBJ)
    $(CC) -o $(BIN) $(OBJ)
    .o.c: $(SRC)
    $(CC) -g -Wall $@ -c $<
    .PHONY: clean
    clean:
    rm -f $(OBJ)

    效果图:

linux下多路复用模型之Select模型的更多相关文章

  1. Linux 下的五种 IO 模型

    概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的 ...

  2. Linux 下 简单客户端服务器通讯模型(TCP)

    原文:Linux 下 简单客户端服务器通讯模型(TCP) 服务器端:server.c #include<stdio.h> #include<stdlib.h> #include ...

  3. Socket I/O模型之select模型

    socket网络编程中有多种常见的I/O模型: 1.blocking阻塞 2.nonblocking非阻塞 3.I/O multiplexing复用 4.signal driven 5.asynchr ...

  4. 关于 Poco::TCPServer框架 (windows 下使用的是 select模型) 学习笔记.

    说明 为何要写这篇文章 ,之前看过阿二的梦想船的<Poco::TCPServer框架解析> http://www.cppblog.com/richbirdandy/archive/2010 ...

  5. [转载] Linux下多路复用IO接口 epoll select poll 的区别

    原地址:http://bbs.linuxpk.com/thread-43628-1-1.html 废话不多说,一下是本人学习nginx 的时候总结的一些资料,比较乱,但看完后细细揣摩一下应该就弄明白区 ...

  6. Linux下多进程服务端客户端模型一(单进程与多进程模型)

    本文将会简单介绍Linux下如何利用C库函数与系统调用编写一个完整的.初级可用的C-S模型. 一.基本模型: 1.1   首先服务器调用socket()函数建立一个套接字,然后bind()端口,开始l ...

  7. Winsock IO模型之select模型

    之所以称其为select模型是因为它主要是使用select函数来管理I/O的.这个模型的设计源于UNIX系统,目的是允许那些想要避免在套接字调用上阻塞的应用程序有能力管理多个套接字. int sele ...

  8. Linux下多路复用IO接口epoll/select/poll的区别

    select比epoll效率差的原因:select是轮询,epoll是触发式的,所以效率高. Select: 1.Socket数量限制:该模式可操作的Socket数由FD_SETSIZE决定,内核默认 ...

  9. Linux下多进程服务端客户端模型二(粘包问题与一种解决方法)

    一.Linux发送网络消息的过程 (1) 应用程序调用write()将消息发送到内核中 ( 2)内核中的缓存达到了固定长度数据后,一般是SO_SNDBUF,将发送到TCP协议层 (3)IP层从TCP层 ...

随机推荐

  1. spring MVC配置详解

    现在主流的Web MVC框架除了Struts这个主力 外,其次就是Spring MVC了,因此这也是作为一名程序员需要掌握的主流框架,框架选择多了,应对多变的需求和业务时,可实行的方案自然就多了.不过 ...

  2. Netty之有效规避内存泄漏

    有过痛苦的经历,特别能写出深刻的文章 —— 凯尔文. 肖 直接内存是IO框架的绝配,但直接内存的分配销毁不易,所以使用内存池能大幅提高性能,也告别了频繁的GC.但,要重新培养被Java的自动垃圾回收惯 ...

  3. Java接口回调

    public class A { private D d; private C c; public A (C c) { this.c = c; } public void setD (D d) { t ...

  4. 【01:转自知乎:关于 openSUSE 】

    我是 openSUSE 中文维基唯一的非官方维护者,openSUSE 简体中文翻译团队召集人,linuxsir SuSE 版块的版主,openSUSE 官方论坛 http://forums.opens ...

  5. textarea 多行文本保存数据到DB,取出后恢复换行

    Steps: 1.保存到数据库之前把textarea中的换行字符转换为<br>. var dbStr = textareaStr.replace(/\n|\r\n/g,"< ...

  6. Dynamics AX 2012 R2 创建一个带有负载均衡的服务器集群

    安装额外AOS的主要目的,是将它添加到集群,或用于创建批处理服务器. 1.创建集群服务器 这里,Reinhard使用上节Install An Additional AOS 中创建的AOS,来创建集群. ...

  7. mina IoBuffer 常用方法

    Limit(int) 如果position>limit, position = limit,如果mark>limit, 重置mark Mark() 取当前的position的快照标记mar ...

  8. 用CSS3实现文字描边

    CSS3作为新兴的前端技术可以实现很多复杂变化的效果,比如文字描边. 这里主要用到text-shadow属性,顾名思义就是为文字加上阴影效果.例: text-shadow:10px 5px 2px # ...

  9. MapReduce的模式、算法和用例

    英文原文:<MapReduce Patterns, Algorithms, and Use Cases> https://highlyscalable.wordpress.com/2012 ...

  10. extjs 一些杂碎的技术问题

    1怎样将grid 的checkedbox 勾选状态都清除 inv.getSelectionModel().clearSelections(); inv.getView().refresh(); 2怎样 ...