高并发服务器
第一种方案: 使用多进程, 可以让父进程接受新连接, 让子进程处理与客户端通信
思路: 让父进程accept接受新连接, 然后fork子进程, 让子进程处理通信, 子进程处理完成后退出, 父进程使用SIGCHLD信号回收子进程
第二种方案: 使用多线程, 让主线程接受新连接, 让子线程处理与客户端通信; 使用多线程要将线程设置为分离属性, 让线程在退出之后自己回收资源
如何不使用多进程或者多线程完成多个客户端的连接请求
将accept和read函数设置为非阻塞, 调用fcntl函数可以将文件描述符设置为非阻塞, 让后再while循环中忙轮询,但无法判断数据是哪个连接的,假如有多个客户端连接请求,cfd只会保留最后一个文件描述符的值
多进程并发服务器
//多进程版本网络服务器
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<ctype.h>
int main()
{
//创建socket
int lfd=socket(AF_INET,SOCK_STREAM,0);
//绑定
struct sockaddr_in serv;
bzero(&serv,sizeof(serv));
serv.sin_family=AF_INET;
serv.sin_port=htons(8888);
serv.sin_addr.s_addr=htonl(INADDR_ANY);
bind(lfd,(struct sockaddr*)&serv,sizeof(serv));
//设置监听
listen(lfd,128);
int cfd;
while(1)
{
//接受新连接
cfd=accept(lfd,NULL,NULL);
pid_t pid=fork();
if(pid<0)
{
perror("fork error");
exit(-1);
}
else if(pid>0)
{
//关闭通信文件描述符cfd
close(cfd);
}
else if(pid==0)
{
//关闭监听文件描述符
close(lfd);
int n;
char buf[1024];
while(1)
{
//读数据
n=read(cfd,buf,sizeof(buf));
if(n<=0)
{
printf("read error or client close,n==[%d]\n",n);
break;
}
int i=0;
//将小写转为大写
for(i=0;i<n;i++)
{
buf[i]=toupper(buf[i]);
}
//发送数据
write(cfd,buf,n);
}
//关闭cfd
close(cfd);
exit(0);
}
}
//关闭lfd
close(lfd);
return 0;
}
多线程并发服务器
子线程不能关闭监听文件描述符,因为子线程和主线程共享文件描述符而不是复制
主线程不能关闭cfd,主线程和子线程共享一个cfd,而不是复制的
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<ctype.h>
#include<pthread.h>
void* thread_work(void* arg)
{
int cfd=*(int*)arg;
int i;
int n;
char buf[1024];
while(1)
{
//read数据
memset(buf,0x00,sizeof(buf));
n=read(cfd,buf,sizeof(buf));
if(n<=0)
{
printf("read error or client close,n==[%d]\n",n);
break;
}
printf("n==[%d],buf==[%s]\n",n,buf);
for(i=0;i<n;i++)
{
buf[i]=toupper(buf[i]);
}
//发送数据给客户端
write(cfd,buf,n);
}
//关闭通信文件描述符
close(cfd);
pthread_exit(NULL);
}
int main()
{
//创建socket
int lfd=socket(AF_INET,SOCK_STREAM,0);
//绑定
struct sockaddr_in serv;
bzero(&serv,sizeof(serv));
serv.sin_family=AF_INET;
serv.sin_port=htons(8888);
serv.sin_addr.s_addr=htonl(INADDR_ANY);
bind(lfd,(struct sockaddr*)&serv,sizeof(serv));
//设置监听
listen(lfd,128);
int cfd;
pthread_t threadID;
while(1)
{
//接受新连接
cfd=accept(lfd,NULL,NULL);
//创建子线程
pthread_create(&threadID,NULL,thread_work,&cfd);
//设置子线程为分离属性
pthread_detach(threadID);
}
//关闭监听文件描述符
close(lfd);
return 0;
}