免费注册 查看新帖 |

Chinaunix

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

sock编程accept异常 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-11-19 11:24 |只看该作者 |倒序浏览
在服务器编程中,程序开始很正常,但是运行一整天后,每次客户连接都会产生accept连接异常,此时,正在连接的客户只有1-2个,小于队列数,问:这是什么原因产生的,如何解决

论坛徽章:
0
2 [报告]
发表于 2005-11-19 11:29 |只看该作者
int Service(int port, int sec, int usec)
{
    int SockFd;         /* 本地监听端口 */
    int NewSck;         /* 远程连接端口 */
    int addr_len;       /* 网络地址长度 */
    int ret;            /* 函数返回值   */
    int i;              /* 循环变量     */
    int idx;            /* 端口表中序号 */
    int flag;
    struct sockaddr_in my_addr;
    struct sockaddr_in their_addr;
    struct timeval TOut;/* 超时变量     */
    fd_set ReadFds;     /* 读监听端口   */
    fd_set ErrFds;      /* 错误监听端口 */
char msg[1024];

    /* 初始化 */
    SockFd   = -1;
    NewSck   = -1;
    addr_len = sizeof(struct sockaddr_in);
    ret      = 0;
    i        = 0;
    memset(&my_addr, 0x00, sizeof(struct sockaddr_in));
    memset(&their_addr, 0x00, sizeof(struct sockaddr_in));
    memset(&TOut, 0x00, sizeof(struct timeval));
    FD_ZERO(&ReadFds);
    FD_ZERO(&ErrFds);

    /* 建立网络端口 */
    SockFd = socket(AF_INET, SOCK_STREAM, 0);
    if(-1 == SockFd)
    {
        return -1;
    }

    /* 设置端口属性 */
    my_addr.sin_family = PF_INET;
    my_addr.sin_port = htons(port);
    bzero(&my_addr.sin_zero, sizeof(my_addr.sin_zero));
    my_addr.sin_addr.s_addr = INADDR_ANY;
/* 12 add by tch */
    /* 使地址马上可以重用 */
    ret = 1;
    ret = setsockopt(SockFd, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof(ret));

    /* 绑定端口 */
    if(bind(SockFd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
    {
        close(SockFd);
        return -1;
    }

    /* 监听该端口 */
    if(listen(SockFd, MAX_PORT + 1) == -1)
    {
        return -1;
    }
    printf("Listen Begin Port = %dn", port);

    setjmp(NetError);   /* SIGPIPE信号回复点,网络错误 */
    NowPortIdx = -1;
    signal(SIGPIPE, NetErrProc);
                    memset(msg, 0x00, sizeof(msg));
                    sprintf(msg, "Begin Service ---------nn");
                    LogMsg(msg);
    while(1)
    {
        ret = 0;
        /* 检查所有连接是否超时 */
        IsDisConn();
        NowPortIdx = 0;

        /* 设置超时时间 */
        TOut.tv_sec  = sec;
        TOut.tv_usec = usec;
        /* 设置监听端口 */
        MaxFd = GetMaxFd(SockFd);
        FD_ZERO(&ErrFds);
        FD_ZERO(&ReadFds);
        ReadFds  = AllFds;
        ErrFds   = AllFds;
//printf("Select Time = %dn", time(NULL));
        ret = select(MaxFd + 1, &ReadFds, 0x00, &ErrFds, &TOut);
        if(ret <= 0)    /* 监听超时 */
        {
            continue;
        }

        /* 判断是否有新的连接 */
        if(FD_ISSET(SockFd, &ReadFds))
        {
            NowPortIdx = -2;
            flag = 0;
sock_accept:
            NewSck = accept(SockFd, (struct sockaddr *)&their_addr, &addr_len);
            if(-1 != NewSck)
            {
printf("NewSock[%d] = %dn", idx, NewSck);
do some things
                    break;
                }
                if(idx >= MAX_PORT)
                {
                    memset(msg, 0x00, sizeof(msg));
                    sprintf(msg, "No Port Tbl NowSock[%d] = %dn", idx, NewSck);
                    LogMsg(msg);
printf("No Port Table NowSock[%d] = %dn", idx, NewSck);
                    /* 关闭连接 */
                    close(NewSck);
                }
            }
            else
            {
                memset(msg, 0x00, sizeof(msg));
                sprintf(msg, "accept erro SockFd = %dn", SockFd);
                LogMsg(msg);
                printf("accept error SockFd = %d   errorno = %dn", SockFd, errno);


                if((EINTR == errno) && (flag < 3))
                {
                    flag++;
                    goto sock_accept;
                }
            }
        }

论坛徽章:
0
3 [报告]
发表于 2005-11-19 11:29 |只看该作者
用出错时的errno判断一下原因

论坛徽章:
0
4 [报告]
发表于 2005-11-19 11:35 |只看该作者

有没有出现的可能呢

由于需要运行长时间才能出现这个问题,所以不能马上得到errno,
根据代码,有没有其它可能呢,例如使系统错误,代码错误等等类型

论坛徽章:
0
5 [报告]
发表于 2005-11-19 12:02 |只看该作者
程序太长了没耐心看只是觉得不太对劲,accept是个阻塞调用怎么写到while循环的中间了?
一般的
serverSocket = socket(....);
...................
bind(......);
listen(......);
while(someCon.){
conSocket = accept(.....);
if(conSocket < 0) {
// 处理错误
}
else{
forkID = fork();
if(dorkID == 0) {
// 子进程处理新连接
}
else {
// 主进程的其他处理
}
}
LZ好像是把这两部分混在一起了吧。

论坛徽章:
0
6 [报告]
发表于 2005-11-19 12:26 |只看该作者

需要做些其它事情

由于需要在程序中动态监测一些其它事情,每次都需要在select之前进行,所以accept就到了循环中间了

论坛徽章:
0
7 [报告]
发表于 2005-11-19 12:36 |只看该作者
原帖由 tanchanghe 于 2005-11-19 12:26 发表
由于需要在程序中动态监测一些其它事情,每次都需要在select之前进行,所以accept就到了循环中间了

accept阻塞了循环还动得了?

论坛徽章:
0
8 [报告]
发表于 2005-11-19 14:14 |只看该作者
原帖由 caojiqun 于 2005-11-19 12:36 发表

accept阻塞了循环还动得了?


他是要用select 和FD_ISSET检测到有一个新的连接来时才调用accept,所以accept会立即
返回。

论坛徽章:
0
9 [报告]
发表于 2005-11-19 14:25 |只看该作者
lz请检查一下是否在每次调用select之前对ReadFds (也就是AllFds)进行了重新赋值,
注意是每次调用select之前都必须重新赋值。

另外如果是fork子进程来处理新的连接,在父进程里是否close了连接accept返回的连接,
否则当打开的文件到达系统设定的上限时accept就会返回错误。

你也可以吧,errno(或者errinfo)输出到log文件中

论坛徽章:
0
10 [报告]
发表于 2005-11-20 12:35 |只看该作者
listening socket应该置为unblocked,否则accept会阻塞.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP