加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

多线程和epoll的结合运用示例

发布时间:2020-12-15 07:53:47 所属栏目:Java 来源:网络整理
导读://epoll通过将服务socket if (epoll_ctl(kdpfd,EPOLL_CTL_ADD,listener,ev) 0) 添加到epoll中 //然后listener监听链接请求,每次监听到一个新的链接就添加到epoll中 epoll_ctl //如果不是新的链接那么直接创建一个子线程进行业务的处理 #include stdio.h #in
//epoll通过将服务socket if (epoll_ctl(kdpfd,EPOLL_CTL_ADD,listener,&ev) < 0) 添加到epoll中
//然后listener监听链接请求,每次监听到一个新的链接就添加到epoll中 epoll_ctl
//如果不是新的链接那么直接创建一个子线程进行业务的处理

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <pthread.h>

#define MAXBUF 1024
#define MAXEPOLLSIZE 10000

void pthread_handle_message(void para);
/
setnonblocking - 设置句柄为非阻塞方式
/
int setnonblocking(int sockfd)
{
if (fcntl(sockfd,F_SETFL,fcntl(sockfd,F_GETFD,0)|O_NONBLOCK) == -1) {
return -1;
}
return 0;
}

static int count111 = 0;
static time_t oldtime = 0,nowtime = 0;

//------------------------------------------------------------
int main(int argc,char **argv)
{
int listener,new_fd,nfds,n,ret;
struct epoll_event ev;
int kdpfd,curfds;
socklen_t len;
struct sockaddr_in my_addr,their_addr;
unsigned int myport,lisnum;
struct epoll_event events[MAXEPOLLSIZE];
struct rlimit rt;

if (argc>1) 
    myport = atoi(argv[1]); 
else 
    myport = 8006;

if (argc>2) 
    lisnum = atoi(argv[2]); 
else 
    lisnum = 10;

/* 设置每个进程允许打开的最大文件数 */ 
rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE; 
if (setrlimit(RLIMIT_NOFILE,&rt) == -1) { 
    perror("setrlimit"); 
    exit(1); 
} 
else printf("设置系统资源参数成功!/n");

/* 开启 socket 监听 */ 
if ((listener = socket(PF_INET,SOCK_STREAM,0)) == -1) { 
    perror("socket"); 
    exit(1); 
} else 
    printf("socket 创建成功!/n");

/*设置socket属性,端口可以重用*/ 
int opt=SO_REUSEADDR; 
setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

/*设置socket为非阻塞模式*/ 
setnonblocking(listener);

bzero(&my_addr,sizeof(my_addr)); 
my_addr.sin_family = PF_INET; 
my_addr.sin_port = htons(myport); 
if (argc>3) 
    my_addr.sin_addr.s_addr = inet_addr(argv[3]); 
else 
    my_addr.sin_addr.s_addr = INADDR_ANY;

if (bind 
    (listener,(struct sockaddr *) &my_addr,sizeof(struct sockaddr)) 
    == -1) { 
        perror("bind"); 
        exit(1); 
} else 
    printf("IP 地址和端口绑定成功/n");

if (listen(listener,lisnum) == -1) { 
    perror("listen"); 
    exit(1); 
} else 
    printf("开启服务成功!/n");

/* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */ 
kdpfd = epoll_create(MAXEPOLLSIZE); 
len = sizeof(struct sockaddr_in); 
ev.events = EPOLLIN | EPOLLET; 
ev.data.fd = listener; 
if (epoll_ctl(kdpfd,&ev) < 0) { 
    fprintf(stderr,"epoll set insertion error: fd=%d/n",listener); 
    return -1; 
} else 
    printf("监听 socket 加入 epoll 成功!/n"); 
curfds = 1; 
while (1) 
{ 
    /* 等待有事件发生 */ 
    nfds = epoll_wait(kdpfd,events,curfds,-1); 
    if (nfds == -1) 
    { 
        perror("epoll_wait"); 
        continue; 
    } 
    /* 处理所有事件 */ 
    for (n = 0; n < nfds; ++n) 
    { 
        if (events[n].data.fd == listener) 
        { 
            new_fd = accept(listener,(struct sockaddr *) &their_addr,&len); 
            if (new_fd < 0) { 
                perror("accept"); 
                continue; 
            } else 
            {
                //printf("有连接来自于: %s:%d, 分配的 socket 为:%d/n",inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port),new_fd);

            }
            setnonblocking(new_fd); 
            ev.events = EPOLLIN | EPOLLET; 
            ev.data.fd = new_fd; 
            if (epoll_ctl(kdpfd,&ev) < 0) { 
                fprintf(stderr,"把 socket ‘%d‘ 加入 epoll 失败!%s/n",strerror(errno)); 
                return -1; 
            } 
            curfds++; 
        } 
        else 
        { 
            pthread_attr_t attr;
            pthread_t threadId;

            /*初始化属性值,均设为默认值*/ 
            pthread_attr_init(&attr); 
            pthread_attr_setscope(&attr,PTHREAD_SCOPE_SYSTEM); 
            /* 设置线程为分离属性*/ 
            pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
            if(pthread_create(&threadId,&attr,pthread_handle_message,(void*)&(events[n].data.fd)))
            { 
                perror("pthread_creat error!"); 
                exit(-1); 
            } 
        } 
    } 
} 
close(listener); 
return 0;

}

void pthread_handle_message(void para)
{
char recvBuf[1024] = {0};
int ret = 999;
int rs = 1;
int socketfd = (int )para;

while(rs)
{
    ret = recv(socketfd,recvBuf,1024,0);// 接受客户端消息

    if(ret < 0)
    {
        //由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可//读在这里就当作是该次事件已处理过。

        if(errno == EAGAIN)
        {
            printf("EAGAINn");
            break;
        }
        else{
            printf("recv error! errno:%dn",errno);

            close(socketfd);
            break;
        }
    }
    else if(ret == 0)
    {
        // 这里表示对端的socket已正常关闭. 
        rs = 0;
    }
    if(ret == sizeof(recvBuf))
        rs = 1; // 需要再次读取
    else
        rs = 0;
}

if(ret>0){
    count111 ++;
    struct tm *today;
    time_t ltime;
    time( &nowtime );

    if(nowtime != oldtime){
        printf("%dn",count111);
        oldtime = nowtime;
        count111 = 0;
    }

    char buf[1000] = {0};
    sprintf(buf,"HTTP/1.0 200 OKrnContent-type: text/plainrnrn%s","Hello world!n");
    send(socketfd,buf,strlen(buf),0);
}
close(socketfd);

}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读