Linux各种并发服务器优缺点
本文旨在介绍针对“无并发C/S模型”改进的方法总结以及各种改进方法的优缺点,具体函数的实现并不介绍。
1. 无并发C/S模型
创建服务器流程分析:
- socket()创建服务器的监听套接字
- bind()将服务器给服务器的监听套接字绑定IP地址和Port端口号
- listen()设置服务器端能够连接客户端的最大连接数。默认128
- accept()阻塞等待客户端连接,连接成功之后,系统默认创建新的用于与客户端进行数据交换的套接字,accept()返回该数据通信套接字的文件描述符
- 与客户端进行数据交换
- 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;
}
创建客户端流程分析:
- socket()创建套接字
- 【bind()给套接字分配IP地址】此步骤可有可无,不调用bind的话系统自动分配
- connect()与请求连接服务器
- 与服务器进行数据通信
- 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);
}
数据通信:
- 运行./server
- 运行./client, 成功完成数据通信
- 再次运行client,此时无法通信
无并发C/S模型模型缺点:
运行server后,accpet只调用了一次,因此当一个client发出连接请求,accpet便不再监听,而是与客户端建立连接,开始通信,无法做到一个server程序同时与多个client通信。
2. 多进程C/S模型
3. 多线程C/S模型
4. select模型
5. select多线程模型
6. poll模型
poll的参数:
fds:监听的文件描述符【数组】,该数组的每个成员是struct pollfd
nfds: 监听数组的实际有效监听个数
7. epoll模型