免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5279 | 回复: 15
打印 上一主题 下一主题

[C++] 用epoll时,经常在收到连接的消息后半天才能收到接受数据的消息,请问是为什么,谢谢了. [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-05-30 16:29 |只看该作者 |倒序浏览
本帖最后由 hegu 于 2011-05-31 11:53 编辑

我的代码就是一个简单的http server,对任何请求都是返回200 OK。
我的测试方法就是用curl一个url。

这个是我的一个log,可以看到经常收到连接后,9秒才收到数据,感觉应该不是网络原因,
因为我curl服务器的nginx的一个文件,响应就很快。

current_conn=441 123.125.117.250-242 r-c=3 r=0 w-r=0 w=0 spend=3
Mon May 30 16:24:41 2011 connect
Mon May 30 16:24:41 2011 rec 403
Mon May 30 16:24:41 2011 writed 89
current_conn=1866 123.125.117.250-39618 r-c=0 r=0 w-r=0 w=0 spend=0
Mon May 30 16:24:42 2011 connect
Mon May 30 16:24:42 2011 rec 403
Mon May 30 16:24:42 2011 writed 89
current_conn=1782 123.125.117.250-228 r-c=0 r=0 w-r=0 w=0 spend=0
Mon May 30 16:24:43 2011 connect
Mon May 30 16:24:43 2011 rec 403
Mon May 30 16:24:43 2011 writed 89
current_conn=1820 123.125.117.250-2331 r-c=0 r=0 w-r=0 w=0 spend=0
Mon May 30 16:24:44 2011 connect
Mon May 30 16:24:47 2011 rec 403
Mon May 30 16:24:47 2011 writed 89
current_conn=1879 123.125.117.250-14107 r-c=3 r=0 w-r=0 w=0 spend=3
Mon May 30 16:25:08 2011 connect
Mon May 30 16:25:17 2011 rec 403
Mon May 30 16:25:17 2011 writed 89
current_conn=1842 123.125.117.250-22503 r-c=9 r=0 w-r=0 w=0 spend=9


下面是我的代码:

#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <sstream>

using namespace std;

#define LISTENQ 20000
#define SERV_PORT 9889
#define HTTP_END "\r\n\r\n"
//#define HTTP_END "abcd"
#define HTTP_200_OK "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nCache-Control: no-cache\r\nContent-Length: 0\r\n\r\n"
//#define HTTP_200_OK "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nCache-Control: no-cache\r\nContent-Length: "
#define TEST_IP "123.125.117.250"

int CreateWorker(int nWorker)
{
        if (0 < nWorker)
        {
                bool bIsChild = false;
                pid_t nPid;

                while (!bIsChild)
                {
                        if (0 < nWorker)
                        {
                                nPid = ::fork();
                                if (nPid > 0)
                                {
                                        bIsChild = false;
                                        --nWorker;
                                }
                                else if (0 == nPid)
                                {
                                        bIsChild = true;
                                        printf("create worker %d success!\n", ::getpid());
                                }
                                else
                                {
                                        printf("fork error: %s\n", ::strerror(errno));
                                        return -1;
                                }
                        }
                        else
                        {
                                int nStatus;
                               
                                if (-1 == ::wait(&nStatus))
                                {
                                       
                                }

                                printf("wait status=%d\n", nStatus);

                                ++nWorker;
                        }
                }
        }

        return 0;
}

void setnonblocking(int sock)
{
        int opts;
        opts=fcntl(sock,F_GETFL);
        if(opts<0)
        {
                perror("fcntl(sock,GETFL)");
                exit(1);
        }
        opts = opts|O_NONBLOCK;
        if(fcntl(sock,F_SETFL,opts)<0)
        {
                perror("fcntl(sock,SETFL,opts)");
                exit(1);
        }   
}

class http_task
{
public:
        int fd;
        struct sockaddr_in remoteAddr;
        char recv_buffer[1024];
        int  recved;
        int Writed;

        static int current_connect;
        string strInfoHash;
        unsigned int connect_time;
        unsigned int read_begin_time;
        unsigned int read_end_time;
        unsigned int write_begin_time;
        unsigned int write_end_time;

        http_task():fd(0),Writed(0),read_begin_time(0),read_end_time(0),write_begin_time(0),write_end_time(0),recved(0)
        {
                current_connect++;
                connect_time = time(NULL);
        };

        ~http_task()
        {
                current_connect--;
        };
};

int http_task::current_connect = 0;


void delete_http_task(int epfd,http_task* ptask)
{
        int sockfd = ptask->fd;

        if (strcmp(inet_ntoa(ptask->remoteAddr.sin_addr),TEST_IP) == 0)
        {       
                time_t tNow = time( NULL );
                //        char *szTime = asctime( localtime( &tNow ) );
                //        szTime[strlen( szTime ) - 1] = '\0';

                ptask->write_end_time = time(NULL);
                int spend = time(NULL)-ptask->connect_time;
                stringstream ss;
                ss << "current_conn="<<ptask->current_connect << " "
                        << inet_ntoa(ptask->remoteAddr.sin_addr) << "-" << ptask->remoteAddr.sin_port << " "
                        << "r-c=" << ptask->read_begin_time-ptask->connect_time << " "
                        << "r=" << ptask->read_end_time-ptask->read_begin_time << " "
                        << "w-r=" <<  ptask->write_begin_time-ptask->read_end_time << " "
                         << "w=" << ptask->write_end_time-ptask->write_begin_time << " "
                         << "spend=" << spend;

                std::cout << ss.str() << endl;
        }
       
        delete ptask;

        epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,NULL);
        close(sockfd);
};

int main()
{
        int i, listenfd, connfd, sockfd,epfd,nfds;
        ssize_t n;
        socklen_t clilen;
        const int MAX_EVENT = 20;
        struct epoll_event ev,events[MAX_EVENT];

        struct sockaddr_in clientaddr;
        struct sockaddr_in serveraddr;
        listenfd = socket(AF_INET, SOCK_STREAM, 0);
        bzero(&serveraddr, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = INADDR_ANY;

        serveraddr.sin_port=htons(SERV_PORT);
        int nOptVal = 1;
        socklen_t nOptLen = sizeof(int);
        if (-1 == ::setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &nOptVal, nOptLen))
        {
                return -1;
        }   
        setnonblocking(listenfd);
        bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));
        listen(listenfd, LISTENQ);   

        CreateWorker(5);

        epfd = epoll_create(25600);   
        ev.data.fd=listenfd;
        ev.events=EPOLLIN|EPOLLET;
        //ev.events=EPOLLIN;
        epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);

        struct sockaddr_in  remoteAddr;
        socklen_t remoteAddrLen = sizeof(remoteAddr);

        http_task *ptask;
        while(true)
        {
                nfds=epoll_wait(epfd,events,MAX_EVENT,-1);
                for(i=0;i<nfds;++i)
                {
                        if(events.data.fd==listenfd && (events.events&EPOLLIN))
                        {         
                                        while(1)
                                        {
                                                connfd = accept(listenfd, (struct sockaddr*)&remoteAddr, &remoteAddrLen);
                                                if(connfd == -1)
                                                {
                                                        if(errno == EWOULDBLOCK || errno == EAGAIN)
                                                        {
                                                                //printf("none connections\n");
                                                                break;
                                                        }
                                                        perror("accept error");
                                                        return -1;
                                                }
                                                //printf("%d: %s coming\n",getpid(),inet_ntoa(remoteAddr.sin_addr));

                                                setnonblocking(connfd);

                                                ptask = new http_task;
                                                ptask->fd = connfd;
                                                ptask->remoteAddr = remoteAddr;
                                                ev.data.ptr = ptask;
                                                ev.events=EPOLLIN|EPOLLET;
                                                //ev.events=EPOLLIN;
                                                epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);

                                                if (strcmp(inet_ntoa(ptask->remoteAddr.sin_addr),TEST_IP) == 0)
                                                {
                                                        time_t tNow = time( NULL );
                                                        char *szTime = asctime( localtime( &tNow ) );
                                                        szTime[strlen( szTime ) - 1] = '\0';
                                                        std::cout<< szTime <<" connect "<<std::endl;
                                                }
                                        }

                        }
                        else if(events.events&EPOLLIN)
                        {
                                ptask = (http_task*)events.data.ptr;
                                sockfd = ptask->fd;
                                int nRecv;

                                if (ptask->read_begin_time == 0)
                                {
                                        ptask->read_begin_time = time(NULL);
                                }

                                //do
                                //{
                                        nRecv = read(sockfd, ptask->recv_buffer+ptask->recved, 1024-ptask->recved);

                                        if (strcmp(inet_ntoa(ptask->remoteAddr.sin_addr),TEST_IP) == 0)
                                        {
                                                time_t tNow = time( NULL );
                                                char *szTime = asctime( localtime( &tNow ) );
                                                szTime[strlen( szTime ) - 1] = '\0';
                                                std::cout<< szTime <<" rec " <<  nRecv <<std::endl;
                                        }
                                //}while(nRecv == 1024);

                                if (nRecv < 0)
                                {
                                        if (errno == ECONNRESET)
                                        {

                                        }
                                        else
                                        {
                                                std::cout<<"readline error"<<std::endl;
                                        }

                                        delete ptask;
                                        epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,&ev);
                                        close(sockfd);
                                }
                                else
                                {
                                        ptask->recved += nRecv;
                       
                                        if (ptask->recved > 4 && memcmp(&ptask->recv_buffer[ptask->recved-4],HTTP_END,4) == 0)
                                        {
                                                ptask->read_end_time = time(NULL);
                                               
                                                ev.data.ptr = ptask;
            ev.events=EPOLLOUT|EPOLLET;
                        
            epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
                                        }
                                        else
                                        {
                                                std::cout << "not end" << std::endl;
                                        }
                                }
                        }
                        else if(events.events&EPOLLOUT)
                        {   
                                ptask = (http_task*)events.data.ptr;
                                sockfd = ptask->fd;

                                if (ptask->write_begin_time == 0)
                                {
                                        ptask->write_begin_time = time(NULL);
                                }
                               
                                static char* pSend = HTTP_200_OK;
                                int writed = write(sockfd, pSend+ptask->Writed, sizeof(HTTP_200_OK)-1-ptask->Writed);
                                if (strcmp(inet_ntoa(ptask->remoteAddr.sin_addr),"123.125.117.250") == 0)
                                {
                                        time_t tNow = time( NULL );
                                        char *szTime = asctime( localtime( &tNow ) );
                                        szTime[strlen( szTime ) - 1] = '\0';
                                        std::cout<< szTime <<" writed " << writed <<std::endl;
                                }

                                if (writed <= 0)
                                {
                                        if(errno == EAGAIN)
                                        {
                                                cout << getpid() <<":write EAGAIN" << endl;

                                                ev.data.ptr = ptask;
                                                ev.events=EPOLLOUT|EPOLLET;

                                                epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
                                        }
                                        else
                                        {
                                                delete_http_task(epfd,(http_task*)events.data.ptr);
                                                cout << getpid() <<":write error=" << errno << endl;
                                        }
                                }
                                else
                                {
                                        ptask->Writed += writed;
                                        if (ptask->Writed >= sizeof(HTTP_200_OK)-1)
                                        {
                                                delete_http_task(epfd,(http_task*)events.data.ptr);
                                        }
                                        else
                                        {
                                                cout << "need write again..." << endl;
                                        }
                                }
                        }
                        else if(events.events & (EPOLLHUP|EPOLLERR))
                        {
                                cout << getpid() <<":EPOLLHUP|EPOLLERR" << endl;

                                delete_http_task(epfd,(http_task*)events.data.ptr);
                        }
                }
        }
        return 0;
}

论坛徽章:
0
2 [报告]
发表于 2011-05-30 17:05 |只看该作者
有人知道吗?

自己顶一下。

谢谢了。

论坛徽章:
0
3 [报告]
发表于 2011-05-30 17:32 |只看该作者
而且发现,时间不是3秒,就是9秒。

论坛徽章:
0
4 [报告]
发表于 2011-05-30 17:33 |只看该作者
你的多线程模型有问题吧
你创建了6个进程,每个进程创建一个epoll 最大连接数25600。
6个进程监听同一个端口(假设上面都成功了)。
当有新链接过来的时候每个进程生成一个新socket?
每个进程处理一次这个socket?

其实你用epoll io复用应该就足够满足你的性能需求了,没有必要多进程,多线程的。
而且你的epoll最大连接数也太大啦。
一般的服务器总链接数也就3w。

论坛徽章:
0
5 [报告]
发表于 2011-05-30 17:39 |只看该作者
回复 4# congwu0505_sky


    多进程好像不是关键问题,我把注释调多进程的,//CreateWorker(5);
   就一个进程也发现慢,而且有时还是慢45秒,比较奇怪的是慢的数字都是3的倍数。

论坛徽章:
0
6 [报告]
发表于 2011-05-30 17:42 |只看该作者
你的多线程模型有问题吧
你创建了6个进程,每个进程创建一个epoll 最大连接数25600。
6个进程监听同一个端 ...
congwu0505_sky 发表于 2011-05-30 17:33



    这个连接数好像也不是问题所在,我本来是256的,后来怕是这个太小导致的问题,所以就填了两个0试试,结果发现还是不行。

论坛徽章:
0
7 [报告]
发表于 2011-05-30 17:44 |只看该作者
gdb跟一下,如果你的服务器很快就处理完了,那就不是程序的问题啦。
或者说不是这个程序的问题了。

论坛徽章:
0
8 [报告]
发表于 2011-05-30 17:47 |只看该作者
这个连接数好像也不是问题所在,我本来是256的,后来怕是这个太小导致的问题,所以就填了两个0试 ...
hegu 发表于 2011-05-30 17:42



    这个值的意思应该是说 epoll_wait一次返回就绪的socket个数。
一般都很小,就算是比较忙碌的服务器这个值都不会超过500吧,我写的服务器一般这个值都设置成100.

论坛徽章:
0
9 [报告]
发表于 2011-05-30 17:47 |只看该作者
gdb跟一下,如果你的服务器很快就处理完了,那就不是程序的问题啦。
或者说不是这个程序的问题了。
congwu0505_sky 发表于 2011-05-30 17:44



    上面代码可以看到我程序没有做任何处理,就是直接返回200 OK的。

论坛徽章:
0
10 [报告]
发表于 2011-05-30 17:53 |只看该作者
你的问题是:
用epoll时,经常在收到连接的消息后半天才能收到接受数据的消息,请问是为什么,谢谢了.
-----前提是有数据过来epoll_wait才会返回。给你处理,否则epoll_wait会一直阻塞。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP