并发服务器:服务起在同一时刻可以响应多个客户端的请求
一.多进程
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/wait.h>
int tcp_init(const char *ip,int port)
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
perror("socket fail");
return -1;
}
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(port);
ser.sin_addr.s_addr = inet_addr(ip);
int ret_bind = bind(sockfd,(struct sockaddr *)&ser,sizeof(ser));
if(ret_bind == -1)
{
perror("bind fail");
return -1;
}
int ret_listen = listen(sockfd,10);
if(ret_listen == -1)
{
perror("listen fail");
return -1;
}
return sockfd;
}
void handle (int sig)
{
wait(NULL);
}
int main(void)
{
signal(SIGCHLD,handle);
int sockfd = tcp_init("192.168.1.24",50000);
if(sockfd == -1)
{
return -1;
}
while(1)
{
int accfd = accept(sockfd,NULL,NULL);
if(accfd == -1)
{
perror("accept fail");
return -1;
}
pid_t pid = fork();
if(pid > 0)
{
}
else if(pid == 0)
{
char buff[1024] = {0};
while(1)
{
memset(buff,0,sizeof(buff));
ssize_t size = recv(accfd,buff,sizeof(buff),0);
if(size <= 0)
{
break;
}
printf("buff=%s\n",buff);
size = send(accfd,"HELLO",5,0);
if(size < 0)
{
break;
}
}
}
close(accfd);
}
close(sockfd);
return 0;
}
二.多线程
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
#include<pthread.h>
int tcp_init(const char *ip,int port)
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
perror("socket fail");
return -1;
}
struct sockaddr_in ser;
ser.sin_family = AF_INET;
ser.sin_port = htons(port);
ser.sin_addr.s_addr = inet_addr(ip);
int ret_bind = bind(sockfd,(struct sockaddr *)&ser,sizeof(ser));
if(ret_bind == -1)
{
perror("bind fail");
return -1;
}
int ret_listen = listen(sockfd,10);
if(ret_listen == -1)
{
perror("listen fail");
return -1;
}
return sockfd;
}
void *thread(void *arg)
{
int accfd = *(int *)arg;
char buff[1024] = {0};
while(1)
{
memset(buff,0,sizeof(buff));
ssize_t size = recv(accfd,buff,sizeof(buff),0);
if(size <= 0)
{
break;
}
printf("buff=%s\n",buff);
size = send(accfd,"HELLO",5,0);
if(size < 0)
{
break;
}
}
close(accfd);
}
int main(void)
{
int sockfd = tcp_init("192.168.1.24",50000);
if(sockfd == -1)
{
return -1;
}
pthread_t tid;
while(1)
{
int accfd = accept(sockfd,NULL,NULL);
if(accfd == -1)
{
perror("accept fail");
return -1;
}
pthread_create(&tid,NULL,thread,&accfd);
pthread_detach(tid);
}
close(sockfd);
return 0;
}
三.IO多路复用
1.select
缺点:
1.select监听文件描述符最大个数为1024 (数组)
2.select监听的文件描述符集合在用户层,需要应用层和内核层互相传递数据
3.select需要循环遍历一次才能找到产生的事件
4.select只能工作在水平触发模式(低速模式)无法工作在边沿触发模式(高速模式)
2.poll
缺点:
1.poll监测文件描述符不受上限限制 (链表)
2.poll监听的文件描述符集合在用户层,需要内核层向用户层传递数据
3.poll需要循环遍历一次才能找到产生的事件
4.poll只能工作在水平触发模式(低速模式)无法工作在边沿触发模式(高速模式)
3.epoll
优点:
1.epoll创建内核事件表,不受到文件描述符上限限制 (红黑树)
2.epoll监听的事件表在内核中,直接在内核中监测事件效率高
3.epoll会直接获得产生事件的文件描述符的信息,而不需要遍历检测
4.epoll既能工作在水平触发模式,也能工作在边沿触发模式