免费注册 查看新帖 |

Chinaunix

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

[C] epoll模型, socket设置了keepalive,但为什么时间到了,没能关闭连接呢 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-11-01 14:22 |只看该作者 |倒序浏览
本帖最后由 hsdrhsdr 于 2013-11-01 14:36 编辑

使用epoll了模型,socket设置了keepalive,但为什么时间到了,没能捕获到关闭连接呢,代码如下:
//
//  Server.c
//  carsoulCloudDogServer
//
//  Created by Leo.Chen on 13-8-5.
//  Copyright (c) 2013年 carsoul. All rights reserved.
//

#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <fcntl.h>
#include "Server.h"

#define MAX_EVENTS        640

static int listen_sock                                =        0;
static unsigned long int times                =        0;
static Server_event_handle *serverCfg        =        NULL;

//创建并绑定端口
int create_and_bind(int port)
{
   
    int listenfd;
    struct sockaddr_in local;
   
    //创建listen socket
    if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("create sockfd error");
        return -1;
    }
   
        memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_addr.s_addr = htonl(INADDR_ANY);;
    local.sin_port = htons(port);
   
    if (bind(listenfd, (struct sockaddr *) &local, sizeof(local)) < 0) {
        perror("Could not bind:");
        return -1;
    }
   
    return listenfd;
}

//设置socket为非阻塞
int setnonblocking(int sockfd)
{
        int opts;
   
    opts = fcntl(sockfd, F_GETFL);
    if(opts < 0) {
        perror("fcntl(F_GETFL)\n");
        return -1;
    }
    opts = (opts | O_NONBLOCK);
    if(fcntl(sockfd, F_SETFL, opts) < 0) {
        perror("fcntl(F_SETFL)\n");
        return -1;
    }
    return 0;
}

int _set_socket_keepalive(int listenfd)
{
        int optval;
        socklen_t optlen = sizeof(optval);
   
            /* Check the status for the keepalive option */
        if(getsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen) < 0) {
            perror("getsockopt()");
            close(listenfd);
            //exit(EXIT_FAILURE);
        }
        printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));
   
        /* Set the option active */
        optval = 1;
        optlen = sizeof(optval);
        if(setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
            perror("setsockopt()");
            close(listenfd);
            //exit(EXIT_FAILURE);
        }
   
        int keepIdle = 30;     //30秒没有数据上来,则发送探测包
        int keepInterval = 10;  //每隔10发数一个探测包
        int keepCount = 3;      //发送3个探测包,未收到反馈则主动断开连接
        setsockopt(listenfd, SOL_SOCKET, TCP_KEEPIDLE, (void *)&keepIdle, sizeof(keepIdle));
        setsockopt(listenfd, SOL_SOCKET,TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
        setsockopt(listenfd, SOL_SOCKET, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

        printf("SO_KEEPALIVE set on socket\n");

        /* Check the status again */
        if(getsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen) < 0) {
            perror("getsockopt()");
            close(listenfd);
            //exit(EXIT_FAILURE);
        }
        printf("SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));
}

int server_init(Server_event_handle *server)
{
        serverCfg = server;
    if ((listen_sock = create_and_bind(serverCfg->port)) == -1) {
        return -1;
    };
   
    setnonblocking(listen_sock);
        //_set_socket_keepalive(listen_sock);
        if ((listen(listen_sock, SOMAXCONN)) == -1) {
        return -1;
    }
       
    return 0;
}

int server_start()
{
        char buf[BUFSIZ];
    int conn_sock, epollfd, nfds,n, nread;
    struct epoll_event ev, events[MAX_EVENTS];
   
    if ((epollfd = epoll_create1(0)) == -1) {
        perror("epoll_create");
        return -1;
    }
   
    ev.events = EPOLLIN;
    ev.data.fd = listen_sock;
   
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
        perror("epoll_ctl: listen_sock");
        return -1;
    }
       
   
    while (1) {
        nfds = epoll_wait(epollfd, events, MAX_EVENTS, 5000);
        if (nfds == -1) {
            perror("epoll_pwait");
            return -1;
        }
        for (n = 0; n < nfds; ++n) {
            //处理其他事件类型
            printf("event:%X\n",events[n].events);
            if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP)|| (!(events[n].events & EPOLLIN))) {
                                printf("Closed connection %d\n",events[n].data.fd);
                                //serverCfg->close_handle(events[n].data.fd);
                                close(events[n].data.fd);
                                continue;
                        }
            
            //处理新连接
            if (events[n].data.fd == listen_sock) {
                struct sockaddr remote;
                socklen_t addrlen;
                addrlen = sizeof remote;
                char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
               
                conn_sock = accept(listen_sock, (struct sockaddr *) &remote, &addrlen);
                if (conn_sock == -1) {
                    if ((errno == EAGAIN) || (errno== EWOULDBLOCK)) {
                        break;
                    } else {
                        perror("accept");
                        break;
                    }
                }
                if (getnameinfo(&remote,addrlen, hbuf,sizeof hbuf, sbuf,sizeof sbuf,
                                NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
                    printf("Accepted connection from %s:%s\n",hbuf,sbuf);
                                }
                if (setnonblocking(conn_sock) == -1) {
                    break;
                }
                _set_socket_keepalive(conn_sock);
               
                //为新的连接注册epoll事件
                ev.events = EPOLLIN;
                ev.data.fd = conn_sock;
                if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
                    perror("epoll_ctl: conn_sock");
                    return -1;
                }
                                serverCfg->accept_handle(conn_sock);
                continue;
            }
            
            //处理接收数据
            if (events[n].events & EPOLLIN) {
                int done = 0;
                                int code = 0;
                                while(1) {
                                        code = serverCfg->process_handle(events[n].data.fd);
                                        if ( code == 1) {
                                                done = 1;
                                                break;
                                        } else if (code == 2) {
                                                break;
                                        }
                                }
                                if (done) {
                                        printf("Closed connection %d\n",events[n].data.fd);
                                        //serverCfg->close_handle(events[n].data.fd);
                    close(events[n].data.fd);
                                }
            }
        }
    }
    return 0;
}

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
2 [报告]
发表于 2013-11-01 17:43 |只看该作者
你用tcpdump抓下包看看,是不是真的断了,是不是真的keepalive包有发送。 keepalive这玩意不靠谱的,很多网络设备会帮你回应的。 检测是否断掉还是要靠应用层的心跳。

论坛徽章:
5
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:53:172015亚冠之水原三星
日期:2015-06-02 16:34:202015年亚冠纪念徽章
日期:2015-10-19 18:13:37程序设计版块每日发帖之星
日期:2015-11-08 06:20:00
3 [报告]
发表于 2013-11-01 18:28 |只看该作者
这个keepalive不是说连接上不动 到了时间就断开,而是没有数据传输到了一定时间发送探测包,而且对方没有相应才断开
主要处理对方掉电 拔网线 网络拓扑变化的情况

论坛徽章:
17
处女座
日期:2013-08-27 09:59:352015亚冠之柏太阳神
日期:2015-07-30 10:16:402015亚冠之萨济拖拉机
日期:2015-07-29 18:58:182015年亚洲杯之巴勒斯坦
日期:2015-03-06 17:38:17摩羯座
日期:2014-12-11 21:31:34戌狗
日期:2014-07-20 20:57:32子鼠
日期:2014-05-15 16:25:21亥猪
日期:2014-02-11 17:32:05丑牛
日期:2014-01-20 15:45:51丑牛
日期:2013-10-22 11:12:56双子座
日期:2013-10-18 16:28:17白羊座
日期:2013-10-18 10:50:45
4 [报告]
发表于 2013-11-01 18:41 |只看该作者
回复 1# hsdrhsdr


    3楼说的对,tcp的Keepalive只是表示在没有网络通信的情况下多长时间检测一次连接是否正常,在连接的端点主机突然断电而连接又没有通信的情况下另一端并不知道网络发生了变化。

论坛徽章:
0
5 [报告]
发表于 2013-11-04 11:08 |只看该作者
我的终端是移动网络,我是在连接上后,直接就把终端的电给拔掉了,还是没有检测到keepalive的断开事件。会不会移动基站帮我回应的
回复 3# xinglp


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP