转载地址:http://blog.chinaunix.net/uid-28977986-id-3886809.html
《UNIX网络编程套接字联网API》这本书的示例中定义了许多包裹函数,它们的名称和标准函数一样,只是首字母变成大写字母;每个包裹函数完成实际的函数调用,检查返回值,并在发生错误时终止程序。
我在重写书上例子的时候,也仿照书上的方式,定义了许多包裹函数,提高程序的可读性(当然,我定义的包裹函数的错误处理没有书上例子这么详细了)
文件my_unp.h:它定义了一些常量,声明了所有的包裹函数
#ifndef MY_UNP_H_ #define MY_UNP_H_ #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include <errno.h> #include <pthread.h> #include <semaphore.h> #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/select.h> #include <sys/epoll.h> #include <sys/poll.h> #include <sys/file.h> #include <sys/mman.h> #define MAXLINE 1024 #define LISTENQ 1024 #define MAXNITEMS 1000000 #define MAXNTHREADS 100 #define SERV_PORT 9877 #define SERV_PORT_STR "9877" #define SA struct sockaddr typedef void Sigfunc(int); #define min(a,b) ((a) < (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b)) //错误处理函数,输出错误信息后退出程序 void error_quit(char *fmt, ...); //为了适应网络的慢速IO而编写的读写函数 ssize_t readn(int fd, void *vptr, size_t n); ssize_t writen(int fd, const void *vptr, size_t n); ssize_t readline(int fd, void *vptr, size_t maxlen); //各类读写包裹函数 void Write(int fd, void *ptr, size_t nbytes); ssize_t Read(int fd, void *ptr, size_t nbytes); ssize_t Readn(int fd, void *ptr, size_t nbytes); void Writen(int fd, void *ptr, size_t nbytes); ssize_t Readline(int fd, void *ptr, size_t maxlen); void Fputs(const char *ptr, FILE *stream); char *Fgets(char *ptr, int n, FILE *stream); //各类标准包裹函数 int Open(const char *pathname, int flags, mode_t mode); void Close(int fd); Sigfunc *Signal(int signo, Sigfunc *func); void *Malloc(size_t size); void *Calloc(size_t n, size_t size); void Pipe(int *fds); pid_t Fork(void); pid_t Waitpid(pid_t pid, int *iptr, int options); void Dup2(int fd1, int fd2); //各类网络包裹函数 int Socket(int family, int type, int protocol); void Inet_pton(int family, const char *strptr, void *addrptr); void Connect(int fd, const struct sockaddr *sa, socklen_t salen); void Listen(int fd, int backlog); void Bind(int fd, const struct sockaddr *sa, socklen_t salen); int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr); const char *Inet_ntop(int family, const void *addrptr, char *strptr, size_t len); int Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); int Poll(struct pollfd *fdarray, unsigned long nfds, int timeout); void Shutdown(int fd, int how); int Epoll_create(int size); void Epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); int Epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); void Sendto(int fd, const void *ptr, size_t nbytes, int flags, const struct sockaddr *sa, socklen_t salen); ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr *sa, socklen_t *salenptr); void Setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen); void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); void Munmap(void *addr, size_t len); void Ftruncate(int fd, off_t length); //各类和线程操作相关的包裹函数 void Pthread_create(pthread_t *tid, const pthread_attr_t *attr, void * (*func)(void *), void *arg); void Pthread_detach(pthread_t tid); void Pthread_join(pthread_t tid, void **status); void Pthread_kill(pthread_t tid, int signo); void Pthread_mutex_lock(pthread_mutex_t *mptr); void Pthread_mutex_unlock(pthread_mutex_t *mptr); //此函数相当于UNP书上的set_concurrency函数 void Pthread_setconcurrency(int level); void Pthread_cond_signal(pthread_cond_t *cptr); void Pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr); //各类和信号量相关的包裹函数 sem_t *Sem_open(const char *name, int oflag, mode_t mode, unsigned int value); void Sem_close(sem_t *sem); void Sem_unlink(const char *pathname); void Sem_init(sem_t *sem, int pshared, unsigned int value); void Sem_destroy(sem_t *sem); void Sem_wait(sem_t *sem); void Sem_post(sem_t *sem); void Sem_getvalue(sem_t *sem, int *valp); #endif
文件unp_base.c:它定义了基本的包裹函数
#include "my_unp.h" //此函数是在程序发生错误时被调用 //先输出字符串fmt,再根据errno输出错误原因(如果有的话),最后退出程序 //注:在多线程程序中,错误原因可能不正确 void error_quit(char *fmt, ...) { int res; va_list list; va_start(list, fmt); res = vfprintf(stderr, fmt, list); if( errno != 0 ) fprintf(stderr, " : %s", strerror(errno)); fprintf(stderr, "\n", list); va_end(list); exit(1); } //字节流套接字上调用read时,输入的字节数可能比请求的数量少, //但这不是出错的状态,原因是内核中用于套接字的缓冲区可能已经达到了极限, //此时需要调用者再次调用read函数 ssize_t readn(int fd, void *vptr, size_t n) { size_t nleft; ssize_t nread; char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nread = read(fd, ptr, nleft)) < 0) { if (errno == EINTR) nread = 0; /* and call read() again */ else return(-1); } else if (nread == 0) break; /* EOF */ nleft -= nread; ptr += nread; } return (n - nleft); /* return >= 0 */ } //字节流套接字上调用write时,输出的字节数可能比请求的数量少, //但这不是出错的状态,原因是内核中用于套接字的缓冲区可能已经达到了极限, //此时需要调用者再次调用write函数 ssize_t writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR) nwritten = 0; /* and call write() again */ else return(-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return n; } static int read_cnt; static char *read_ptr; static char read_buf[MAXLINE]; //内部函数my_read每次最多读MAXLINE个字节,然后每次返回一个字节 static ssize_t my_read(int fd, char *ptr) { if (read_cnt <= 0) { again: if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) { if (errno == EINTR) goto again; return(-1); } else if (read_cnt == 0) return(0); read_ptr = read_buf; } read_cnt--; *ptr = *read_ptr++; return 1; } //从描述符中读取文本行 ssize_t readline(int fd, void *vptr, size_t maxlen) { ssize_t n, rc; char c, *ptr; ptr = vptr; for (n = 1; n < maxlen; n++) { if ( (rc = my_read(fd, &c)) == 1) { *ptr++ = c; if (c == '\n') break; /* newline is stored, like fgets() */ } else if (rc == 0) { *ptr = 0; return(n - 1); /* EOF, n - 1 bytes were read */ } else return(-1); /* error, errno set by read() */ } *ptr = 0; /* null terminate like fgets() */ return n; } ssize_t Readn(int fd, void *ptr, size_t nbytes) { ssize_t n = readn(fd, ptr, nbytes); if ( n < 0) error_quit("readn error"); return n; } void Writen(int fd, void *ptr, size_t nbytes) { if ( writen(fd, ptr, nbytes) != nbytes ) error_quit("writen error"); } ssize_t Readline(int fd, void *ptr, size_t maxlen) { ssize_t n = readline(fd, ptr, maxlen); if ( n < 0) error_quit("readline error"); return n; } ssize_t Read(int fd, void *ptr, size_t nbytes) { ssize_t n = read(fd, ptr, nbytes); if ( n == -1) error_quit("read error"); return n; } void Write(int fd, void *ptr, size_t nbytes) { if (write(fd, ptr, nbytes) != nbytes) error_quit("write error"); } int Open(const char *pathname, int flags, mode_t mode) { int fd = open(pathname, flags, mode); if( -1 == fd ) error_quit("open file %s error", pathname); return fd; } void Close(int fd) { if (close(fd) == -1) error_quit("close error"); } void Fputs(const char *ptr, FILE *stream) { if (fputs(ptr, stream) == EOF) error_quit("fputs error"); } char *Fgets(char *ptr, int n, FILE *stream) { char *rptr = fgets(ptr, n, stream); if ( rptr == NULL && ferror(stream) ) error_quit("fgets error"); return rptr; } int Socket(int family, int type, int protocol) { int n = socket(family, type, protocol); if( n < 0) error_quit("socket error"); return n; } void Inet_pton(int family, const char *strptr, void *addrptr) { int n = inet_pton(family, strptr, addrptr); if( n < 0) error_quit("inet_pton error for %s", strptr); } void Connect(int fd, const struct sockaddr *sa, socklen_t salen) { if (connect(fd, sa, salen) < 0) error_quit("connect error"); } void Listen(int fd, int backlog) { if (listen(fd, backlog) < 0) error_quit("listen error"); } void Bind(int fd, const struct sockaddr *sa, socklen_t salen) { if (bind(fd, sa, salen) < 0) error_quit("bind error"); } int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr) { int n = accept(fd, sa, salenptr); if ( n < 0) error_quit("accept error"); return n; } const char *Inet_ntop(int family, const void *addrptr, char *strptr, size_t len) { const char *ptr = inet_ntop(family, addrptr, strptr, len); if ( ptr == NULL) error_quit("inet_ntop error"); return ptr; } pid_t Fork(void) { pid_t pid = fork(); if ( pid == -1) error_quit("fork error"); return pid; } Sigfunc *Signal(int signo, Sigfunc *func) { Sigfunc *sigfunc = signal(signo, func); if ( sigfunc == SIG_ERR) error_quit("signal error"); return sigfunc; } int Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int n = select(nfds, readfds, writefds, exceptfds, timeout); if ( n < 0 ) error_quit("select error"); return n; /* can return 0 on timeout */ } int Poll(struct pollfd *fdarray, unsigned long nfds, int timeout) { int n = poll(fdarray, nfds, timeout); if ( n < 0 ) error_quit("poll error"); return n; } void Shutdown(int fd, int how) { if (shutdown(fd, how) < 0) error_quit("shutdown error"); } int Epoll_create(int size) { int n = epoll_create(size); if( n < 0 ) error_quit("epoll create error"); return n; } void Epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) { if( epoll_ctl(epfd, op, fd, event) < 0 ) error_quit("epoll ctl error"); } int Epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) { int n = epoll_wait(epfd, events, maxevents, timeout); if( n < 0 ) error_quit("epoll wait error"); return n; } 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) error_quit("sendto error"); } ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags, struct sockaddr *sa, socklen_t *salenptr) { ssize_t n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr); if ( n < 0 ) error_quit("recvfrom error"); return n; } ssize_t Recvmsg(int fd, struct msghdr *msg, int flags) { ssize_t n = recvmsg(fd, msg, flags); if ( n < 0 ) error_quit("recvmsg error"); return(n); } void *Malloc(size_t size) { void *ptr = malloc(size); if ( ptr == NULL ) error_quit("malloc error"); return ptr; } void *Calloc(size_t n, size_t size) { void *ptr = calloc(n, size); if ( ptr == NULL) error_quit("calloc error"); return ptr; } void Pipe(int *fds) { if ( pipe(fds) < 0 ) error_quit("pipe error"); } pid_t Waitpid(pid_t pid, int *iptr, int options) { pid_t retpid = waitpid(pid, iptr, options); if ( retpid == -1) error_quit("waitpid error"); return retpid; } void Setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) { if (setsockopt(fd, level, optname, optval, optlen) < 0) error_quit("setsockopt error"); } void Socketpair(int family, int type, int protocol, int *fd) { int n = socketpair(family, type, protocol, fd); if ( n < 0 ) error_quit("socketpair error"); } void Dup2(int fd1, int fd2) { if (dup2(fd1, fd2) == -1) error_quit("dup2 error"); } void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { void *ptr = mmap(addr, len, prot, flags, fd, offset); if ( ptr == MAP_FAILED ) error_quit("mmap error"); return ptr; } void Munmap(void *addr, size_t len) { if (munmap(addr, len) == -1) error_quit("munmap error"); } void Ftruncate(int fd, off_t length) { if (ftruncate(fd, length) == -1) error_quit("ftruncate error"); }
文件unp_pthread.c:它定义了基本的线程类包裹函数
#include "my_unp.h" void Pthread_create(pthread_t *tid, const pthread_attr_t *attr, void * (*func)(void *), void *arg) { int n = pthread_create(tid, attr, func, arg); if ( n == 0) return; errno = n; error_quit("pthread_create error"); } void Pthread_detach(pthread_t tid) { int n = pthread_detach(tid); if ( n == 0) return; errno = n; error_quit("pthread_detach error"); } void Pthread_join(pthread_t tid, void **status) { int n = pthread_join(tid, status); if ( n == 0 ) return; errno = n; error_quit("pthread_join error"); } void Pthread_kill(pthread_t tid, int signo) { int n = pthread_kill(tid, signo); if ( n == 0 ) return; errno = n; error_quit("pthread_kill error"); } void Pthread_mutex_lock(pthread_mutex_t *mptr) { int n = pthread_mutex_lock(mptr); if ( n == 0 ) return; errno = n; error_quit("pthread_mutex_lock error"); } void Pthread_mutex_unlock(pthread_mutex_t *mptr) { int n = pthread_mutex_unlock(mptr); if ( n == 0 ) return; errno = n; error_quit("pthread_mutex_unlock error"); } void Pthread_setconcurrency(int level) { int n = pthread_setconcurrency(level); if ( n == 0 ) return; errno = n; error_quit("pthread_mutex_unlock error"); } void Pthread_cond_signal(pthread_cond_t *cptr) { int n = pthread_cond_signal(cptr); if ( n == 0 ) return; errno = n; error_quit("pthread_cond_signal error"); } void Pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr) { int n = pthread_cond_wait(cptr, mptr); if ( n == 0 ) return; errno = n; error_quit("pthread_cond_wait error"); } sem_t *Sem_open(const char *name, int oflag, mode_t mode, unsigned int value) { sem_t *sem = sem_open(name, oflag, mode, value); if( NULL == sem ) error_quit("sem_open error for %s", name); return sem; } void Sem_close(sem_t *sem) { if (sem_close(sem) == -1) error_quit("sem_close error"); } void Sem_unlink(const char *pathname) { if (sem_unlink(pathname) == -1) error_quit("sem_unlink error"); } void Sem_init(sem_t *sem, int pshared, unsigned int value) { if (sem_init(sem, pshared, value) == -1) error_quit("sem_init error"); } void Sem_destroy(sem_t *sem) { if (sem_destroy(sem) == -1) error_quit("sem_destroy error"); } void Sem_wait(sem_t *sem) { if (sem_wait(sem) == -1) error_quit("sem_wait error"); } void Sem_post(sem_t *sem) { if (sem_post(sem) == -1) error_quit("sem_post error"); } void Sem_getvalue(sem_t *sem, int *valp) { if (sem_getvalue(sem, valp) == -1) error_quit("sem_getvalue error"); }