免费注册 查看新帖 |

Chinaunix

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

[求助] socketpair进程间传递描述符 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-04-13 17:40 |只看该作者 |倒序浏览
本来最近想写一个进程间传递文件描述符的程序,从网上copy了一段代码,先是在AIX上面编译运行,程序成功运行,但是移植到HP UNIX上,运行后,发现sendmsg函数返回错误,errno的错误码是“Bad file number”错误。本人在网上查过一些资料,此程序在SCO上也会出现“Bad file number”错误,但是都说AIX和HP UNIX可以成功执行。前两天,本来将编译后的程序copy到另外一台HP UNIX机器,发现sendmsg函数居然成功了,但至今在测试的HP UNIX机器上都不能成功。请教一下各位大牛,是否也有遇到我这种情况的,是不是和HP UNIX机器设置相关,是否需要打开流管道神马之类的。在线等答案,急!!!

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <time.h>
#include <stdarg.h>

#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <assert.h>
#include <signal.h>
#include <sys/param.h>

#define IDLE        0   
#define BUSY        1   
#define END         2   
#define MAXLINE     1024

#define SA        struct sockaddr

typedef struct pro {  
    pid_t   id;     /*进程的进程ID*/  
    int     fd;     /*与父进程通信的描述符*/  
    int     flags;  /*进程当前状态*/  
    int     cnt;        /*进程服务的次数*/  
}process;  
process *mypid;     /*进程池*/  

ssize_t write_the_fd(int fd, void *ptr, size_t nbytes, int sendfd);  
pid_t make_child( int i, int listenfd );  
ssize_t read_the_fd(int fd, void *ptr, size_t nbytes, int *recvfd);  
void child_func(pid_t pid, int id, int fd);  
void clr(int signo);

static void err_doit(int errnoflag, int error, const char *fmt, va_list ap)
{
    char buf[MAXLINE];
    vsnprintf(buf, MAXLINE, fmt, ap);

    if (errnoflag)
        snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s", strerror(error));

    strcat(buf, "\n";
    fflush(stdout);  /* in case stdout and stderr are the same */
    fputs(buf, stderr);
    fflush(NULL);    /* flushes all stdio output streams */
}

void err_sys(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    err_doit(1, errno, fmt, ap);
    va_end(ap);
    exit(1);
}

void err_quit(const char *fmt, ...)
{
    va_list ap;
       
        va_start(ap, fmt);
    err_doit(0, 0, fmt, ap);
    va_end(ap);

    exit(1);
}

int max(int a, int b)
{
   return a > b ? a : b;
}

int main( int argc, char **argv ) {  
    int         nchild, fdmax, listenfd, connfd, i, len, nselect, port;  
    char        c;  
    struct sockaddr_in      addr, clientaddr;  
    signal(SIGCHLD, clr);  
    signal(SIGINT, clr);  
    fd_set  rset, oset;  
    if(argc != 3)  
        err_quit("args";
    listenfd = socket( AF_INET, SOCK_STREAM, 0 );/*服务器监听套接字*/  
    if( listenfd < 0 ) {  
        err_sys("socket";  
    }  
    nchild = atoi(argv[1]);
    port = atoi(argv[2]);
    mypid = (struct pro *)malloc( nchild * sizeof( struct pro) );  
    bzero( &addr, sizeof(addr));  
    addr.sin_family = AF_INET;  
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);  
    bind(listenfd, (SA *)&addr, sizeof(struct sockaddr));  
    fdmax = listenfd;                       /*用于select */  
    for( i = 0; i < nchild; i++ ) {  
        make_child(i, listenfd);                /*创建子进程并等待给客户服务*/  
    }                                   /*传入listenfd子进程关闭监听套接字*/  
    int idle = nchild;                      /*当前空闲的子进程*/  
    len = sizeof(struct sockaddr);  
    FD_ZERO(&oset);  
    FD_ZERO(&rset);  
    listen(listenfd,5);  
    FD_SET(listenfd, &oset);  
    for( ; {  
        if(idle == 0)
            FD_CLR(listenfd, &oset);        /*若没有空闲子进程,则禁止accept新连接*/  
        else
            FD_SET(listenfd, &oset);      
        rset = oset;  
        nselect = select(fdmax+1, &rset, NULL, NULL, NULL);
        printf("loop select = %d\n", nselect);
        if( FD_ISSET(listenfd, &rset) ) {       /*收到客户端连接请求*/  
            connfd = accept(listenfd, (SA *)&clientaddr, (socklen_t *)&len);  
            for( i = 0; i < nchild; i++) {  
                if(mypid[i].flags == IDLE) {    /*查找可供服务的子进程*/  
                    break;  
                }  
            }
            /*  */  
            //assert(i < nchild);  
            if (i >= nchild)
            {
                printf("poll enough\n";
                continue;
            }

            printf("the id is %d [connfd = %d]\n", i, connfd);  
            mypid[i].flags = BUSY;                  /*改变子进程状态*/  
            mypid[i].cnt ++;                        /*子进程服务次数*/  
            FD_SET(mypid[i].fd, &oset);             /*加入描述集,等待子进程*/  
            fdmax = max(fdmax ,mypid[i].fd);  
            idle --;                                /*空闲进程减少*/  
            /*通知子进程*/  
            write_the_fd(mypid[i].fd, " ", 1,connfd);/*把连接套接字传送给子进程*/
            printf("write the fd\n";
            close(connfd);                           /*因为有一个connfd在飞,所以这个可以关闭*/  
            if(--nselect  ==0)  
                continue;  
        }  
        else {  
            for(i = 0; i < nchild; i++ )
            {
                printf("child cancle\n";
                if(FD_ISSET(mypid[i].fd , &rset))
                {
                    read(mypid[i].fd, &c, 1);  
                    mypid[i].flags = IDLE;  
                    FD_CLR(mypid[i].fd, &oset);  
                    idle ++;
                    nselect--;
                    printf("idle = %d\n", idle);
                }
                if(nselect  == 0)  
                    break;  
            }
  
        }
        
    }  
}

void clr(int signo)
{
    pid_t pid;

    while( (pid = waitpid(-1, NULL, WNOHANG)) > 0 )
    {
        printf("The child %d is done\n", pid);
    }
    sleep(2);
    printf("process %d cancel!!!\n", getpid());
    fflush(stdout);
    kill(getpid(), SIGTERM);
    return;
}

pid_t make_child( int i, int listenfd ) {  
    pid_t   child;  
    int     fd[2];
    int     ret;
   
    if (0 != socketpair( AF_UNIX, SOCK_STREAM,0, fd))
    {
        printf("socketpair fail\n";
    }
    else
    {
        printf("scoketpair succ\n";
    }
    if( (child = fork( ) ) < 0 ) {  
        err_quit("fork ";  
    }  
    if( child > 0 ) {  /*父进程*/  
        //printf("the  i is  %d\n", i);   
        close( fd[1] );  
        mypid[i].id = child;  
        mypid[i].fd= fd[0];  
        mypid[i].flags = IDLE;  
        mypid[i].cnt = 0;  
        return child;  
    }  
    /*子进程*/  
    close( fd[0] );  
    close(listenfd);  
    //dup2( fd[1], STDERR_FILENO);  
    //close( fd[1]);  
    printf("fd[1] = %d\n", fd[1]);
    child_func(getpid(), i, fd[1]);  
}  
  
void child_func(pid_t pid, int id, int fd) {  
    int         connfd, n;  
    char        c;  
    char        buf[MAXLINE];  
    for( ; ; )
    {
        printf("fd = %d\n", fd);
        n = read_the_fd(fd, &c, 1, &connfd);
        printf("read fd succ!!![id = %d][fd = %d]\n", id, connfd);
        if(n <0 )
            err_sys("read_fd");
        
        again:
        /*
        while( (n = read(connfd, buf, sizeof(buf))) > 0 ){
            write(connfd, buf ,n);
            printf("%s[id = %d]\n", buf, id);
        }
        */
        n = read(connfd, buf, sizeof(buf));

        printf("break connfd\n");
        if((n < 0)&&( errno == EINTR))
            goto again;
        else if(n < 0)
            err_sys("error");  
        else if(n == 0) {
            close(connfd);
            //printf("$$$$$$[id = %d]\n", id);
            write(fd, " ", 1);
        }
    }
}  
ssize_t write_the_fd(int fd, void *ptr, size_t nbytes, int sendfd) {  
    struct msghdr   msg;  
    struct iovec    iov[1];  
    union {  
      struct cmsghdr    cm;  
      char              control[CMSG_SPACE(sizeof(int))];  
    } control_un;  
    struct cmsghdr  *cmptr;
    int ret = 0;

    msg.msg_control = control_un.control;  
    msg.msg_controllen = sizeof(control_un.control);  
    cmptr = CMSG_FIRSTHDR(&msg);  
    cmptr->cmsg_len = CMSG_LEN(sizeof(int));  
    cmptr->cmsg_level = SOL_SOCKET;  
    cmptr->cmsg_type = SCM_RIGHTS;  
    *((int *) CMSG_DATA(cmptr)) = sendfd;  
    msg.msg_name = NULL;  
    msg.msg_namelen = 0;  
    iov[0].iov_base = ptr;  
    iov[0].iov_len = nbytes;  
    msg.msg_iov = iov;  
    msg.msg_iovlen = 1;
    ret = sendmsg(fd, &msg, 0);
    perror("sendmsg");
    printf("fd = %d,ret = %d\n", fd, ret);
   
    return ret;
}  
ssize_t read_the_fd(int fd, void *ptr, size_t nbytes, int *recvfd) {  
    struct msghdr   msg;  
    struct iovec    iov[1];  
    ssize_t         n;  
    int             newfd;  
    union {  
      struct cmsghdr    cm;  
      char              control[CMSG_SPACE(sizeof(int))];  
    } control_un;  
    struct cmsghdr  *cmptr;  
  
    msg.msg_control = control_un.control;  
    msg.msg_controllen = sizeof(control_un.control);  
    msg.msg_name = NULL;  
    msg.msg_namelen = 0;  
  
    iov[0].iov_base = ptr;  
    iov[0].iov_len = nbytes;  
    msg.msg_iov = iov;  
    msg.msg_iovlen = 1;  
  
    if ( (n = recvmsg(fd, &msg, 0)) <= 0)  
        return(n);  
    if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&  
        cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {  
        if (cmptr->cmsg_level != SOL_SOCKET)  
            err_quit("control level != SOL_SOCKET");  
        if (cmptr->cmsg_type != SCM_RIGHTS)  
            err_quit("control type != SCM_RIGHTS");  
        *recvfd = *((int *) CMSG_DATA(cmptr));  
    } else  
        *recvfd = -1;         
    return(n);  
}  

论坛徽章:
0
2 [报告]
发表于 2013-04-13 18:36 |只看该作者
惠普unix的版本:HP-UX DCCTST B.11.11 U 9000/800 3554230364 unlimited-user license

论坛徽章:
48
15-16赛季CBA联赛之青岛
日期:2021-01-07 13:41:2315-16赛季CBA联赛之上海
日期:2020-12-01 18:02:0720周年集字徽章-20	
日期:2020-10-28 14:14:2620周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之天津
日期:2020-10-18 22:51:412016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之北控
日期:2015-12-22 13:30:48操作系统版块每日发帖之星
日期:2015-12-07 06:20:00操作系统版块每日发帖之星
日期:2015-09-04 06:20:002015亚冠之德黑兰石油
日期:2015-08-05 18:46:082015年亚洲杯之巴勒斯坦
日期:2015-04-19 10:42:502015年亚洲杯之巴林
日期:2015-04-09 08:03:23
3 [报告]
发表于 2013-04-14 21:09 |只看该作者
没玩过,不过可以给个思考的思路:

1. 那套正常的HP-UX的系统版本和patch level和这台有问题的是否一样?
2. 对比两台机器的errno.h文件版本是否一样?

论坛徽章:
0
4 [报告]
发表于 2013-04-15 17:07 |只看该作者
应该都是同一批机器,现在怀疑是不是权限问题

论坛徽章:
48
15-16赛季CBA联赛之青岛
日期:2021-01-07 13:41:2315-16赛季CBA联赛之上海
日期:2020-12-01 18:02:0720周年集字徽章-20	
日期:2020-10-28 14:14:2620周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之天津
日期:2020-10-18 22:51:412016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之北控
日期:2015-12-22 13:30:48操作系统版块每日发帖之星
日期:2015-12-07 06:20:00操作系统版块每日发帖之星
日期:2015-09-04 06:20:002015亚冠之德黑兰石油
日期:2015-08-05 18:46:082015年亚洲杯之巴勒斯坦
日期:2015-04-19 10:42:502015年亚洲杯之巴林
日期:2015-04-09 08:03:23
5 [报告]
发表于 2013-04-16 00:24 |只看该作者
那就检查权限问题了,怀疑归怀疑,还得去验证了~:wink:

论坛徽章:
0
6 [报告]
发表于 2013-04-16 09:53 |只看该作者
拿root用户执行了,还是不成功啊

论坛徽章:
48
15-16赛季CBA联赛之青岛
日期:2021-01-07 13:41:2315-16赛季CBA联赛之上海
日期:2020-12-01 18:02:0720周年集字徽章-20	
日期:2020-10-28 14:14:2620周年集字徽章-20	
日期:2020-10-28 14:04:3015-16赛季CBA联赛之天津
日期:2020-10-18 22:51:412016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之北控
日期:2015-12-22 13:30:48操作系统版块每日发帖之星
日期:2015-12-07 06:20:00操作系统版块每日发帖之星
日期:2015-09-04 06:20:002015亚冠之德黑兰石油
日期:2015-08-05 18:46:082015年亚洲杯之巴勒斯坦
日期:2015-04-19 10:42:502015年亚洲杯之巴林
日期:2015-04-09 08:03:23
7 [报告]
发表于 2013-04-16 21:25 |只看该作者
不懂coding,Google或看看下面的帖子:

http://h30499.www3.hp.com/t5/Lan ... rrno-9/td-p/3614219
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP