1.1 需求规定
写一个tcp服务端,实现高并发、高吞吐量、高稳定性,并且扩展方便,后面很容易添加具体业务操作
1.2 运行环境
1.2.1 硬件环境
后台主机为刀片服务器。
1.2.2 软件环境
操作系统是centos6.x
开发语言是ANSI C
设置系统参数,使最大文件数达到1048576
1.3 基本流程
2. 方案分析和选择
由于多进程的效率比不上多线程的效率,这里只考虑到单线程或线程,并且用epoll ET模式。为了方面过程的描述,用到伪代码,具体如下:
createSocket():新建侦听FD
createEpollFd():创建 epoll fd
setListenEventIn():将listen fd 添加到事件中
epollWait():等待事件发生
dealAccept():处理accept事件
createPthread():创建线程
recv():接收数据
deal():业务处理
send():返回数据
func{do}:函数名称和里面的处理过程
2.1 单线程
单线程的设计比较简单,大致过程如下:
createSocket();
setListenEventIn();
createEpollFd();
while(1)
{
epollWait();
dealAccept
{
accept
{
recv();
deal();
send();
}
}
}
单线程的优点显而易见,流程处理简单,并且效率很高,可以达到30,000TPS。缺点就是,如果某个事件在deal()时消耗的时间比较多,就导致其他事件未及时处理引起的超时。
2.2 多线程
多线程是在单线程的基础上开发的,目的是通过并发来提高吞吐量,并且避免某个事件处理时间过长而导致其他事件未及时处理引起的超时。尝试过多种方法,然而可用的方法只有一种。
2.2.1 方案1:共用1个epoll fd,单线程accept,多线程数据接收和处理(方案可用)
方案的大致流程是:
createSocket();
setListenEventIn();
createEpollFd();
while(1)
{
epollWait();
dealAccept
{
accept();
createPthread
{
recv();
deal();
send();
}
}
}
这个方案,是在accept后面才开线程处理剩下的流程,也是网络上主流的方案,只是实现细节可能有所差异。
在测试了1000万个客户端的请求后,程序依然稳定,性能也算好,达到14,000TPS。
2.2.2 方案2:共用1个epoll fd,多线程处理epollWait后的事件(方案不可用)
方案的大致流程是:
createSocket();
setListenEventIn();
createEpollFd();
while (1)
{
epollWait();
createPthread
{
dealAccept
{
accept();
recv();
deal();
send();
}
}
}
方案1的是accept后才开多线程处理的,感觉可以在更前的步骤开多线程,说不定效率会更高一点,这个方案是在epollWait后开多线程处理事件,每收到一个事件集,开一个线程来处理,这样就可以多个线程处理事件集。
这个方案,理论上比方案1更高性能。然而,在测试过程中,程序不是很稳定,经常出现客户端请求没处理的情况,其实,这是因为惊群现象引起的,下面会有分析。
2.2.3 方案3:共用1个epoll fd,多线程 epoll wait 和 accept(方案不可用)
方案大致流程是:
createSocket();
setListenEventIn();
createEpollFd();
createPthread
{
while(1)
{
epollWait();
dealAccept
{
accept();
recv();
deal();
send();
}
}
}
方案2失败了,这个方案是比方案2在更前的步骤开多线程,开了多个epollWait线程来处理事件集,由于epoll相关函数都是线程安全的,一个epollWait线程从内核获取事件集然后处理,另一个epollWait线程可以跟着获取未处理的事件集。
但是,这个方案也不稳定,有时客户端发了10万个连接,服务端都正常返回,跟着再发10万个连接,卡住了。
2.2.4 方案4:多线程有单独的epoll过程(方案不可用)
方案大致流程是:
createSocket();
setListenEventIn();
createPthread
{
createEpollFd();
while (1)
{
epollWait();
dealAccept
{
accept();
recv();
deal();
send();
}
}
}
这个方案比方案3在更前的步骤开多线程,由于epoll有一个epoll fd,可以建立多个epoll fd来监控事件,这个方案就是每个线程都有单独的epoll fd,监控相同的listen fd的事件。
在测试过程中,还是不稳定。
2.2.5 不可用的方案分析
由于多个accept一个socket,只有一个accept有效,这就是防止惊群效应,所以,accept多线程无法同时执行,即使用了,也要用到锁来使之变成accept单线程。
在传统的select方法,就是开多线程accept,类似于方案4,然而,哪个线程的accept可以处理,是由系统分配的,也是一个线程accept完成,其他线程才可以做accept。
2、3、4这3个方案,在测试过程中很不稳定,通常是一共处理客户端10万个请求,在第9万个开始不稳定,并且后续再开客户端向服务端请求,请求失败。
2.3 单线程和多线程选用
2.3.1 性能测试
性能测试的目的是了解方案的可行性,如果方案达不到性能要求或者不稳定,方案就需要再优化了,当前性能测试是在虚拟机上运行的。
测试环境:
硬件:CPU(6*2794MHZ) 内存(4GB)
软件:操作系统(centos6.5) 进程最大打开文件数(1048576)
测试方法:服务端一直运行,直到修改参数才重启,并且业务处理时间用usleep函数来模拟。客户端和服务端在同一台主机,客户端开多个线程,每个线程循环多次,每次向服务端发起连接请求,发送少数数据,接收服务端返回的数据。
用time命令来看整个客户端执行的时间,可以大致得到TPS,如果需要更详细的TPS和服务端的性能参数,就需要性能测试软件loadrunner和服务端的nmon命令了。
2.3.1.1 epoll et tcp 单线程
性能分析:当每个业务的处理时间为0,或者接近0时,TPS达到了3万以上,性能还是可以的。当业务处理时间为10微秒到100毫秒,性能逐渐下降,在100毫秒降到了2000以下,并且在1000微秒,也就是1毫秒的处理时间,降到了587TPS。
2.3.1.2 epoll et tcp多线程
性能分析:当每个业务的处理时间为0,或者接近0时,TPS在15,000到18,000,这种情况,业务处理的数量反而限制了TPS,可能是因为线程锁的问题,这种情况,单线程比多线程好。当处理时间在10微秒和100微秒时,业务线程的数量也限制了TPS。但是,在业务处理时间为1000微秒,也就是1毫秒时,业务线程的数量就体现出优势了,10业务线程的TPS还能有6000多,100个业务线程的TPS居然和业务处理时间为10微秒时一样的多。
2.3.2 适用场景分析
从性能测试来看,epoll单线程是在处理时间接近0时,有性能上的优势,比较适合处理简单的业务。而epoll多线程在业务处理时间比较多的情况下有性能优势,比较适合处理复杂的业务。
3 源代码
编译的时候加上 -lpthread
3.1 客户端代码
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define WAIT_OUT 0
#define WAIT_IN 1
#define MAX_PTHREAD 100000
struct dstServer
{
char pcIp[20];
char pcPort[6];
int iLoopSize;
};
void sendToServer( struct dstServer *savr );
int connectToServer( char *pcaIp, char *pcaPort );
int waitFd( int iFd, int iFlag, int iTimeOut );
pthread_mutex_t mutex;
struct dstServer svr;
int igTotalConnect = 0;
int igTotalSendSize = 0;
int igTotalRecvSize = 0;
char *pcgFileData = NULL;
int igFileDataLen = 0;
int main( int argc, char *argv[] )
{
int iTmp;
int iLoopSize;
int iPthreadSize;
pthread_t id[MAX_PTHREAD];
void *status;
char pcSendFile[1024];
FILE *fp;
if (argc < 5)
{
fprintf( stderr, "usage: %s IP PORT LOOPS PTHREAD_SIZE [file]\n", argv[0] );
return 0;
}
if(pthread_mutex_init(&mutex,NULL) != 0 )
{
printf("Init metux error.");
exit(1);
}
iLoopSize = atoi(argv[3]);
iPthreadSize = atoi(argv[4]);
if (iPthreadSize > MAX_PTHREAD)
{
iPthreadSize = MAX_PTHREAD;
}
fprintf( stdout, "total loop %d\n", iLoopSize * iPthreadSize );
memset( &svr, 0x00, sizeof(svr) );
strcpy( svr.pcIp, argv[1] );
strcpy( svr.pcPort, argv[2] );
svr.iLoopSize = iLoopSize;
if (argc == 6)//从文件读取数据
{
memset( pcSendFile, 0x00, sizeof(pcSendFile) );
strcpy( pcSendFile, argv[5] );
fp = fopen( pcSendFile, "rb" );
if (fp == NULL)
{
fprintf( stderr, "open file [%s] error\n", pcSendFile );
return 0;
}
fseek( fp, 0, SEEK_END );
igFileDataLen = ftell(fp);
rewind(fp);
pcgFileData = malloc( igFileDataLen + 1 );
if (pcgFileData == NULL)
{
fprintf( stderr, "get ram error\n" );
fclose(fp);
return 0;
}
memset( pcgFileData, 0x00, igFileDataLen + 1 );
fread( pcgFileData, 1, igFileDataLen, fp );
fclose(fp);
}
fprintf( stderr, "bat start:%ld\n", clock() );
for (iTmp = 0; iTmp < iPthreadSize; iTmp++)
{
pthread_create(&(id[iTmp]), NULL, (void *)&sendToServer, &svr);
/*线程分离,结束时自动回收资源*/
//pthread_detach(id[iTmp]); 和 pthread_join 没必要用在一起
}
for (iTmp = 0; iTmp < iPthreadSize; iTmp++)
{
pthread_join( id[iTmp], &status );
}
fprintf( stderr, "bat end:%ld\n", clock() );
return 0;
}
void sendToServer( struct dstServer *savr )
{
int iLoop;
for (iLoop = 0; iLoop < savr->iLoopSize; iLoop++)
{
connectToServer( savr->pcIp , savr->pcPort );
//fprintf( stdout, "pthreadid[%ld] loop[%d]\n", pthread_self(), iLoop + 1 );
}
return;
}
int connectToServer( char *pcaIp, char *pcaPort )
{
struct sockaddr_in servAddr; /*服务器地址信息结构体*/
struct sockaddr_in addr; /*接收到的客户端信息结构体*/
int iSocket;
char pcBuf[1024];
int iRet;
int iRecvLen = 0;
int iDataLen = 0;
/*建立socket*/
iSocket = socket(AF_INET, SOCK_STREAM, 0);
if (iSocket == -1)
{
return -1;
}
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(atoi(pcaPort));
servAddr.sin_addr.s_addr = inet_addr(pcaIp);
/*连接服务*/
if (connect(iSocket, (struct sockaddr *)(&servAddr), sizeof(struct sockaddr)) < 0)
{
fprintf( stderr, "connect error\n" );
return -1;
}
__sync_fetch_and_add(&igTotalConnect, 1);
fprintf( stdout, "pthreadId[%ld] total connect size[%d]\n", pthread_self(), igTotalConnect );
//发送数据
memset( pcBuf, 0x00, sizeof(pcBuf) );
//strcpy( pcBuf, "01234567890123456789" );
memset( pcBuf, 0x31, sizeof(pcBuf) - 1 );
if (pcgFileData == NULL)
{
memset( pcBuf, 0x00, sizeof(pcBuf) );
strcpy( pcBuf, "01234567890123456789" );
iRet = send( iSocket, pcBuf, strlen(pcBuf), 0 );
}
else
{
iRet = send( iSocket, pcgFileData, igFileDataLen, 0 );
}
fprintf( stdout, "send len[%d]\n", iRet );
__sync_fetch_and_add(&igTotalSendSize, 1);
fprintf( stdout, "pthreadId[%ld] total send size[%d]\n", pthread_self(), igTotalSendSize );
#if 1
iRet = waitFd( iSocket, WAIT_IN, 0 );
if (iRet == -1)
{
fprintf( stderr, "error\n" );
return -1;
}
#endif
//recv data
memset( pcBuf, 0x00, sizeof(pcBuf) );
iRecvLen = 0;
iDataLen = 0;
while (1)
{
iRecvLen = recv( iSocket, pcBuf + iDataLen, sizeof(pcBuf), 0 );
if (iRecvLen < 0) //recv error
{
break;
}
if (iRecvLen == 0) //recv over
{
break;
}
iDataLen += iRecvLen;
}
fprintf( stdout, "recv[%d][%s]\n", iDataLen, pcBuf );
__sync_fetch_and_add(&igTotalRecvSize, 1);
fprintf( stdout, "pthreadId[%ld] total recv size[%d]\n",pthread_self(), igTotalRecvSize );
close(iSocket);
return 0;
}
int waitFd( int iFd, int iFlag, int iTimeOut )
{
int iRc;
fd_set fds;
struct timeval sTimeval;
fd_set *fds_read = NULL;
fd_set *fds_write = NULL;
struct timeval *tv = NULL;
memset( &sTimeval, 0x00, sizeof(sTimeval) );
sTimeval.tv_sec = iTimeOut;
FD_ZERO( &fds );
FD_SET( iFd, &fds );
if (iFlag == WAIT_OUT)
{
fds_write = &fds;
}
else
{
fds_read = &fds;
}
if (iTimeOut >= 0)
{
tv = &sTimeval;
}
else
{
tv = NULL;
}
return select( iFd + 1, fds_read, fds_write, NULL, tv );
}
3.2 epoll et 服务端单线程代码
/*
测试 epoll,建立连接,固定返回值
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <fcntl.h>
#define MAX_LINKS 1024*1024 //侦听的最大数量
#define MAX_EVENT_NUM 1024*1024 //每次处理服务程序处理的事件数
#define MAX_EPOLL_LISTEN MAX_EVENT_NUM //可以监控的最大数量事件
#define TRUE 1
#define FALSE 0
#define MAX_BUF 102400
#define ERROR -1
#define SUCCESS 0
int createServerSocket( int iaPort );
int addEvent(int iaEpollFd, int iaListenFd);
int alterEventOut(int iaEpollFd, int iaRecvFd);
int delEvent(int iaEpollFd, int iaSendFd);
int dealLt(struct epoll_event *saEvents, int iaNum, int iaEpollFd, int iaSocket);
int igRecvSize = 0;
int igSendSize = 0;
int main( int argc, char *argv[] )
{
struct epoll_event *psEpollEvent;
char pcPort[5+1];
int iSocket;
int iEpollFd;
int iRet;
int iRetNum;
if (argc == 1)
{
fprintf( stdout, "usage: %s port\n", argv[0] );
return 0;
}
//get port
memset( pcPort, 0x00, sizeof(pcPort) );
strcpy( pcPort, argv[1] );
//create socket
iSocket = createServerSocket(atoi(pcPort));
if (iSocket == -1)
{
fprintf( stderr, "create server socket error\n" );
return 0;
}
//分配事件缓冲区
psEpollEvent = malloc( sizeof(struct epoll_event) * MAX_EVENT_NUM );
if (psEpollEvent == NULL)
{
fprintf( stderr, "ram is not enough\n" );
return 0;
}
//epoll create
iEpollFd = epoll_create(MAX_EPOLL_LISTEN);
if(iEpollFd < 0)
{
fprintf( stdout, "epoll create error[%d][%s]\n", errno, strerror(errno) );
return 0;
}
addEvent( iEpollFd, iSocket);
while (1)
{
//wait fd
iRetNum = epoll_wait(iEpollFd, psEpollEvent, MAX_EVENT_NUM, -1);
if(iRetNum < 0)
{
fprintf( stderr, "epoll failure\n" );
break;
}
dealLt(psEpollEvent, iRetNum, iEpollFd, iSocket);//lt模式
}
close( iSocket );
return 0;
}
/**********************************************************************
函数名称: createServerSocket
函数功能: 创建SOCKET
参 数:
第 一:端口 I
**********************************************************************/
int createServerSocket( int iaPort )
{
struct sockaddr_in server; /*服务器地址信息结构体*/
int iOpt;
int iSocket;
fprintf( stdout, "start create socket\n" );
/*建立socket*/
iSocket = socket(AF_INET, SOCK_STREAM, 0);
if (iSocket == -1)
{
fprintf( stderr, "create socket error[%d][%s]\n", errno, strerror(errno) );
return ERROR;
}
/*设置socket属性*/
iOpt = SO_REUSEADDR;
setsockopt(iSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&iOpt, sizeof(iOpt));
memset(&server, 0x00, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(iaPort);
server.sin_addr.s_addr = htonl(INADDR_ANY);
/*调用bind绑定地址*/
if (bind(iSocket, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
{
fprintf( stderr, "bind socket error[%d][%s]", errno, strerror(errno) );
return ERROR;
}
/*调用listen开始监听*/
if (listen(iSocket, MAX_LINKS) == -1)
{
fprintf( stderr, "listen socket error[%d][%s]\n", errno, strerror(errno) );
return ERROR;
}
fprintf( stdout, "create socket success\n" );
return iSocket;
}
//注册事件
int addEvent(int iaEpollFd, int iaListenFd)
{
struct epoll_event sEpollEvent;
sEpollEvent.data.fd = iaListenFd;
sEpollEvent.events = EPOLLIN;
epoll_ctl(iaEpollFd, EPOLL_CTL_ADD, iaListenFd, &sEpollEvent);
return 0;
}
//注册事件
int alterEventOut(int iaEpollFd, int iaRecvFd)
{
struct epoll_event sEpollEvent;
sEpollEvent.data.fd = iaRecvFd;
sEpollEvent.events = EPOLLOUT;
epoll_ctl(iaEpollFd, EPOLL_CTL_MOD, iaRecvFd, &sEpollEvent);
return 0;
}
//删除事件
int delEvent(int iaEpollFd, int iaSendFd)
{
struct epoll_event sEpollEvent;
sEpollEvent.data.fd = iaSendFd;
sEpollEvent.events = EPOLLIN;
epoll_ctl(iaEpollFd, EPOLL_CTL_DEL, iaSendFd, &sEpollEvent);
return 0;
}
//处理 LT 模式的事件
int dealLt(struct epoll_event *saEvents, int iaNum, int iaEpollFd, int iaSocket)
{
char pcBuf[1024*1024+1];
int iTmp;
int iSocket;
int iNewSocket;
struct sockaddr_in sClientAddr;
int iClientAddrLen;
int iRet;
int iRecvLen;
iClientAddrLen = sizeof(sClientAddr);
//处理所有事件
for (iTmp = 0; iTmp < iaNum; iTmp++)
{
iSocket = saEvents[iTmp].data.fd;//就绪的FD
//如果发生事件的 SOCKET 是侦听时的FD ,表示有连接请求
if(iSocket == iaSocket)
{
//接收连接
iNewSocket = accept(iaSocket, (struct sockaddr *)&sClientAddr, &iClientAddrLen);
//注册事件
addEvent(iaEpollFd, iNewSocket);//对new socket使用默认的lt模式
}
else if(saEvents[iTmp].events & EPOLLIN)//表示有数据进来
{
#if 1
//只要socket读缓存中还有未读的数据,这段代码就会触发
//fprintf( stdout, "event trigger once\n");
memset( pcBuf, 0x00, sizeof(pcBuf) );
iRecvLen = recv(iSocket, pcBuf, 10000, 0);
fprintf(stdout, "get %d bytes\n", iRecvLen);
if(iRecvLen == 0)//接收到主动关闭请求
{
delEvent( iaEpollFd, iSocket );
close(iSocket);
continue;
}
else if (iRecvLen < 0)//recv error
{
delEvent( iaEpollFd, iSocket );
close(iSocket);
continue;
}
//fprintf( stdout, "recv index %d\n", ++igLtRecvSize );
//fprintf(stdout, "get %d bytes\n", iRecvLen);
#else
while(1)//有可能只接收了一次,返回了大于0的子节,那就没办法判断什么时候接收结束了
{//这段代码不会重复触发,所以要循环读取数据
memset( pcBuf, 0x00, sizeof(pcBuf) );
iRecvLen = recv(iSocket, pcBuf, sizeof(pcBuf) - 1, 0);
fprintf( stdout, "recvlen[%d]\n", iRecvLen );
if(iRecvLen < 0)//recv error
{
if((errno == EAGAIN) || (errno == EWOULDBLOCK))
{
fprintf( stdout, "read later\n" );
break;
}
delEvent( iaEpollFd, iSocket );
close(iSocket);
break;
}
else if(iRecvLen == 0)//接收到主动关闭请求
{
//delEvent( iaEpollFd, iSocket );
//close(iSocket);
break;
}
else
{
printf("get %d bytes\n", iRecvLen);
}
}
#endif
igRecvSize++;
fprintf( stdout, "recv total[%d]\n", igRecvSize );
//添加输出事件
alterEventOut( iaEpollFd, iSocket );
}
else if(saEvents[iTmp].events & EPOLLOUT)
{
//fprintf( stdout, "something else happened2 \n");
send(iSocket, "12345", 5, 0 );
delEvent( iaEpollFd, iSocket );
close(iSocket);
igSendSize++;
fprintf( stdout, "send total[%d]\n", igSendSize );
}
else
{
fprintf(stdout, "something else happened\n");
delEvent( iaEpollFd, iSocket );
close(iSocket);
}
}
return 0;
}
3.3 epoll et 服务端多线程代码
/*
测试 epoll,建立连接,固定返回值
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/syscall.h>
enum pthread_command
{
PTHREAD_RUN = 0, //线程允许继续运行
PTHREAD_STOP //线程软性结束
};
enum pthread_state
{
PTHREAD_RUNING = 0, //线程正在处理
PTHREAD_SLEEP, //线程空闲中
PTHREAD_STOPPED //线程已停止
};
#define MAX_BUSS_EVENTS 100 //每个业务线程容纳的最大事件
#define EACH_RECV_EVENTS 10 //accept 线程接收了这个数量的recv事件,才放到全局缓冲区
#define EACH_SEND_EVENTS 10 //accept 线程接收了这个数量的send事件,才放到全局缓冲区
#define EACH_BUSS_EVENTS 10 //manager给每个业务线程一次分配的最多任务数量
typedef struct manager_buss_tran//控制线程和业务线程的数据交互结构
{
struct epoll_event event_buss[MAX_BUSS_EVENTS]; //业务处理的事件
int iBussEvents; //未处理事件数量
enum pthread_command cmd; //控制线程发出的命令
enum pthread_state state; //状态
pthread_cond_t condt; //控制业务线程休眠
pthread_mutex_t mutex; //业务线程和管理线程之间的锁
}mbt;
typedef struct epollDataStruct //发送数据结构体,由业务处理线程放到event中
{
char *pcData; //数据地址
int iDataLen;//数据长度
int fd; //SOCKET
int iEpollFd;//epoll fd
}eds;
#define EPOLL_WAIT_TIME_OUT 100 //epoll wait的时间,单位是毫秒
#define MAX_BUSS_PTHREADS 10 //程序定义的最大线程数量
#define ACCEPT_PTHREAD_WAIT 1000 //accept重新分配空间失败时的间隔时间,单位微秒
#define MAX_LINKS 1024*1024 //侦听的最大数量
#define MAX_EVENT_NUM 1024*1024 //每次处理服务程序处理的事件数
#define MAX_EPOLL_LISTEN MAX_EVENT_NUM //可以监控的最大数量事件
//测试结果,在处理时间为 1~1000微秒,业务线程 100 的情况下,速度是一样的
//#define __SIMULATE //定义了该宏,表示模拟处理消耗的时间,单位:微秒(10^-6)
#ifdef __SIMULATE
#define SIMULATE_TIME 1000
#endif
#define MAIN_PTHREAD_SLEEP_TIME 1 //main线程每隔时间段检查程序的状态,当收到 STOP_PROGRAM 时结束进程
#define __PTHREAD_PROPERTY_SET
#ifdef __PTHREAD_PROPERTY_SET
#define PTHREAD_STACK_SIZE 10*1024*1024 //线程栈大小,系统默认值是8MB,最小值16KB。因为要开很多个线程,这里设置1MB
#endif
pthread_cond_t condt_gAcceptManager;//accept 控制 manager 线程睡眠或运行状态
pthread_cond_t condt_gAcceptSend; //accept 控制 send 线程睡眠或运行状态
pthread_mutex_t mute_gAcceptManager;//accept 线程和业务控制线程的锁
pthread_mutex_t mute_gAcceptSend; //accept 线程和发送数据线程的锁
pthread_mutex_t mute_gBuss; //业务线程锁,用来获得线程序列号
int igPthreadBussSize; //当前业务线程数量
#define INIT_ACCEPT_MNG_BUF 1024 //accept 和控制线程数据交换区初始数量
struct epoll_event *accept_gMng = NULL; //accept 和控制现场数据交换区地址
int igAcceptMngTranSize = 0; //accept 和控制线程数据交换当前数量, 未处理的 recv event 数量
int igAcceptMngMaxTranSize = INIT_ACCEPT_MNG_BUF; //accept 和控制线程数据交换区最大值,程序执行过程中可变
#define INIT_ACCEPT_SND_BUF 1024 //accept 和发送线程数据交换区初始数量
struct epoll_event *accept_gSnd = NULL; //accept 和发送线程数据交换区地址
int igAcceptSndTranSize = 0; //accept 和发送线程数据交换当前数量, 未处理的 send event 数量
int igAcceptSndMaxTranSize = INIT_ACCEPT_SND_BUF; //accept 和发送线程数据交换区最大值,程序执行过程中可变
struct manager_buss_tran mbt_gTran[MAX_BUSS_PTHREADS];//业务控制线程和控制线程数据交互变量。在管理线程里初始化
int igMaxBussPthreads = 0; //如果这个不等于0,实际最大的业务线程数。这里暂时没有设置该变量的值
#define TRUE 1
#define FALSE 0
#define MAX_BUF 102400
#define ERROR -1
#define SUCCESS 0
#define PORT_LEN 6
//信号相关
#define INIT_PROGRAM_STATE 0 //进程初始状态
#define STOP_PROGRAM 1 //进程停止
#define SHOW_MESSAGE 2 //显示相关信息
int igStopProgram = INIT_PROGRAM_STATE;//进程状态变量
int igShowMessage = INIT_PROGRAM_STATE;//显示进程信息变量
void stopProgram(int iaSigNum);
void showMessage(int iaSigNum);
#define INIT_PTHREAD_STATE 0 //线程初始状态
#define STOP_PTHREAD_STATE 1 //线程停止
int igAcceptPthreadState = INIT_PTHREAD_STATE; //线程状态变量,accept worker 根据这个值来实现软停止
int igManagerPthreadState = INIT_PTHREAD_STATE; //线程状态变量,manager worker 根据这个值来实现软停止
int igSendPthreadState = INIT_PTHREAD_STATE; //线程状态变量,send worker 根据这个值来实现软停止
int recvClientData(int iAcceptFd, char **pcaDataOut, int *iaDataOutLen);
int dealBussData(char *pcaDataIn, int iDataInLen, char **pcaDataOut, int *iaDataOutLen);
//自定义接收函数,业务线程中用这个来接收数据。现在,这个函数指向了 recvClientData 。个人可以修改指向函数,同时新增该函数
int (*recvClient)(int iAcceptFd, char **pcaDataOut, int *iaDataOutLen) = recvClientData;
//自定义数据处理,业务线程中用这个来处理数据。现在,这个函数指向了 dealBussData 。个人可以修改指向函数,同时新增该函数
int (*dealBuss)(char *pcaDataIn, int iDataInLen, char **pcaDataOut, int *iaDataOutLen) = dealBussData;
void setSignal();//设置信号,软停止程序,或者显示进程信息
void deamon(); //进入后台
void initMutex();//初始化互斥锁
void startPthread();//启动线程
void stopPthread(); //停止线程
void acceptWorker( char *pcaPort ); //accept工作线程
void managerWorker(); //业务管理线程
void bussWorker(); //业务工作线程
void sendWorker(); //发送数据工作线程
pthread_t igAcceptWorkerId; //accept工作线程 ID
pthread_t igManagerWorkerId; //业务管理线程ID
pthread_t igSendWorkerId; //发送数据工作线程ID
char pcgPort[PORT_LEN + 1]; //侦听端口
int igBussPthreadSeq = 0; //业务线程序列号
int igAllPthreads = 0; //所有已启动的线程数量,线程创建时加1,结束是减1。程序软停止就检查这个变量值是否为 0 。
//int igEpollFd = 0;
int tcpServer( int iaPort );//创建SOCKET
int addEventAccept(int iaListenFd, struct epollDataStruct *sasdt);//将侦听SOCKET添加到事件列表
int addEventIn(int iaAcceptFd, struct epollDataStruct *saeds);//将侦听 accept fd 添加到事件列表
int alterEventOut(int iaRecvFd, struct epollDataStruct *saeds);//修改 recv fd 为输出事件
int delEvent(int iaSendFd, struct epollDataStruct *saeds);//删除 send fd 事件
int setnonblocking(int fd);//将文件描述符设置为非阻塞的
int dealAcceptEvent(struct epoll_event *saEvents, int iaNum, int iaSocket);//处理事件
struct epollDataStruct *createEpollData( char *pcData, int iDataLen, int iSocket, int iaEpollFd ); //新建 epoll data 结构
int igRecvSize = 0;//统计用
int igSendSize = 0;//统计用
int igAcceptSize = 0;//统计用
int igRecvError = 0;//统计用
int igSendError = 0;//统计用
int igAcceptError = 0;//统计用
int igTotalRecvEvent = 0;//统计用
int igTotalSendEvent = 0;//统计用
int igTotalEventOut = 0; //统计用
int main( int argc, char *argv[] )
{
int iSleepTime;
int iRet;
if (argc == 1)
{
fprintf( stdout, "usage: %s port\n", argv[0] );fflush(stdout);
return 0;
}
//get port
memset( pcgPort, 0x00, sizeof(pcgPort) );
strcpy( pcgPort, argv[1] );
//设置信号
setSignal();
//进入后台
deamon();
//初始化线程锁
initMutex();
//启动accept主线程、业务管理线程、send事件处理线程。业务工作线程在业务管理线程中启动
startPthread();
//侦听部分在acceptWorker
//主线程循环检查状态
while (igStopProgram == INIT_PROGRAM_STATE)
{
//睡眠
iSleepTime = MAIN_PTHREAD_SLEEP_TIME;
while ((iSleepTime = sleep(iSleepTime)) > 0);//用循环是为了防止被信号中断,保证一定能够睡眠这么长时间
}
//到了这里,进程软停止
//设置线程结束变量
stopPthread();//用这个函数,是为了以后扩展用,进程可能会有其他更多的资源要释放
//等待所有线程结束
while (igAllPthreads > 0)
{
//睡眠
iSleepTime = MAIN_PTHREAD_SLEEP_TIME;
while ((iSleepTime = sleep(iSleepTime)) > 0);//用循环是为了防止被信号中断,保证一定能够睡眠这么长时间
}
fprintf( stdout, "程序[%s]退出完成\n", argv[0] );fflush(stdout);
return 0;
}
/**********************************************************************
函数名称: setSignal
函数功能: 设置信号量
参 数:
返 回:异常直接退出程序
**********************************************************************/
void setSignal()
{
//捕捉信号
signal(SIGUSR1, stopProgram);//信号值10,软停止程序
signal(SIGUSR2, showMessage);//信号值12,显示进程信息,该信号量为备用
signal(SIGSEGV, stopProgram);
//忽略信号
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGALRM, SIG_IGN);
signal(SIGSEGV, SIG_IGN);//内存溢出
signal(SIGTERM, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
return;
}
/**********************************************************************
函数名称: stopProgram
函数功能: 捕捉信号值 10,软停止程序
参 数:
返 回:异常直接退出程序
**********************************************************************/
void stopProgram(int iaSigNum)
{
fprintf( stdout, "捕捉到退出信号\n" );fflush(stdout);
igStopProgram = STOP_PROGRAM;
return;
}
/**********************************************************************
函数名称: showMessage
函数功能: 捕捉信号值 12,显示进程信息
参 数:
返 回:异常直接退出程序
**********************************************************************/
void showMessage(int iaSigNum)
{
igShowMessage = SHOW_MESSAGE;
fprintf( stderr, "igRecvSize[%d]\n", igRecvSize );fflush(stderr);
fprintf( stderr, "igSendSize[%d]\n", igSendSize );fflush(stderr);
fprintf( stderr, "igAcceptSize[%d]\n", igAcceptSize );fflush(stderr);
fprintf( stderr, "igRecvError[%d]\n", igRecvError );fflush(stderr);
fprintf( stderr, "igSendError[%d]\n", igSendError );fflush(stderr);
fprintf( stderr, "igAcceptError[%d]\n", igAcceptError );fflush(stderr);
fprintf( stderr, "igTotalRecvEvent[%d]\n", igTotalRecvEvent );fflush(stderr);
fprintf( stderr, "igTotalSendEvent[%d]\n", igTotalSendEvent );fflush(stderr);
fprintf( stderr, "igTotalEventOut[%d]\n", igTotalEventOut );fflush(stderr);
return;
}
/**********************************************************************
函数名称: deamon
函数功能: 进入后台
参 数:
返 回:异常直接退出程序
**********************************************************************/
void deamon()
{
//进入子进程
if (fork() != 0)
{
exit(1);
}
//进入孙子进程
if (fork() != 0)
{
exit(1);
}
return;
}
/**********************************************************************
函数名称: initMutex
函数功能: 初始化线程锁
参 数:
返 回:异常直接退出程序
**********************************************************************/
void initMutex()
{
int iTmp;
//初始化condt
pthread_cond_init(&condt_gAcceptManager, NULL);
pthread_cond_init(&condt_gAcceptSend, NULL);
//初始化 accept 线程和业务控制线程的锁
if(pthread_mutex_init(&mute_gAcceptManager, NULL) != 0 )
{
fprintf( stderr, "init metux accept manager error\n" ); fflush(stderr);
exit(1);
}
//初始化 accept 线程和发送数据线程的锁
if(pthread_mutex_init(&mute_gAcceptSend, NULL) != 0 )
{
fprintf( stderr, "init metux accept send error\n" ); fflush(stderr);
exit(1);
}
return;
}
/**********************************************************************
函数名称: startPthread
函数功能: 启动accept主线程、业务管理线程、send事件处理线程
参 数:
返 回:异常直接退出程序
**********************************************************************/
void startPthread()
{
#ifdef __PTHREAD_PROPERTY_SET //自定义线程属性
pthread_attr_t pthAttr; //线程属性变量
//初始化线程属性变量
pthread_attr_init(&pthAttr);
/*
size_t size = 0;
pthread_attr_getstacksize(&pthAttr, &size);
fprintf(stdout, "current thread stack size:%d\n", size);
*/
//设置栈大小
if (pthread_attr_setstacksize(&pthAttr, PTHREAD_STACK_SIZE) != 0)
{
fprintf( stderr, "pthread set stack size error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
//设置线程分离
if (pthread_attr_setdetachstate(&pthAttr, PTHREAD_CREATE_DETACHED) != 0)
{
fprintf( stderr, "pthread set detached error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
//建立 accept 主线程
if (pthread_create(&igAcceptWorkerId, &pthAttr, (void *)(&acceptWorker), pcgPort ) != 0)
{
fprintf( stderr, "start accept worker error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
//建立业务管理线程
if (pthread_create(&igManagerWorkerId, &pthAttr, (void *)(&managerWorker), NULL ) != 0)
{
fprintf( stderr, "start manager worker error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
//建立发送数据业务线程
if (pthread_create(&igSendWorkerId, &pthAttr, (void *)(&sendWorker), NULL ) != 0)
{
fprintf( stderr, "start send worker error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
//销毁线程属性结构,它在重新初始化之前不能重新使用
pthread_attr_destroy(&pthAttr);
#else
//建立 accept 主线程
if (pthread_create(&igAcceptWorkerId, NULL, (void *)(&acceptWorker), pcgPort ) != 0)
{
fprintf( stderr, "start accept worker error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
/*线程分离,结束时自动回收资源*/
pthread_detach(igAcceptWorkerId);
//建立业务管理线程
if (pthread_create(&igManagerWorkerId, NULL, (void *)(&managerWorker), NULL ) != 0)
{
fprintf( stderr, "start manager worker error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
/*线程分离,结束时自动回收资源*/
pthread_detach(igManagerWorkerId);
//建立发送数据线程
if (pthread_create(&igSendWorkerId, NULL, (void *)(&sendWorker), NULL ) != 0)
{
fprintf( stderr, "start send worker error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
/*线程分离,结束时自动回收资源*/
pthread_detach(igSendWorkerId);
#endif
return;
}
/**********************************************************************
函数名称: stopPthread
函数功能: 停止accept主线程、业务管理线程、send事件处理线程
参 数:
返 回:异常直接退出程序
**********************************************************************/
void stopPthread()
{
igAcceptPthreadState = STOP_PTHREAD_STATE;
/*
进程退出步骤
1. accept worker 收到信号,开始退出,并设置 manager worker 和 send worker 状态,唤醒这两个线程,退出
2. manager worker 退出,设置状态,让 buss worker 退出
*/
}
/**********************************************************************
函数名称: acceptWorker
函数功能: 建立SOCKET、等待事件处理
参 数:
返 回:异常直接退出程序
**********************************************************************/
void acceptWorker( char *pcaPort )
{
struct epoll_event *psEpollEvent;
int iSocket;
int iRetNum;
int iEpollFd;
struct epollDataStruct *edsNew;//epoll数据结构体
fprintf( stdout, "[%s][%d]acceptWorker PthreadId[%ld]\n", __FUNCTION__, __LINE__, syscall(SYS_gettid) );fflush(stdout);
//create socket
iSocket = tcpServer(atoi(pcaPort));
if (iSocket == -1)
{
fprintf( stderr, "create server socket error\n" );fflush(stderr);
exit(1);
}
//分配事件缓冲区
psEpollEvent = malloc( sizeof(struct epoll_event) * MAX_EVENT_NUM );
if (psEpollEvent == NULL)
{
fprintf( stderr, "ram is not enough\n" );fflush(stderr);
exit(1);
}
memset( psEpollEvent, 0x00, sizeof(struct epoll_event) * MAX_EVENT_NUM );
//epoll create
iEpollFd = epoll_create(MAX_EPOLL_LISTEN);
if(iEpollFd < 0)
{
fprintf( stderr, "epoll create error[%d][%s]\n", errno, strerror(errno) );fflush(stderr);
exit(1);
}
edsNew = createEpollData( NULL, 0, iSocket, iEpollFd );
if (edsNew == NULL)
{
fprintf( stderr, "get ram [%lu] error\n", sizeof(struct epollDataStruct) );fflush(stderr);
exit(1);
}
//accept-manager交换区
accept_gMng = malloc( sizeof(struct epoll_event) * INIT_ACCEPT_MNG_BUF );
if (accept_gMng == NULL)
{
fprintf( stderr, "ram is not enough\n" );fflush(stderr);
exit(1);
}
memset( accept_gMng, 0x00, sizeof(struct epoll_event) * INIT_ACCEPT_MNG_BUF );
igAcceptMngTranSize = 0;
//accept-send交换区
accept_gSnd = malloc( sizeof(struct epoll_event) * INIT_ACCEPT_SND_BUF );
if (accept_gSnd == NULL)
{
fprintf( stderr, "ram is not enough\n" );fflush(stderr);
exit(1);
}
memset( accept_gSnd, 0x00, sizeof(struct epoll_event) * INIT_ACCEPT_SND_BUF );
igAcceptMngTranSize = 0;
//添加侦听事件
addEventAccept( iSocket, edsNew );
__sync_fetch_and_add(&igAllPthreads, 1); //进程的线程数加1
//循环处理事件
while (igAcceptPthreadState == INIT_PTHREAD_STATE)
{
//wait fd
iRetNum = epoll_wait(iEpollFd, psEpollEvent, MAX_EVENT_NUM, EPOLL_WAIT_TIME_OUT);
//fprintf( stdout, "[%s][%d]retnum[%d]\n", __FUNCTION__, __LINE__, iRetNum );fflush(stdout);
if(iRetNum < 0)
{
fprintf( stderr, "epoll failure\n" );fflush(stderr);
continue;
}
if(iRetNum == 0)
{
continue;
}
//这里,把事件给线程
dealAcceptEvent(psEpollEvent, iRetNum, iSocket);//处理事件
//exit(0);
}
fprintf( stdout, "acceptWorker 收到信号,开始退出\n" );fflush(stdout);
delEvent( iSocket, edsNew );
close( iSocket );
if (edsNew != NULL)//该结构体只能在这里释放了
{
free( edsNew );
edsNew = NULL;
}
igManagerPthreadState = STOP_PTHREAD_STATE;
igSendPthreadState = STOP_PTHREAD_STATE;
//激活业务管理线程和数据发送线程
if (pthread_mutex_trylock(&mute_gAcceptManager) == 0)
{
pthread_cond_signal(&condt_gAcceptManager);
pthread_mutex_unlock(&mute_gAcceptManager);
}
if (pthread_mutex_trylock(&mute_gAcceptSend) == 0)
{
pthread_cond_signal(&condt_gAcceptSend);
pthread_mutex_unlock(&mute_gAcceptSend);
}
if (accept_gMng != NULL)
{
free(accept_gMng);
accept_gMng = NULL;
}
if (accept_gSnd != NULL)
{
free(accept_gSnd);
accept_gSnd = NULL;
}
fprintf( stdout, "acceptWorker 退出完成\n" );fflush(stdout);
__sync_fetch_and_sub(&igAllPthreads, 1); //进程的线程数减1
pthread_exit(NULL);//线程退出
return;
}
/**********************************************************************
函数名称: managerWorker
函数功能: 业务管理线程
参 数:
返 回:异常直接退出程序
**********************************************************************/
void managerWorker()
{
pthread_t pthreadIdBuss[MAX_BUSS_PTHREADS]; //业务线程PTHREAD ID
int iBussPthreadTmp = 0; //临时变量
int iTotalPhtread = 0; //全部业务线程
int iAllocEvents = 0; //已分配任务数量
int iPthreadSeq = 0; //当前线程序列号
struct epoll_event *accept_mng = NULL; //accpet-manager待处理数据
int iAcceptMngMaxTranSize = 0; //accept-manager待处理数据最大数量,程序执行过程中可变
int iAcceptMngTranSize = 0; //accept-manager待处理数据当前数量
int iTmp;
int *piBussEvents;
fprintf( stdout, "[%s][%d]managerWorker PthreadId[%ld]\n", __FUNCTION__, __LINE__, syscall(SYS_gettid) );fflush(stdout);
//计算实际最大业务线程数量
if (igMaxBussPthreads == 0 || igMaxBussPthreads > MAX_BUSS_PTHREADS)
{
iTotalPhtread = MAX_BUSS_PTHREADS;
}
else
{
iTotalPhtread = igMaxBussPthreads;
}
//初始化业务线程锁
if(pthread_mutex_init(&mute_gBuss, NULL) != 0 )
{
fprintf( stderr, "init metux accept send error\n" ); fflush(stderr);
exit(1);
}
//建立业务线程,业务线程里面自己休眠
memset( &pthreadIdBuss, 0x00, sizeof(pthreadIdBuss) );
memset( &mbt_gTran, 0x00, sizeof(mbt_gTran) );
for (iBussPthreadTmp = 0; iBussPthreadTmp < iTotalPhtread; iBussPthreadTmp++)
{
//初始化业务线程和管理线程的锁
if(pthread_mutex_init(&(mbt_gTran[iBussPthreadTmp].mutex), NULL) != 0 )
{
fprintf( stderr, "init metux accept send error\n" ); fflush(stderr);
exit(1);
}
//设置线程命令
mbt_gTran[iBussPthreadTmp].cmd = PTHREAD_RUN;
//初始化condt
pthread_cond_init(&(mbt_gTran[iBussPthreadTmp].condt), NULL);
#ifdef __PTHREAD_PROPERTY_SET //自定义线程属性
pthread_attr_t pthAttr; //线程属性变量
//初始化线程属性变量
pthread_attr_init(&pthAttr);
//设置栈大小
if (pthread_attr_setstacksize(&pthAttr, PTHREAD_STACK_SIZE) != 0)
{
fprintf( stderr, "pthread set stack size error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
//设置线程分离
if (pthread_attr_setdetachstate(&pthAttr, PTHREAD_CREATE_DETACHED) != 0)
{
fprintf( stderr, "pthread set detached error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
//建立业务线程
if (pthread_create(&(pthreadIdBuss[iBussPthreadTmp]), &pthAttr, (void *)(&bussWorker), NULL ) != 0)
{
fprintf( stderr, "start accept worker error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
//销毁线程属性结构,它在重新初始化之前不能重新使用
pthread_attr_destroy(&pthAttr);
#else
//建立业务线程
if (pthread_create(&(pthreadIdBuss[iBussPthreadTmp]), NULL, (void *)(&bussWorker), NULL ) != 0)
{
fprintf( stderr, "start accept worker error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
exit(1);
}
/*线程分离,结束时自动回收资源*/
pthread_detach(pthreadIdBuss[iBussPthreadTmp]);
#endif
}
//初始化本地缓冲区
accept_mng = malloc( sizeof(struct epoll_event) * INIT_ACCEPT_MNG_BUF );
if (accept_mng == NULL)
{
fprintf( stderr, "ram is not enough\n" );fflush(stderr);
exit(1);
}
memset( accept_mng, 0x00, sizeof(struct epoll_event) * INIT_ACCEPT_MNG_BUF );
iAcceptMngMaxTranSize = INIT_ACCEPT_MNG_BUF;
iAcceptMngTranSize = 0;
__sync_fetch_and_add(&igAllPthreads, 1); //进程的线程数加1
//开始管理业务线程,分配任务
while (1)
{
while (1)//获取accept-manager交换区的全部数据
{
//获取accept-manager线程锁
pthread_mutex_lock(&mute_gAcceptManager);
if (igManagerPthreadState == STOP_PTHREAD_STATE && igAcceptMngTranSize == 0)//如果线程是停止命令,并且没有任务数
{
fprintf( stdout, "managerWorker 收到信号,开始退出\n" );fflush(stdout);
pthread_mutex_unlock(&mute_gAcceptManager);
break;
}
//fprintf( stdout, "[%s][%d]igRecvEvents[%d]\n", __FUNCTION__, __LINE__, igRecvEvents );fflush(stdout);
//如果没有事件要处理
if (igAcceptMngTranSize == 0)
{
//等待信号
pthread_cond_wait(&condt_gAcceptManager, &mute_gAcceptManager);
//释放accept-manager线程锁
pthread_mutex_unlock(&mute_gAcceptManager);
continue;
}
//全部任务数量
iAcceptMngTranSize = igAcceptMngTranSize;
if (iAcceptMngTranSize > iAcceptMngMaxTranSize)//超出当前容纳的最大数量,扩展空间
{
iAcceptMngMaxTranSize = iAcceptMngTranSize;
accept_mng = realloc(accept_mng, sizeof(struct epoll_event) * iAcceptMngMaxTranSize);
if (accept_mng == NULL)
{
pthread_mutex_unlock(&mute_gAcceptManager);
usleep(ACCEPT_PTHREAD_WAIT);
continue;
}
memset( accept_mng, 0x00, sizeof(struct epoll_event) * iAcceptMngMaxTranSize );
}
else
{
memset( accept_mng, 0x00, sizeof(struct epoll_event) * iAcceptMngMaxTranSize );
}
memcpy( accept_mng, accept_gMng, sizeof(struct epoll_event) * iAcceptMngTranSize );
//初始化accept-manager交互区、初始化全部任务数量
memset( accept_gMng, 0x00, sizeof(struct epoll_event) * igAcceptMngTranSize );
igAcceptMngTranSize = 0;
//释放accept-manager线程锁
pthread_mutex_unlock(&mute_gAcceptManager);
break;
}
if (igManagerPthreadState == STOP_PTHREAD_STATE && igAcceptMngTranSize == 0)//和上面while循环的break一样。如果线程是停止命令,并且没有任务数。
{
pthread_mutex_unlock(&mute_gAcceptManager);//上面已经解锁了
break;
}
//fprintf( stdout, "[%s][%d]开始任务分配\n", __FUNCTION__, __LINE__ );fflush(stdout);
//开始任务分配
iAllocEvents = 0;
while (1)
{
//所有任务分配完了
if (iAllocEvents == iAcceptMngTranSize)
{
break;
}
//如果当前序列号超过最大值
if (iPthreadSeq >= iTotalPhtread)
{
iPthreadSeq = 0;
}
//fprintf( stdout, "[%s][%d]获取manager-buss锁\n", __FUNCTION__, __LINE__ );fflush(stdout);
//获取manager-buss锁,如果获取失败,表示业务线程正在工作,寻找下一个线程
if (pthread_mutex_trylock(&(mbt_gTran[iPthreadSeq].mutex)) != 0)
{
iPthreadSeq++;
continue;
}
//fprintf( stdout, "[%s][%d]线程序列号[%d]\n", __FUNCTION__, __LINE__, iPthreadSeq );fflush(stdout);
//指向当前线程未处理的业务数量
piBussEvents = &(mbt_gTran[iPthreadSeq].iBussEvents);
//如果业务线程的缓冲区满了
if (*piBussEvents >= MAX_BUSS_EVENTS)
{
//激活业务线程,并释放manager-buss的锁
pthread_cond_signal(&(mbt_gTran[iPthreadSeq].condt));
pthread_mutex_unlock(&(mbt_gTran[iPthreadSeq].mutex));
iPthreadSeq++;
continue;
}
//fprintf( stdout, "[%s][%d]添加到manager-buss交互区\n", __FUNCTION__, __LINE__ );fflush(stdout);
//添加到manager-buss交互区
for (iTmp = 0; iTmp < EACH_BUSS_EVENTS; iTmp++)
{
//fprintf( stdout, "[%s][%d]剩余业务总数量[%d]\n", __FUNCTION__, __LINE__, iRestEvents );fflush(stdout);
if (iAllocEvents == iAcceptMngTranSize)//如果没有业务数据了
{
break;
}
if (*piBussEvents >= MAX_BUSS_EVENTS)//如果超出了每个线程处理的业务最大数量
{
break;
}
//fprintf( stdout, "[%s][%d]开始设置事件\n", __FUNCTION__, __LINE__ );fflush(stdout);
//设置事件
memcpy( &(mbt_gTran[iPthreadSeq].event_buss[*piBussEvents]), accept_mng + iAllocEvents, sizeof(struct epoll_event) );
//未处理业务数量加1
(*piBussEvents)++;
//已分配业务数量加1
iAllocEvents++;
//fprintf( stdout, "[%s][%d]设置事件完成\n", __FUNCTION__, __LINE__ );fflush(stdout);
}
//激活业务线程,并释放manager-buss的锁
pthread_cond_signal(&(mbt_gTran[iPthreadSeq].condt));
pthread_mutex_unlock(&(mbt_gTran[iPthreadSeq].mutex));
//fprintf( stdout, "[%s][%d]激活业务线程完成\n", __FUNCTION__, __LINE__ );fflush(stdout);
iPthreadSeq++;
}
}
fprintf( stdout, "[%s][%d]管理线程收到信号,开始结束\n", __FUNCTION__, __LINE__ );fflush(stdout);
//fprintf( stdout, "iTotalPhtread[%d]\n", iTotalPhtread );fflush(stdout);
//管理线程结束,释放业务线程
for (iTmp = 0; iTmp < iTotalPhtread; iTmp++)
{
//fprintf( stdout, "[%s][%d]获取manager-buss[%d]锁\n", __FUNCTION__, __LINE__, iTmp );fflush(stdout);
pthread_mutex_lock(&(mbt_gTran[iTmp].mutex));
mbt_gTran[iTmp].cmd = PTHREAD_STOP;
//激活业务线程,并释放manager-buss的锁
pthread_cond_signal(&(mbt_gTran[iTmp].condt));
pthread_mutex_unlock(&(mbt_gTran[iTmp].mutex));
//fprintf( stdout, "[%s][%d]释放manager-buss[%d]锁\n", __FUNCTION__, __LINE__, iTmp );fflush(stdout);
}
//fprintf( stdout, "managerWorker 释放buss线程结束\n" );fflush(stdout);
if (accept_mng != NULL)
{
free(accept_mng);
accept_mng = NULL;
}
fprintf( stdout, "managerWorker 退出完成\n" );fflush(stdout);
__sync_fetch_and_sub(&igAllPthreads, 1); //进程的线程数减1
pthread_exit(NULL);
return;
}
/**********************************************************************
函数名称: bussWorker
函数功能: 业务工作线程
参 数:
返 回:异常直接退出程序
**********************************************************************/
void bussWorker( )
{
struct epoll_event event_buss[MAX_BUSS_EVENTS];
int iBussEvents;
int iPthreadSeq; //线程序列号
int iTmp;
int iRet;
int iSocket;
int iEpollFd; //epoll fd
char *pcRecvData;//接收到的数据
int iRecvDataLen;//接收到的数据长度
char *pcSendData;//业务处理后要发送的数据
int iSendDataLen;//发送数据长度
struct epollDataStruct *eds_data;//epoll数据结构体
//业务线程加锁,获取线程序列号
pthread_mutex_lock(&mute_gBuss);
iPthreadSeq = igBussPthreadSeq;
igBussPthreadSeq++;
//释放业务线程之间的锁
pthread_mutex_unlock(&mute_gBuss);
//fprintf( stdout, "[%s][%d]释放业务锁完成iPthreadSeq[%d]\n", __FUNCTION__, __LINE__, iPthreadSeq );fflush(stdout);
__sync_fetch_and_add(&igAllPthreads, 1); //进程的线程数加1
while (1)
{
//fprintf( stdout, "[%s][%d]获取manager-buss锁[%d]\n", __FUNCTION__, __LINE__, iPthreadSeq );fflush(stdout);
//对管理线程和业务线程之间加锁
pthread_mutex_lock(&(mbt_gTran[iPthreadSeq].mutex));
//fprintf( stdout, "bussWorker state[%d]\n", mbt_gTran[iPthreadSeq].cmd );fflush(stdout);
if (mbt_gTran[iPthreadSeq].cmd == PTHREAD_STOP && mbt_gTran[iPthreadSeq].iBussEvents == 0)//如果线程是停止命令
{
mbt_gTran[iPthreadSeq].state = PTHREAD_STOPPED; //线程已停止
pthread_mutex_unlock(&(mbt_gTran[iPthreadSeq].mutex));//释放管理线程和业务线程之间的锁
fprintf( stdout, "bussWorker 收到信号,开始退出\n" );fflush(stdout);
break;
}
//fprintf( stdout, "[%s][%d]bussEvents[%d]\n", __FUNCTION__, __LINE__, mbt_gTran[iPthreadSeq].iBussEvents );fflush(stdout);
//如果条件数为0,等待
if (mbt_gTran[iPthreadSeq].iBussEvents == 0)
{
//fprintf( stdout, "[%s][%d]等待唤醒信号\n", __FUNCTION__, __LINE__ );fflush(stdout);
//设置线程工作状态
mbt_gTran[iPthreadSeq].state = PTHREAD_SLEEP;
pthread_cond_wait(&(mbt_gTran[iPthreadSeq].condt), &(mbt_gTran[iPthreadSeq].mutex));
pthread_mutex_unlock(&(mbt_gTran[iPthreadSeq].mutex));
continue;
}
//设置线程工作状态
mbt_gTran[iPthreadSeq].state = PTHREAD_RUNING;
//获取业务内容
iBussEvents = mbt_gTran[iPthreadSeq].iBussEvents;
memset( &event_buss, 0x00, sizeof(event_buss) );
memcpy( &event_buss, &(mbt_gTran[iPthreadSeq].event_buss), sizeof(struct epoll_event) * iBussEvents );
//初始化数据交互区的待处理事件
memset( &(mbt_gTran[iPthreadSeq].event_buss), 0x00, sizeof(mbt_gTran[iPthreadSeq].event_buss) );
mbt_gTran[iPthreadSeq].iBussEvents = 0;
//释放管理线程和业务线程之间的锁
pthread_mutex_unlock(&(mbt_gTran[iPthreadSeq].mutex));
//fprintf( stdout, "[%s][%d]开始业务处理\n", __FUNCTION__, __LINE__ );fflush(stdout);
//开始业务处理
for (iTmp = 0; iTmp < iBussEvents; iTmp++)
{
eds_data = (struct epollDataStruct *)event_buss[iTmp].data.ptr;
iSocket = eds_data->fd;
iEpollFd = eds_data->iEpollFd;
//fprintf( stdout, "[%s][%d]iSocket[%d]\n", __FUNCTION__, __LINE__, iSocket );fflush(stdout);
pcRecvData = NULL;
iRecvDataLen = 0;
//接收数据,函数可以自定义
iRet = (*recvClient)( iSocket, &pcRecvData, &iRecvDataLen );
if (iRet != 0)
{
if (pcRecvData != NULL)
{
free(pcRecvData);
pcRecvData = NULL;
}
delEvent( iSocket, eds_data );
close(iSocket);
//free(eds_data);
igRecvError++;
continue;
}
//fprintf( stdout, "[%s][%d]socketFd[%d]接收到数据[%d][%s]\n", __FUNCTION__, __LINE__,iSocket, iRecvDataLen, pcRecvData );fflush(stdout);
pcSendData = NULL;
iSendDataLen = 0;
//调用业务处理函数
iRet = (*dealBuss)( pcRecvData, iRecvDataLen, &pcSendData, &iSendDataLen );
if (iRet != 0)
{
if (pcRecvData != NULL)
{
free(pcRecvData);
pcRecvData = NULL;
}
if (pcSendData != NULL)
{
free(pcSendData);
pcSendData = NULL;
}
delEvent( iSocket, eds_data );
close(iSocket);
//free(eds_data);
continue;
}
#ifdef __SIMULATE
usleep(SIMULATE_TIME);//模拟处理消耗的时间,微秒
#endif
//fprintf( stdout, "[%s][%d]socket fd[%d]处理后的数据[%d][%s]\n", __FUNCTION__, __LINE__, iSocket, iSendDataLen, pcSendData );fflush(stdout);
if (pcRecvData != NULL)//接收数据到这里没用了
{
free(pcRecvData);
pcRecvData = NULL;
}
//fprintf( stdout, "[%s][%d]socket fd[%d]开始设置发送数据结构体\n", __FUNCTION__, __LINE__, iSocket );fflush(stdout);
eds_data->pcData = pcSendData;
eds_data->iDataLen = iSendDataLen;
//fprintf( stdout, "[%s][%d]socket fd[%d]设置发送数据结构体结束\n", __FUNCTION__, __LINE__, iSocket );fflush(stdout);
//将处理后的数据添加到事件中,让accept线程转给发送数据线程发送出去
//eds_data记得要在发送线程释放
alterEventOut( iSocket, eds_data );
//fprintf( stdout, "[%s][%d]已经添加到事件\n", __FUNCTION__, __LINE__ );fflush(stdout);
}
}
fprintf( stdout, "bussWorker 退出完成\n" );fflush(stdout);
__sync_fetch_and_sub(&igAllPthreads, 1); //进程的线程数减1
pthread_exit(NULL);
return;
}
/**********************************************************************
函数名称: sendWorker
函数功能: send事件处理线程
参 数:
返 回:异常直接退出程序
**********************************************************************/
void sendWorker()
{
char *pcSendData;
int iSendDataLen;
int iRet;
int iAllocEvents;
int iSendLen;
int iSocket;
struct epollDataStruct *eds_data;//发送数据结构体
struct epoll_event *accept_snd = NULL; //accpet-send待处理数据
int iAcceptSndMaxTranSize = 0; //accept-send待处理数据最大数量,程序执行过程中可变
int iAcceptSndTranSize = 0; //accept-send待处理数据当前数量
fprintf( stdout, "[%s][%d]sendWorker PthreadId[%ld]\n", __FUNCTION__, __LINE__, syscall(SYS_gettid) );fflush(stdout);
//初始化本地缓冲区
accept_snd = malloc( sizeof(struct epoll_event) * INIT_ACCEPT_SND_BUF );
if (accept_snd == NULL)
{
fprintf( stderr, "ram is not enough\n" );fflush(stderr);
exit(1);
}
memset( accept_snd, 0x00, sizeof(struct epoll_event) * INIT_ACCEPT_SND_BUF );
iAcceptSndMaxTranSize = INIT_ACCEPT_MNG_BUF;
iAcceptSndTranSize = 0;
__sync_fetch_and_add(&igAllPthreads, 1); //进程的线程数加1
while (1)
{
while (1)//获取所有任务
{
//fprintf( stdout, "[%s][%d]获取accept-send锁\n", __FUNCTION__, __LINE__ );fflush(stdout);
//获取accept-send线程锁
pthread_mutex_lock(&mute_gAcceptSend);
if (igSendPthreadState == STOP_PTHREAD_STATE && igAcceptSndTranSize == 0)//如果线程是停止命令,并且没有任务数
{
fprintf( stdout, "sendWorker 收到信号,开始退出\n" );fflush(stdout);
pthread_mutex_unlock(&mute_gAcceptSend);
break;
}
//如果没有事件要处理
if (igAcceptSndTranSize == 0)
{
//等待信号
pthread_cond_wait(&condt_gAcceptSend, &mute_gAcceptSend);
//释放accept-manager线程锁
pthread_mutex_unlock(&mute_gAcceptSend);
continue;
}
///fprintf( stdout, "[%s][%d]igSendEvents[%d]\n", __FUNCTION__, __LINE__,igSendEvents );fflush(stdout);
//全部任务数量
iAcceptSndTranSize = igAcceptSndTranSize;
if (iAcceptSndTranSize > iAcceptSndMaxTranSize)//超出当前容纳的最大数量,扩展空间
{
iAcceptSndMaxTranSize = iAcceptSndTranSize;
accept_snd = realloc(accept_snd, sizeof(struct epoll_event) * iAcceptSndMaxTranSize);
if (accept_snd == NULL)
{
pthread_mutex_unlock(&mute_gAcceptManager);
usleep(ACCEPT_PTHREAD_WAIT);
continue;
}
memset( accept_snd, 0x00, sizeof(struct epoll_event) * iAcceptSndMaxTranSize );
}
else
{
memset( accept_snd, 0x00, sizeof(struct epoll_event) * iAcceptSndMaxTranSize );
}
memcpy( accept_snd, accept_gSnd, sizeof(struct epoll_event) * iAcceptSndTranSize );
//初始化accept-send交互区、初始化全部任务数量
memset( accept_gSnd, 0x00, sizeof(struct epoll_event) * igAcceptSndTranSize );
igAcceptSndTranSize = 0;
//释放accept-send线程锁
pthread_mutex_unlock(&mute_gAcceptSend);
break;
}
if (igSendPthreadState == STOP_PTHREAD_STATE && igAcceptSndTranSize == 0)//和上面一个while循环的break一样。如果线程是停止命令,并且没有任务数
{
//pthread_mutex_unlock(&mute_gAcceptSend);上面已经解锁了
break;
}
//开始发送数据
iAllocEvents = 0;
while (1)
{
//fprintf( stdout, "[%s][%d]iRestEvents[%d]acceptHead[%p]\n", __FUNCTION__, __LINE__, iRestEvents, acceptHead );fflush(stdout);
//所有数据发送完了
if (iAllocEvents == iAcceptSndTranSize)
{
break;
}
//fprintf( stdout, "[%s][%d]ptr[%p]\n", __FUNCTION__, __LINE__, acceptHead->event_accept.data.ptr );fflush(stdout);
//发送数据、发送长度、发送SOCKET
eds_data = accept_snd[iAllocEvents].data.ptr;
pcSendData = eds_data->pcData;
iSendDataLen = eds_data->iDataLen;
iSocket = eds_data->fd;
//fprintf( stdout, "[%s][%d]iSendDataLen[%d]pcSendData[%s]\n", __FUNCTION__, __LINE__, iSendDataLen, pcSendData );fflush(stdout);
if (pcSendData != NULL && iSendDataLen > 0)
{
//发送数据
iSendLen = 0;
while (1)
{
iRet = send(iSocket, pcSendData + iSendLen, iSendDataLen - iSendLen, 0 );
if (iRet < 0)//客户端关闭SOCKET
{
//fprintf( stderr, "send data error\n" );fflush(stderr);
break;
}
iSendLen += iRet;
if (iSendLen == iSendDataLen)
{
break;
}
}
}
if (pcSendData != NULL)//释放在业务处理中分配的内存
{
//free(pcSendData);
pcSendData = NULL;
}
delEvent( iSocket, eds_data );//删除监控在accept-worker添加的SOCKET
close(iSocket);
if (eds_data != NULL)//释放该结构体
{
free(eds_data);
eds_data = NULL;
}
//fprintf( stdout, "send success \n");
igSendSize++;
//fprintf( stdout, "[%s][%d]send total[%d]sendLen[%d]\n", __FUNCTION__, __LINE__, igSendSize, iSendLen );fflush(stdout);
//已处理任务加1
iAllocEvents++;
}
}
fprintf( stdout, "sendWorker 退出完成\n" );fflush(stdout);
__sync_fetch_and_sub(&igAllPthreads, 1); //进程的线程数减1
pthread_exit(NULL);
return;
}
/**********************************************************************
函数名称: dealAcceptEvent
函数功能: accept 线程处理事件
参 数:
第 一:(I)事件列表
第 二:(I)事件数量
第 三:(I)socket fd
返 回: 0表示成功
**********************************************************************/
int dealAcceptEvent(struct epoll_event *saEvents, int iaNum, int iaSocket)
{
int iTmp;
int iNumTmp;
int iRecvLen;
int iSocket;
int iNewSocket;
struct sockaddr_in sClientAddr;
int iClientAddrLen;
int iRet;
struct epoll_event eventRecv[EACH_RECV_EVENTS];//接收事件缓冲区
struct epoll_event eventSend[EACH_SEND_EVENTS];//发送事件缓冲区
int iEventRecv;//接收事件数
int iEventSend;//发送事件数
struct epollDataStruct *edsNew; //epoll data 结构变量
struct epollDataStruct *eds_data;//epoll data 结构变量
int iEpollFd; // epoll fd
iClientAddrLen = sizeof(sClientAddr);
memset( &eventRecv, 0x00, sizeof(eventRecv) );
memset( &eventSend, 0x00, sizeof(eventSend) );
iEventRecv = 0;
iEventSend = 0;
//fprintf( stdout, "EPOLLIN[%d]EPOLLOUT[%d]\n", EPOLLIN, EPOLLOUT );
for (iNumTmp = 0; iNumTmp < iaNum; iNumTmp++)
{
eds_data = saEvents[iNumTmp].data.ptr;//事件数据
iSocket = eds_data->fd;//就绪的FD
iEpollFd = eds_data->iEpollFd; //epoll fd
//fprintf( stdout, "[%s][%d]socket[%d]iaSocket[%d]event[%d]\n", __FUNCTION__, __LINE__, iSocket, iaSocket, saEvents[iNumTmp].events );fflush(stdout);
if(iSocket == iaSocket)//三次握手
{
iNewSocket = accept(iaSocket, (struct sockaddr *)&sClientAddr, &iClientAddrLen);
if (iNewSocket < 0)
{
//fprintf( stderr, "accept error\n" );fflush(stderr);
igAcceptError++;
continue;
}
edsNew = createEpollData( NULL, 0, iNewSocket, iEpollFd );
if (edsNew == NULL)
{
//fprintf( stderr, "get ram [%lu] error\n", sizeof(struct epollDataStruct) );
close(iNewSocket);
continue;
}
if (addEventIn( iNewSocket, edsNew ) != 0)//添加accept fd
{
close(iNewSocket);
continue;
}
igAcceptSize++;
//fprintf( stdout, "[%s][%d]accept total %d\n", __FUNCTION__, __LINE__, igAcceptSize );fflush(stdout);
}
else
if(saEvents[iNumTmp].events & EPOLLIN)
{
//将事件添加到临时变量
memcpy( &(eventRecv[iEventRecv]), saEvents+iNumTmp, sizeof(struct epoll_event) );
iEventRecv++;
igTotalRecvEvent++;
//如果缓冲区慢了,将所有数据添加到 accept-manager 交互区
if (iEventRecv == EACH_RECV_EVENTS)
{
//添加到数据交互区
while (1)
{
//加锁
pthread_mutex_lock(&mute_gAcceptManager);
if (igAcceptMngTranSize + iEventRecv > igAcceptMngMaxTranSize)//如果数量超了,重新分配缓冲区
{
igAcceptMngMaxTranSize = igAcceptMngTranSize + iEventRecv;
accept_gMng = realloc(accept_gMng, sizeof(struct epoll_event) * igAcceptMngMaxTranSize);
if (accept_gMng == NULL)
{
pthread_mutex_unlock(&mute_gAcceptManager);
usleep(ACCEPT_PTHREAD_WAIT);
continue;
}
memset( accept_gMng + igAcceptMngTranSize, 0x00, sizeof(struct epoll_event) * iEventRecv );
}
memcpy( accept_gMng + igAcceptMngTranSize, &eventRecv, sizeof(struct epoll_event) * iEventRecv );
igAcceptMngTranSize += iEventRecv;
//激活业务线程,并释放accept-manager的锁
pthread_cond_signal(&condt_gAcceptManager);
pthread_mutex_unlock(&mute_gAcceptManager);
//初始化
memset( &eventRecv, 0x00, sizeof(eventRecv) );
iEventRecv = 0;
break;
}
}
}
else
if(saEvents[iNumTmp].events & EPOLLOUT)
{
//将事件添加到临时变量
memcpy( &(eventSend[iEventSend]), saEvents+iNumTmp, sizeof(struct epoll_event) );
iEventSend++;
igTotalSendEvent++;
//如果缓冲区慢了,将所有数据添加到 accept-manager 交互区
if (iEventSend == EACH_SEND_EVENTS)
{
//添加到数据交互区
while (1)
{
//加锁
pthread_mutex_lock(&mute_gAcceptSend);
if (igAcceptSndTranSize + iEventSend > igAcceptSndMaxTranSize)//如果数量超了,重新分配缓冲区
{
igAcceptSndMaxTranSize = igAcceptSndTranSize + iEventSend;
accept_gSnd = realloc(accept_gSnd, sizeof(struct epoll_event) * igAcceptSndMaxTranSize);
if (accept_gSnd == NULL)
{
pthread_mutex_unlock(&mute_gAcceptSend);
usleep(ACCEPT_PTHREAD_WAIT);
continue;
}
memset( accept_gSnd + igAcceptSndTranSize, 0x00, sizeof(struct epoll_event) * iEventSend );
}
memcpy( accept_gSnd + igAcceptSndTranSize, &eventSend, sizeof(struct epoll_event) * iEventSend );
igAcceptSndTranSize += iEventSend;
//激活业务线程,并释放accept-send的锁
pthread_cond_signal(&condt_gAcceptSend);
pthread_mutex_unlock(&mute_gAcceptSend);
//初始化
memset( &eventSend, 0x00, sizeof(eventSend) );
iEventSend = 0;
break;
}
}
}
else
{
//fprintf( stdout, "something else happened \n");fflush(stdout);
delEvent( iSocket, eds_data );
close(iSocket);
}
}
//fprintf( stdout, "[%s][%d]iEventRecv[%d]iEventSend[%d]\n", __FUNCTION__, __LINE__, iEventRecv, iEventSend );fflush(stdout);
//将剩余的缓冲区数据加入到accept-manager交互区
if (iEventRecv > 0)
{
//fprintf( stdout, "[%s][%d]获取accept-manager锁\n", __FUNCTION__, __LINE__ );fflush(stdout);
//添加到数据交互区
while (1)
{
//加锁
pthread_mutex_lock(&mute_gAcceptManager);
if (igAcceptMngTranSize + iEventRecv > igAcceptMngMaxTranSize)//如果数量超了,重新分配缓冲区
{
igAcceptMngMaxTranSize = igAcceptMngTranSize + iEventRecv;
accept_gMng = realloc(accept_gMng, sizeof(struct epoll_event) * igAcceptMngMaxTranSize);
if (accept_gMng == NULL)
{
pthread_mutex_unlock(&mute_gAcceptManager);
usleep(ACCEPT_PTHREAD_WAIT);
continue;
}
memset( accept_gMng + igAcceptMngTranSize, 0x00, sizeof(struct epoll_event) * iEventRecv );
}
memcpy( accept_gMng + igAcceptMngTranSize, &eventRecv, sizeof(struct epoll_event) * iEventRecv );
igAcceptMngTranSize += iEventRecv;
//激活业务线程,并释放accept-manager的锁
pthread_cond_signal(&condt_gAcceptManager);
pthread_mutex_unlock(&mute_gAcceptManager);
//fprintf( stdout, "[%s][%d]添加数据到accept-manager交互区完成\n", __FUNCTION__, __LINE__ );fflush(stdout);
break;
}
}
//将剩余的缓冲区数据加入到accept-send交互区
if (iEventSend > 0)
{
//fprintf( stdout, "[%s][%d]获取accept-send锁\n", __FUNCTION__, __LINE__ );fflush(stdout);
while (1)
{
//加锁
pthread_mutex_lock(&mute_gAcceptSend);
if (igAcceptSndTranSize + iEventSend > igAcceptSndMaxTranSize)//如果数量超了,重新分配缓冲区
{
igAcceptSndMaxTranSize = igAcceptSndTranSize + iEventSend;
accept_gSnd = realloc(accept_gSnd, sizeof(struct epoll_event) * igAcceptSndMaxTranSize);
if (accept_gSnd == NULL)
{
pthread_mutex_unlock(&mute_gAcceptSend);
usleep(ACCEPT_PTHREAD_WAIT);
continue;
}
memset( accept_gSnd + igAcceptSndTranSize, 0x00, sizeof(struct epoll_event) * iEventSend );
}
memcpy( accept_gSnd + igAcceptSndTranSize, &eventSend, sizeof(struct epoll_event) * iEventSend );
igAcceptSndTranSize += iEventSend;
//激活业务线程,并释放accept-send的锁
pthread_cond_signal(&condt_gAcceptSend);
pthread_mutex_unlock(&mute_gAcceptSend);
//fprintf( stdout, "[%s][%d]添加数据到accept-send交互区完成\n", __FUNCTION__, __LINE__ );fflush(stdout);
break;
}
}
//fprintf( stdout, "[%s][%d]total recv event[%d] send event[%d]\n", __FUNCTION__, __LINE__, igTotalRecvEvent, igTotalSendEvent );fflush(stdout);
return 0;
}
/**********************************************************************
函数名称: recvClientData
函数功能: 自定义接收客户端数据函数
参 数:
第 一:(I) accept fd
第 二:(O) 接收到的数据地址
第 三:(O) 接收到的数据长度
返 回:0表示成功
**********************************************************************/
int recvClientData(int iAcceptFd, char **pcaDataOut, int *iaDataOutLen)
{
char *pcData;
char pcBuf[MAX_BUF] = {0};
int iRecvLen;
iRecvLen = recv(iAcceptFd, pcBuf, sizeof(pcBuf) - 1, 0);
if(iRecvLen < 0)//recv error
{
if((errno == EAGAIN) || (errno == EWOULDBLOCK))
{
//fprintf( stdout, "read later\n" );fflush(stdout);
return 0;
}
return -1;
}
if (iRecvLen == 0)//连接关闭
{
return -1;
}
//fprintf( stdout, "recvlen[%d][%s]\n", iRecvLen, pcBuf );
igRecvSize++;
//fprintf( stdout, "recv total[%d]\n", igRecvSize );fflush(stdout);
pcData = malloc( iRecvLen + 1 );//在bussWorker中的调用dealBussData();后释放
if (pcData == NULL)
{
//fprintf( stderr, "get ram [%d] error\n", iRecvLen + 1 );fflush(stderr);
return -1;
}
memset( pcData, 0x00, iRecvLen + 1 );
memcpy( pcData, pcBuf, iRecvLen );
*pcaDataOut = pcData;
*iaDataOutLen = iRecvLen;
return 0;
}
/**********************************************************************
函数名称: dealBussData
函数功能: 自定义处理客户端数据函数
参 数:
第 一:(I) 输入数据
第 二:(I) 输入数据长度
第 三:(O) 输出数据
第 四:(O) 输出数据长度
返 回:0表示成功
**********************************************************************/
int dealBussData(char *pcaDataIn, int iDataInLen, char **pcaDataOut, int *iaDataOutLen)
{
#define DATA_LEN 12
#define RET_MSG "12345"
char *pcData;
pcData = malloc( DATA_LEN + 1 );//在sendWorker调用send后释放
if (pcData == NULL)
{
fprintf( stderr, "get ram [%lu] error\n", sizeof(RET_MSG) );fflush(stderr);
return -1;
}
memset( pcData, 0x00, DATA_LEN + 1 );
sprintf( pcData, "%0*d", DATA_LEN, igRecvSize );
*pcaDataOut = pcData;
*iaDataOutLen = strlen(pcData);
return 0;
}
/**********************************************************************
函数名称: tcpServer
函数功能: 创建SOCKET
参 数:
第 一:端口 I
**********************************************************************/
int tcpServer( int iaPort )
{
struct sockaddr_in server; /*服务器地址信息结构体*/
int iOpt;
int iSocket;
fprintf( stdout, "start create socket\n" );fflush(stdout);
/*建立socket*/
iSocket = socket(AF_INET, SOCK_STREAM, 0);
if (iSocket == -1)
{
fprintf( stderr, "create socket error[%d][%s]\n", errno, strerror(errno) ); fflush(stderr);
return ERROR;
}
/*设置socket属性*/
iOpt = SO_REUSEADDR;
setsockopt(iSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&iOpt, sizeof(iOpt));
memset(&server, 0x00, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(iaPort);
server.sin_addr.s_addr = htonl(INADDR_ANY);
/*调用bind绑定地址*/
if (bind(iSocket, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1)
{
fprintf( stderr, "bind socket error[%d][%s]", errno, strerror(errno) );fflush(stderr);
return ERROR;
}
/*调用listen开始监听*/
if (listen(iSocket, MAX_LINKS) == -1)
{
fprintf( stderr, "listen socket error[%d][%s]\n", errno, strerror(errno) );fflush(stderr);
return ERROR;
}
fprintf( stdout, "create socket success\n" );fflush(stdout);
return iSocket;
}
/**********************************************************************
函数名称: addEventAccept
函数功能: 将侦听SOCKET添加到事件列表
参 数:
第 一:(I)socket
第 二:(I) epoll data
返 回: 0表示成功
**********************************************************************/
int addEventAccept(int iaListenFd, struct epollDataStruct *saeds)
{
struct epoll_event sEpollEvent;
//sEpollEvent.data.fd = iaListenFd;
sEpollEvent.data.ptr = (void *)saeds;
sEpollEvent.events = EPOLLIN;
epoll_ctl(saeds->iEpollFd, EPOLL_CTL_ADD, iaListenFd, &sEpollEvent);
return 0;
}
/**********************************************************************
函数名称: addEventIn
函数功能: 将侦听 accept fd 添加到事件列表
参 数:
第 一:(I)accept fd
第 二:(I)epoll data
返 回: 0表示成功
**********************************************************************/
int addEventIn(int iaAcceptFd, struct epollDataStruct *saeds)
{
struct epoll_event sEpollEvent;
//sEpollEvent.data.fd = iaAcceptFd;
sEpollEvent.data.ptr = (void *)saeds;
sEpollEvent.events = EPOLLIN | EPOLLET;
epoll_ctl(saeds->iEpollFd, EPOLL_CTL_ADD, iaAcceptFd, &sEpollEvent);
return setnonblocking(iaAcceptFd);//设置非阻塞模式
}
/**********************************************************************
函数名称: alterEventOut
函数功能: 修改 recv fd 为输出事件
参 数:
第 一:(I)epoll fd
第 二:(I)epoll data
返 回: 0表示成功
**********************************************************************/
int alterEventOut(int iaRecvFd, struct epollDataStruct *saeds)
{
struct epoll_event sEpollEvent;
//sEpollEvent.data.fd = iaRecvFd;
sEpollEvent.data.ptr = (void *)saeds;
sEpollEvent.events = EPOLLIN | EPOLLOUT | EPOLLET;
epoll_ctl(saeds->iEpollFd, EPOLL_CTL_MOD, iaRecvFd, &sEpollEvent);
igTotalEventOut++;
//fprintf( stdout, "[%s][%d]igTotalEventOut[%d]\n", __FUNCTION__, __LINE__, igTotalEventOut );fflush(stdout);
return 0;
}
/**********************************************************************
函数名称: delEvent
函数功能: 删除 send fd 事件
参 数:
第 一:(I)send fd
返 回: 0表示成功
**********************************************************************/
int delEvent(int iaSendFd, struct epollDataStruct *saeds)
{
struct epoll_event sEpollEvent;
//sEpollEvent.data.ptr = saeds;
sEpollEvent.events = EPOLLIN | EPOLLET;
epoll_ctl(saeds->iEpollFd, EPOLL_CTL_DEL, iaSendFd, &sEpollEvent);
return 0;
}
/**********************************************************************
函数名称: setnonblocking
函数功能: 将文件描述符设置为非阻塞的
参 数:
第 一:(I)accept fd
返 回: 0表示成功
**********************************************************************/
int setnonblocking(int fd)
{
int iOldOpt;
int iNewOpt;
iOldOpt = fcntl(fd, F_GETFD);
if (iOldOpt < 0)//可能是客户端已关闭造成的
{
//fprintf( stderr, "fcntl F_GETFD error[%d][%s]\n", errno, strerror(errno) );fflush(stderr);
return -1;
}
iNewOpt = iOldOpt | O_NONBLOCK;
if (fcntl(fd, F_SETFD, iNewOpt) < 0)//可能是客户端已关闭造成的
{
//fprintf( stderr, "fcntl F_SETFD error[%d][%s]\n", errno, strerror(errno) );fflush(stderr);
return -1;
}
return 0;
}
/**********************************************************************
函数名称: createEpollData
函数功能: 新建 epoll data 结构
参 数:
第 一:(I)数据
第 二:(I)数据长度
第 三:(I)SOCKET
第 四:(I)epoll fd
返 回: 地址,空表示错误
**********************************************************************/
struct epollDataStruct *createEpollData( char *pcData, int iDataLen, int iSocket, int iaEpollFd )
{
struct epollDataStruct *eds_data;
eds_data = malloc( sizeof(struct epollDataStruct) );//在sendWorker中释放
if (eds_data == NULL)
{
//fprintf( stderr, "get ram [%lu] error\n", sizeof(struct epollDataStruct) );fflush(stderr);
return NULL;
}
memset( eds_data, 0x00, sizeof(struct epollDataStruct) );
eds_data->pcData = pcData;
eds_data->iDataLen = iDataLen;
eds_data->fd = iSocket;
eds_data->iEpollFd = iaEpollFd;
return eds_data;
}