网站流量怎么做的,手机网站跳出率低,wordpress谷歌字体优化,设计君服务器模型
tcp服务器: socket bind listen accept recv/send close
1.支持多客户端访问
//单循环服务器 socket bind listen while(1) { accept while(1) { recv/send } } close
2.支持多客户端同时访问 (并发能力) 并发服务器 socket bind … 服务器模型
tcp服务器: socket bind listen accept recv/send close
1.支持多客户端访问
//单循环服务器 socket bind listen while(1) { accept while(1) { recv/send } } close
2.支持多客户端同时访问 (并发能力) 并发服务器 socket bind listen while(1) { connf accept pid_t pid fork(); if(pid 0) { continue; }else if (pid 0) { while(1) //负责 与 客户端通信的 { recv/send } } } close
2.1进程 socket bind listen while(1) { connf accept pid_t pid fork(); //出错处理 if (pid 0) { while(1) //负责 与 客户端通信的 { recv/send } } } close
2.2线程
void *handle_client(void *arg) { while(1) //子线程中 负责 与 客户端通信的 { recv/send } } socket bind listen while(1) { connf accept pthread_create(); //出错处理 } close ------------------------------------------------------------------------- 三种服务器模型比较
1.单循环服务器 2.并发服务器 进程 线程 1、简单循环服务器 http web 服务器apache--》cgiphpperlIIS--》aspNGIXNlighty while(1) { newfd accept(); recv(); close(newfd); } 特点可以接入多个客户端的信息。 缺点数据通信过程短客户端只能一次有效。 实时性效果差。 2、fork循环服务器每次有链接则fork一个子进程为该 链接处理通信过程父进程继续等待新链接。 while(1) { newfd accept(); pid fork() if(pid 0) { ///接收数据 } if(pid 0) { perror(fork); return -1; } waitpid() } 特点可以完成多个进程的实时交互信息的完整性可以保证。 缺点回收资源不方便每次fork 占用系统资源多。 可能出现僵尸进程 多线程: 特点: 创建速度快调度快 缺点: 线程共享进程资源稳定性安全性 较差 3.并发的服务器模型 ---更高程度上的并发 IO模型 阻塞IO 非阻塞IO 1、阻塞IO 用的最多。 读阻塞。 写阻塞。 2、非阻塞IO -1 errno EAGAIN whild(1){read()break;}忙等待 control cntl 3、IO多路复用 4、信号驱动IO SIGIO ---异步 5, 并行模型 进程线程 #include unistd.h #include fcntl.h int fcntl(int fd, int cmd, ... /* arg */ ); 功能修改指定文件的属性信息。 参数fd 要调整的文件描述符 cmd 要调整的文件属性宏名称 ... 可变长的属性值参数。 返回值成功 不一定看cmd 失败 -1 int fcntl(int fd, int cmd, ... /* arg */ ); //驱动: //1.驱动程序 ---- 驱使硬件工作起来的程序 让灯亮起来 eg修改文件的非阻塞属性 int flag ; flag fcntl(fd,F_GETFL,0); ///获取fd文件的默认属性到flag变量中。 flag flag | O_NONBLOCK; ///将变量的值调整并添加非阻塞属性 fcntl(fd,F_SETFL,flag); ///将新属性flag设置到fd对应的文件生效。 以上代码执行后的阻塞IO将变成非阻塞方式。 信号驱动IO //signal 1.fcntl --- 设置 信号接受者 flags fcntl(fd,F_GETFL); //获得当前标志 fcntl(fd,F_SETFL,flags|O_ASYNC); //异步通信的标志 //同步 通信 //异步 通信 2.将该程序 和 SIGIO信号关联起来 fcntl(fd,F_SETOWN,pid); 3.设置信号处理函数 signal owner //所有者 缺点: 处理的数量有限 (超过了1个不好判断了) /---client1 / server ---------------|-----client2 \ \---client3 | ---A /---client1(子进程/线程)-- | ---B / | ---C server ---------------|-----client2(子进程/线程)-- | ---D \ | ---E \---client3(子进程/线程)-- | ---F | ---G stdin //读 stdout //写 stderr //--写出错信息 IO多路服用 多路 --- 多个输入输出 复用 --- 复用同一个进程或线程 select //linux提供实现Io多路复用函数 #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); 功能: io多路复用函数 参数 nfds //三个集合中最大的文件描述符 1 readfds //关心的 读操作的 文件描述符的集合 writefds //关心的 写操作的 文件描述符的集合 exceptfds //关心的 异常操作的 文件描述符的集合 timeout // NULL --- select 阻塞操作 timeout --- 设定超时时间 0 等 这么长时间 0 不阻塞 struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microseconds */ }; 返回值: 成功 表示 就绪的文件描述符的数量 失败 -1 errno设置 void FD_CLR(int fd, fd_set *set); //clear --- 将fd从 set中清除 int FD_ISSET(int fd, fd_set *set); //判断 set 表中 fd是否就绪 void FD_SET(int fd, fd_set *set); //将fd设置(添加)到set中 void FD_ZERO(fd_set *set); //表示将set表清零 注意: 1. select 函数在监控到 有fd就绪后 它会把未就绪的fd清除掉每次需要重新获取 2. 超时一次后时间的变量值为为0 如果需要每次都有超时时间需要每次重新给值 //单循环服务器 //第1路IO fgets --收键盘 --- 打印出来 --- stdin 能不能读? //第2路IO 读管道数据 -- 修改 --- 发回去 --- 管道 能不能读?
select 1.建一张表 放 要监控 的文件描述符 readfds(); 2.添加 要监控的文件描述符 到表中 FD_SET() 3.select eg: 1. 管道双向通信: A.c B.c ---------A2B----------------- --------B2A----------------- A.c代码如下
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include errno.h
#include fcntl.h
#include unistd.h
#include string.h
#include sys/wait.h
#include stdlib.h
//./a.out fifo_A2B fifo_B2A
int main(int argc, const char *argv[])
{if (argc ! 3){printf(Usage: %s fifo_A2B fifo_B2A\n,argv[0]);return -1;}if(mkfifo(argv[1],0666) 0 errno ! EEXIST){perror(mkfifo fail);return -1;}if(mkfifo(argv[2],0666) 0 errno ! EEXIST){perror(mkfifo fail);return -1;}int fd1 open(argv[1],O_WRONLY);int fd2 open(argv[2],O_RDONLY);if (fd1 0 || fd2 0){perror(open fail);return -1;}//1.准备表 fd_set readfds;FD_ZERO(readfds);//2.添加要监控的 fd2FD_SET(0,readfds);FD_SET(fd2,readfds);int nfds fd2 1;int i 0;char buf[1024];while (1){fd_set backfds readfds;int ret select(nfds,backfds,NULL,NULL,NULL);if (ret 0){perror(select fail);return -1;}if (ret 0){for (i 0; i nfds; i){if (FD_ISSET(i,backfds)){if (i 0){printf( );fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] \0;write(fd1,buf,strlen(buf)1);if (strncmp(buf,quit,4) 0){printf(1 exit......\n);exit(0);}}else if (i fd2){printf(c );read(fd2,buf,sizeof(buf));printf(%s \n,buf);if (strncmp(buf,quit,4) 0){printf(2 exit......\n);exit(0);}}}}}}return 0;
}B.c代码如下
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include errno.h
#include fcntl.h
#include unistd.h
#include string.h
#include sys/wait.h
#include stdlib.h//./a.out fifo_A2B fifo_B2A
int main(int argc, const char *argv[])
{if (argc ! 3){printf(Usage: %s fifo_A2B fifo_B2A\n,argv[0]);return -1;}if(mkfifo(argv[1],0666) 0 errno ! EEXIST){perror(mkfifo fail);return -1;}if(mkfifo(argv[2],0666) 0 errno ! EEXIST){perror(mkfifo fail);return -1;}int fd1 open(argv[1],O_RDONLY);int fd2 open(argv[2],O_WRONLY);if (fd1 0 || fd2 0){perror(open fail);return -1;}//1.准备表 fd_set readfds;FD_ZERO(readfds);//2.添加要监控的 fd2FD_SET(0,readfds);FD_SET(fd1,readfds);int nfds fd1 1;int i 0;char buf[1024];while (1){fd_set backfds readfds;int ret select(nfds,backfds,NULL,NULL,NULL);if (ret 0){perror(select fail);return -1;}if (ret 0){for (i 0; i nfds; i){if (FD_ISSET(i,backfds)){if (i 0){printf( );fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] \0;write(fd2,buf,strlen(buf)1);if (strncmp(buf,quit,4) 0){printf(1 exit......\n);exit(0);}}else if (i fd1){printf(c );read(fd1,buf,sizeof(buf));printf(%s \n,buf);if (strncmp(buf,quit,4) 0){printf(2 exit......\n);exit(0);}}}}}}return 0;
}