测试扩容:原来业务处理读取数据是if,改成while,如果有数据发送读取完毕就会阻塞,一个线程绑定一个客户端,这样就会导致线程一直被占用。
测试完扩容以后,用不用改回来?不改回来导致线程被占用。if读一次也不是一件好事 ,recv读我们规定的大小 ,如果读不完怎么办,网络情况变换莫测,可能我们想读500字节,实际上只读取了300字节,且边缘触发模式,clientfd就绪,就发送一次通知,读不读,读没读完,无法确定。
肯定不能读一次 ,采用边缘触发模式+非阻塞读取网络IO。
边缘触发是因为只希望当某个socket就绪,只希望发一次通知。非阻塞是因为阻塞的读取socket,读取完所有数据以后,recv函数阻塞导致线程被占用,非阻塞循环读取,读完后立即返回,不会阻塞。
如何非阻塞读取?
方法一:将网络IO sockfd通过文件属性fctl函数 ,变为非阻塞sockfd。
方法二:不改变sockfd的属性,改变recv函数的读取方式,将recv函数改成非阻塞读取。
#include<THREAD_POOL.h>
void *BUSINES_RESPONSE(void *arg)
{
int clientfd;
clientfd = *(int*)arg;
char buffer[BUFSIZE];
bzero(buffer,BUFSIZE);
int recvsize ,sendsize;
int flags;
//原来是if((recvsize = RECV(clientfd,buffer,sizeof(buffer),0))>0)
while((recvsize = RECV(clientfd,buffer,sizeof(buffer),0))>0){
flags = 0;
while(recvsize > flags){
buffer[flags] = toupper(buffer[flags]);
flags++;
}
sendsize = SEND(clientfd,buffer,recvsize,0);
printf("CUSTOMER EXEC BUSINES_RESPONSE RECV REQUET [%d] SEND RESPONSE [%d]\n",recvsize,sendsize);
}
if(recvsize == 0){
printf("CUSTOMER EXEC BUSINES_RESPONSE CLIENT EXIST ...\n");
epoll_ctl(epfd,EPOLL_CTL_DEL,clientfd,NULL);
close(clientfd);
}
return NULL;
}
//连接业务
#include<THREAD_POOL.h>
void *BUSINES_ACCEPT(void *arg) //传过去的是sockfd
{
struct epoll_event node; //用于将clientfd添加到监听树上创建的节点
int serverfd;
serverfd = *(int*)arg;
int clientfd;
struct sockaddr_in clientaddr;
socklen_t addrlen;
addrlen = sizeof(clientaddr);
char ip[IPSIZE];
bzero(ip,IPSIZE);
int flags;
if((clientfd = ACCEPT(serverfd,(struct sockaddr *)&clientaddr ,&addrlen))>0){ //连接成功需要将clientfd添加到监听树上
//采用方法一将clientfd改成非阻塞
flags = fcntl(clientfd,F_GETFL,NULL);
fcntl(clientfd,F_SETFL,flags|O_NONBLOCK);
printf("CUSTOMER EXEC BUSINES_ACCEPT CONNECTTION SUCCESS CLIENT[%s][%d] clientfd[%d]\n",
inet_ntop(AF_INET,&clientaddr.sin_addr.s_addr,ip,IPSIZE),ntohs(clientaddr.sin_port),clientfd);
node.data.fd = clientfd;
node.events = EPOLLIN|EPOLLET; //监听读事件
if((epoll_ctl(epfd,EPOLL_CTL_ADD,clientfd,&node))==-1) //epfd定义为全局 //连接成功需要将clientfd添加到监听树上
thread_pool_error("BUSINES_ACCEPT epoll_call failed",-1,FALSE);
}
return NULL;
}