Chinaunix首页 | 论坛 | 博客
  • 博客访问: 40306
  • 博文数量: 17
  • 博客积分: 750
  • 博客等级: 军士长
  • 技术积分: 160
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-19 17:39
文章分类
文章存档

2009年(17)

我的朋友

分类: LINUX

2009-11-05 17:14:57


#include    "unp.h"
#include    <stdarg.h>        /* ANSI C header file 可变参数列表*/
#include    <syslog.h>        /* for syslog() */

int        daemon_proc;        /* set nonzero by daemon_init() */
static void    err_doit(int, int, const char *, va_list);


//跟系统调用无关的错误均不打印errno


/* Nonfatal error related to system call
 * Print message and return 跟系统调用相关的非致命错误,仅打印信息不终止进程*/

err_ret(const char *fmt, ...)
{
    va_list        ap;

    va_start(ap, fmt);
    err_doit(1, LOG_INFO, fmt, ap);//打印errno

    va_end(ap);
    return;
}

/* Fatal error related to system call
 * Print message and terminate 跟系统调用相关的致命错误,打印信息并且终止进程*/

void
err_sys(const char *fmt, ...)
{
    va_list        ap;

    va_start(ap, fmt);
    err_doit(1, LOG_ERR, fmt, ap);//打印errno

    va_end(ap);
    exit(1);
}

/* Fatal error related to system call
 * Print message, dump core, and terminate 跟系统调用相关的致命错误,打印信息、生成core文件并且终止进程*/

void
err_dump(const char *fmt, ...)
{
    va_list        ap;

    va_start(ap, fmt);
    err_doit(1, LOG_ERR, fmt, ap);//打印errno

    va_end(ap);
    abort();        /* dump core and terminate */
    exit(1);        /* shouldn't get here 一般不会执行到此*/
}


//跟系统调用无关的错误均不打印errno


/* Nonfatal error unrelated to system call
 * Print message and return 跟系统调用无关的非致命错误,仅打印信息不终止进程*/

void
err_msg(const char *fmt, ...)
{
    va_list        ap;

    va_start(ap, fmt);
    err_doit(0, LOG_INFO, fmt, ap);//不打印errno

    va_end(ap);
    return;
}

/* Fatal error unrelated to system call
 * Print message and terminate 跟系统调用无关的致命错误,打印信息并且终止进程*/

void
err_quit(const char *fmt, ...)
{
    va_list        ap;

    va_start(ap, fmt);
    err_doit(0, LOG_ERR, fmt, ap);//不打印errno

    va_end(ap);
    exit(1);
}



/* Print message and return to caller
 * Caller specifies "errnoflag" and "level" */

static void
err_doit(int errnoflag, int level, const char *fmt, va_list ap)            //第一个参数为1则打印errno的值,为0则不打印;第二个参数传给

{                                                                        //syslog的level参数,fmt是类似printf的格式控制字符串,

    int        errno_save, n;
    char    buf[MAXLINE + 1];

    errno_save = errno;        /* value caller might want printed */
#ifdef    HAVE_VSNPRINTF
    vsnprintf(buf, MAXLINE, fmt, ap);    /* safe */
#else
    vsprintf(buf, fmt, ap);                    /* not safe */
#endif
    n = strlen(buf);
    if (errnoflag)
        snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
    strcat(buf, "\n");

    if (daemon_proc) {                //如果是守护进程的话,将出错消息写到记录文件中。

        syslog(level, buf);
    } else {
        fflush(stdout);                /* in case stdout and stderr are the same */
        fputs(buf, stderr);
        fflush(stderr);
    }
    return;
}


这些函数封装不错,我们自己在编程中也可以借鉴利用。这些出错封装函数用在了本书几乎所有系统调用的封装中,对系统调用进行封装以进行出错处理是一种不错的方法。封装后的函数都放到了自己的库libunp.a中,并在头文件unp.h中作了声明,我们的程序在使用这些封装函数时只需包括头文件unp.h即可,下面是几个例子。


#include    "unp.h"

int
Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
    int        n;

again:
    if ( (n = accept(fd, sa, salenptr)) < 0) {
#ifdef    EPROTO
        if (errno == EPROTO || errno == ECONNABORTED)
#else
        if (errno == ECONNABORTED)
#endif
            goto again;
        else
            err_sys("accept error");
    }
    return(n);
}

void
Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    if (bind(fd, sa, salen) < 0)
        err_sys("bind error");
}

void
Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    if (connect(fd, sa, salen) < 0)
        err_sys("connect error");
}
void
Listen(int fd, int backlog)
{
    char    *ptr;

        /*4can override 2nd argument with environment variable */
    if ( (ptr = getenv("LISTENQ")) != NULL)
        backlog = atoi(ptr);

    if (listen(fd, backlog) < 0)
        err_sys("listen error");
}
int
Socket(int family, int type, int protocol)
{
    int        n;

    if ( (n = socket(family, type, protocol)) < 0)
        err_sys("socket error");
    return(n);
}
/* end Socket */

void
Socketpair(int family, int type, int protocol, int *fd)
{
    int        n;

    if ( (n = socketpair(family, type, protocol, fd)) < 0)
        err_sys("socketpair error");
}
ssize_t
Recv(int fd, void *ptr, size_t nbytes, int flags)
{
    ssize_t        n;

    if ( (n = recv(fd, ptr, nbytes, flags)) < 0)
        err_sys("recv error");
    return(n);
}

ssize_t
Recvfrom(int fd, void *ptr, size_t nbytes, int flags,
         struct sockaddr *sa, socklen_t *salenptr)
{
    ssize_t        n;

    if ( (n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)
        err_sys("recvfrom error");
    return(n);
}

ssize_t
Recvmsg(int fd, struct msghdr *msg, int flags)
{
    ssize_t        n;

    if ( (n = recvmsg(fd, msg, flags)) < 0)
        err_sys("recvmsg error");
    return(n);
}

int
Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
       struct timeval *timeout)
{
    int        n;

    if ( (n = select(nfds, readfds, writefds, exceptfds, timeout)) < 0)
        err_sys("select error");
    return(n);        /* can return 0 on timeout */
}

void
Send(int fd, const void *ptr, size_t nbytes, int flags)
{
    if (send(fd, ptr, nbytes, flags) != (ssize_t)nbytes)
        err_sys("send error");
}

void
Sendto(int fd, const void *ptr, size_t nbytes, int flags,
     const struct sockaddr *sa, socklen_t salen)
{
    if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t)nbytes)
        err_sys("sendto error");
}

void
Sendmsg(int fd, const struct msghdr *msg, int flags)
{
    unsigned int    i;
    ssize_t            nbytes;

    nbytes = 0;    /* must first figure out what return value should be */
    for (i = 0; i < msg->msg_iovlen; i++)
        nbytes += msg->msg_iov[i].iov_len;

    if (sendmsg(fd, msg, flags) != nbytes)
        err_sys("sendmsg error");
}

void
Setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
{
    if (setsockopt(fd, level, optname, optval, optlen) < 0)
        err_sys("setsockopt error");
}

void
Shutdown(int fd, int how)
{
    if (shutdown(fd, how) < 0)
        err_sys("shutdown error");
}


以上函数的原文进均在unpv13e/lib目录中。此目录中还有大量其他的函数。我们在自己编程时,也可以将一些标准API封装,然后将它们连同一些我们自己的其他的常用函数做成一个自己的库。
本书作者在unp.h头文件中有如下语句:

#include    "../config.h"    /* configuration options for current OS */
                            /* "../config.h" is generated by configure */

 
config.h头文件configure脚本生成,从而很好的解决了代码的可移植性,使得在任何操作系统上都能正确的运行。
阅读(842) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~