《UNIX网络编程套接字联网API》这本书的示例中定义了许多包裹函数,它们的名称和标准函数一样,只是首字母变成大写字母;每个包裹函数完成实际的函数调用,检查返回值,并在发生错误时终止程序。
我在重写书上例子的时候,也仿照书上的方式,定义了许多包裹函数,提高程序的可读性(当然,我定义的包裹函数的错误处理没有书上例子这么详细了)
PS:这篇文章(博客)会持续更新。
文件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");
}