Bootstrap

Linux各种并发服务器优缺点

本文旨在介绍针对“无并发C/S模型”改进的方法总结以及各种改进方法的优缺点,具体函数的实现并不介绍。

优点缺点
多进程C/S模型服务器同时处理多个客户端请求系统开销大
多线程C/S模型服务器同时处理多个客户端请求系统开销大
select模型(1)单进程实现服务器同时处理多个客户端请求
(2)select跨平台
(1)内核对于select传递进来的待检测集和的检测方式是线性的
(2)对多个客户端的处理是单个进场轮询处理的,并不是真正意义上的并发
 
select多线程模型对多个客户端的处理采用多线程处理,相当于并发处理增加了系统开销
poll模型
epoll模型

1. 无并发C/S模型

创建服务器流程分析:

  1. socket()创建服务器的监听套接字
  2. bind()将服务器给服务器的监听套接字绑定IP地址和Port端口号
  3. listen()设置服务器端能够连接客户端的最大连接数。默认128
  4. accept()阻塞等待客户端连接,连接成功之后,系统默认创建新的用于与客户端进行数据交换的套接字,accept()返回该数据通信套接字的文件描述符
  5. 与客户端进行数据交换
  6. close()关闭服务器端的俩个套接字
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <ctype.h>
#include <arpa/inet.h>
#define SERV_PORT 9527

void sys_err(const char *str){
    perror(str);
    exit(1);
}

int main(int argc, char *argv[]){
    int lfd = 0 ,cfd = 0;
    int ret,i;
    int buf[BUFSIZ]; //BUFSIZ==4096

    struct sockaddr_in serv_addr;//初始化地址结构体,并给其分配IP和端口号
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址自动获取

    struct sockaddr_in clit_addr; //accept()的传出参数
    socklen_t clit_addr_len; //accept()的传入传出参数

    lfd = socket(AF_INET,SOCK_STREAM,0);//1.服务器端创建套接字
    if (lfd == -1)
        sys_err("socket error");

    bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); //2.bind给服务器套接字分配地址

    listen(lfd,128); //3. 设置服务器端最大连接客户端请求上限

    clit_addr_len = sizeof(clit_addr);
    //accept()调用成功的话, clit_addr会保存客户端的地址结构, clit_addr_len保存长度
    cfd = accept(lfd,(struct sockaddr *)&clit_addr, &clit_addr_len);
    if (cfd == -1)
        sys_err("accept error");

    //服务器与客户端建立连接成功----数据通信
    while(1){
        ret = read(cfd,buf,sizeof(buf));
        write(STDOUT_FILENO,buf,ret);

        for (i = 0; i < ret; i++)
            buf[i] = toupper(buf[i]);
        write(cfd,buf,ret);
    }
    close(lfd);
    close(cfd);

    return 0;
}

创建客户端流程分析:

  1. socket()创建套接字
  2. 【bind()给套接字分配IP地址】此步骤可有可无,不调用bind的话系统自动分配
  3. connect()与请求连接服务器
  4. 与服务器进行数据通信
  5. close()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SERV_PORT 9527
void sys_err(const char *str){
    perror(str);
    exit(1);
}

int main(int argc, char *argv[]){
    int cfd;
    struct sockaddr_in serv_addr; // 服务器的地址结构
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port =htons(SERV_PORT);//存储网络字节序格式的端口号   
    inet_pton(AF_INET,"127.0.0.1",&serv_addr.sin_addr.s_addr);//存储网络字节序的IP地址

    cfd = socket(AF_INET,SOCK_STREAM,0);//1.创建socket套接字
    if (cfd == -1)
        sys_err("socket error");


    int ret = connect(cfd,(struct sockaddr *)&serv_addr, sizeof(serv_addr));//2.与服务器套接字建立连接
    if (ret != 0)
        sys_err("connect err");


    int counter = 10;
    char buf[BUFSIZ];
    while(--counter){//通信
        write(cfd,"hello",5);//写“hello”到缓冲区
        ret = read(cfd,buf,sizeof(buf));//读缓冲区内容到buf中,注意,read是阻塞读取的
        write(STDOUT_FILENO,buf,ret);

    }
    close(cfd);
}

数据通信:

  1. 运行./server
  2. 运行./client, 成功完成数据通信
  3. 再次运行client,此时无法通信

无并发C/S模型模型缺点:

运行server后,accpet只调用了一次,因此当一个client发出连接请求,accpet便不再监听,而是与客户端建立连接,开始通信,无法做到一个server程序同时与多个client通信

2. 多进程C/S模型

3. 多线程C/S模型

4. select模型

5. select多线程模型

6. poll模型

7. epoll模型

;