服务端:
#include <stdio.h>
#include <sys/epoll.h>
#include <queue>
#include <iostream>
#include <semaphore.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
using namespace std;
#define THREAD_NUM 80
#define LISTEN_MAX 100
#define EPOLL_CREATE_FDS 100000
#define EPOLL_WAIT_EVENTS 100
#define WORK_THREADS_MAX 20
sem_t g_sem;
int g_epfd;
int g_conncount = 0;
struct myepoll_buf
{
int iTime;
char szBuf[100];
};
struct myepoll_data
{
int fd;
struct myepoll_buf *pbuf;
};
queue<struct epoll_event *> g_TaskQueue;
pthread_mutex_t g_mutex;
pthread_t pthreadID[WORK_THREADS_MAX];
void * workfunc(void *arg)
{
int listenfd = (int)arg;
struct epoll_event *pev, ev;
int ilen;
socklen_t client_len;
struct sockaddr_in clientaddr;
int connfd;
int old;
char szData[100], szTime[2] = {0};
int iTime;
struct myepoll_data *pData;
while (1)
{
sem_wait(&g_sem);
pthread_mutex_lock(&g_mutex);
pev = g_TaskQueue.front();
g_TaskQueue.pop();
pthread_mutex_unlock(&g_mutex);
if (pev->data.fd == listenfd) //连接请求
{
while ((connfd = accept(listenfd, (struct sockaddr *)&clientaddr, &client_len)) > 0)
{
printf("总连接数:%d\n", ++g_conncount);
old = fcntl(connfd, F_GETFL);
old = old | O_NONBLOCK;
fcntl(connfd, F_SETFL, old);
printf("接收了来自[%s:%d]的请求\n",inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));
struct myepoll_data *pData = (struct myepoll_data *)malloc(sizeof(struct myepoll_data));
pData->fd = connfd;
pData->pbuf = NULL;
ev.data.ptr = pData;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
epoll_ctl(g_epfd, EPOLL_CTL_ADD, connfd, &ev);
}
}
else if (pev->events & EPOLLIN) //读
{
pData = (struct myepoll_data *)pev->data.ptr;
if (pData == NULL)
continue;
memset(szData, 0, sizeof (szData));
ilen = read(pData->fd, szData, 100);
if (ilen <= 0) //连接断开
{
printf("连接断开\n");
if (pData->pbuf)
free(pData->pbuf);
pData->pbuf = NULL;
epoll_ctl(g_epfd, EPOLL_CTL_DEL, pData->fd, NULL);
close(pData->fd);
free(pData);
pData = NULL;
continue;
}
printf("接收到客户端发送的数据:%s\n", szData);
memcpy(szTime, szData, 1);
szTime[1] = '\0';
iTime = atoi(szTime);
if (!pData->pbuf)
{
pData->pbuf = (struct myepoll_buf *)malloc(sizeof (struct myepoll_buf));
if (pData->pbuf == NULL)
{
printf("out of memory!\n");
continue;
}
}
pData->pbuf->iTime = iTime;
sprintf(pData->pbuf->szBuf, "(%s)请求完成,耗时%d", szData, iTime);
ev.events = EPOLLOUT | EPOLLET | EPOLLRDHUP;
ev.data.ptr = pData;
epoll_ctl(g_epfd, EPOLL_CTL_MOD, pData->fd, &ev);
}
else if (pev->events & EPOLLOUT) //写
{
pData = (struct myepoll_data *)pev->data.ptr;
if (pData == NULL)
continue;
if (pData->pbuf)
{
//sleep(pData->pbuf->iTime);
}
else
{
epoll_ctl(g_epfd, EPOLL_CTL_DEL, pData->fd, NULL);
close(pData->fd);
free(pData);
continue;
}
write(pData->fd, pData->pbuf->szBuf, strlen(pData->pbuf->szBuf) + 1);
printf("请求处理完成,发送结果:%s\n", pData->pbuf->szBuf);
free(pData->pbuf);
pData->pbuf = NULL;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
ev.data.ptr = pData;
epoll_ctl(g_epfd, EPOLL_CTL_MOD, pData->fd, &ev);
}
else if (pev->events & EPOLLRDHUP) //连接关闭
{
pData = (struct myepoll_data *)pev->data.ptr;
if (pData != NULL)
{
printf("关闭连接,socket:%d\n", pData->fd);
epoll_ctl(g_epfd, EPOLL_CTL_DEL, pData->fd, NULL);
close(pData->fd);
if (pData->pbuf)
free(pData->pbuf);
pData->pbuf = NULL;
free(pData);
pData = NULL;
}
}
}
}
int main(int argc, char **argv)
{
int iPort = 8888;
char szIp[20] = "127.0.0.1";
if (2 == argc)
{
if ((iPort = atoi(argv[1])) < 0)
{
fprintf(stderr, "端口[%s]不正确!\n", argv[1]);
return 1;
}
}
else if (3 == argc)
{
if ((iPort = atoi(argv[1])) < 0)
{
fprintf(stderr, "端口[%s]不正确!\n", argv[1]);
return 1;
}
sprintf(szIp, "%s", argv[2]);
}
int listenfd, i;
struct sockaddr_in serveraddr;
struct epoll_event ev;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
int old = fcntl(listenfd, F_GETFL);
old = old | O_NONBLOCK;
fcntl(listenfd, F_SETFL, old);
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(szIp);
serveraddr.sin_port = htons(iPort);
if (-1 == bind(listenfd, (struct sockaddr *)&serveraddr, sizeof (serveraddr)))
{
printf("bind()失败!IP:%s, port:%d\n", szIp, iPort);
return 1;
}
else
printf("绑定成功,socket:%d\n", listenfd);
if (-1 == listen(listenfd, LISTEN_MAX))
{
printf("listen()失败!");
return 1;
}
else
printf("监听成功,socket:%d\n", listenfd);
if (sem_init(&g_sem, 0, 0) < 0)
{
printf("sem_init()失败!\n");
return 1;
}
if (pthread_mutex_init(&g_mutex, NULL) < 0)
{
printf("pthread_mutex_init()失败!\n");
return 1;
}
for (i = 0; i < WORK_THREADS_MAX; ++i)
pthread_create(pthreadID + i, NULL, workfunc, (void *)listenfd);
struct epoll_event events[EPOLL_WAIT_EVENTS];
g_epfd = epoll_create(EPOLL_CREATE_FDS);
ev.data.fd = listenfd;
ev.events = EPOLLIN | EPOLLET;
epoll_ctl(g_epfd, EPOLL_CTL_ADD, listenfd, &ev);
while (1)
{
int iFds = epoll_wait(g_epfd, events, EPOLL_WAIT_EVENTS, -1);
if (iFds < 0)
break;
for (i = 0; i < iFds; ++i)
{
struct epoll_event *pev = (struct epoll_event *)malloc(sizeof (struct epoll_event));
memcpy(pev, &events[i], sizeof (struct epoll_event));
pthread_mutex_lock(&g_mutex);
g_TaskQueue.push(pev);
pthread_mutex_unlock(&g_mutex);
sem_post(&g_sem);
}
}
for (i = 0; i < WORK_THREADS_MAX; ++i)
pthread_join(pthreadID[i], NULL);
pthread_mutex_destroy(&g_mutex);
sem_destroy(&g_sem);
close(g_epfd);
return 0;
}
测试客户端:
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8888
int Random(int start, int end)
{
srand(time(NULL));
int dis = end - start;
return rand() % dis + start;
}
void * workfunc(void *arg)
{
int iTime;
char szBuf[100];
int iReq = (int)arg;
int iret = 0;
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(SERVER_IP);
serveraddr.sin_port = htons(SERVER_PORT);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
while (connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
{
printf("连接服务器失败,稍后重试!Err:%d\n", errno);
sleep(1);
}
for (int i = 0; i < iReq; ++i)
{
sprintf(szBuf, "%d线程[%u]发送第%d次请求", Random(0, 10), pthread_self(), i);
printf("%s\n", szBuf);
iret = write(sockfd, szBuf, strlen(szBuf) + 1);
printf("发送数据长度:%d\n", iret);
memset(szBuf, 0, 100);
read(sockfd, szBuf, 100);
printf("接收返回结果:%s\n", szBuf);
}
printf("线程[%u]请求结束,关闭socket[%d]\n", pthread_self(), sockfd);
close(sockfd);
}
int main(int argc, char **argv)
{
if (argc <3)
{
printf("请提供两个参数,例如:程序 线程数 请求数\n");
return 1;
}
int iThreads = atoi(argv[1]);
int iReq = atoi(argv[2]);
int i;
int ifailed = 0;
pthread_t *pThreadID = (pthread_t *)malloc(iThreads * sizeof(pthread_t));
memset(pThreadID, 0, sizeof (pthread_t) * iThreads);
for (i = 0; i < iThreads; i++)
{
if (0 != pthread_create(pThreadID + i, NULL, workfunc, (void *)iReq))
{
printf("创建线程失败!Err:%d\n", errno);
++ifailed;
}
}
for (i = 0; i < iThreads; ++i)
{
if (pThreadID[i] == 0)
continue;
pthread_join(*(pThreadID + i), NULL);
}
printf("创建线程失败数:%d\n", ifailed);
free(pThreadID);
return 0;
}