现在的位置: 首页 > 综合 > 正文

UNP函数笔记十一: 高级I/O函数

2013年01月29日 ⁄ 综合 ⁄ 共 9647字 ⁄ 字号 评论关闭

第十四章  高级I/O函数:

#include <sys/socket.h>
ssize_t recv(int sockfd, void * buff, size_t nbytes, int flags);
    success return recv-byte-count, error return -1
ssize_t send(int sockfd, const void * buff, size_t nbytes, int flags);
    success return send-byte-count, error return -1
    flags:
        MSG_DONTROUTE, MSG_DONTWAIT, MSG_OOB, MSG_PEEK, MSG_WAITALL

/* if system support MSG_WAITALL */
#define readn(fd, ptr, n) recv(fd, ptr, n, MSG_WAITALL)

#include <sys/uio.h>
ssize_t readv(int fileds, const struct iovec * iov, int iovcnt);
    success return total-read-byte-count, error return -1
ssize_t writev(int fileds, const struct iovec * iov, int iovcnt);
    success return total-write-byte-count, error return -1
    struct iovec {
        void  * iov_base; /* starting address of buffer */
        size_t  iov_len;  /* size of buffer */
    };

#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags);
    success return recv-byte-count, error return -1
ssize_t sendmsg(int sockfd, struct msghdr * msg, int flags);
    success return send-byte-count, error return -1
    struct msghdr {
        void         * msg_name;        /* protocol address */
        socklen_t      msg_namelen;     /* size of protocol address (val-ret)*/
        struct iovec * msg_iov;         /* scatter/gather array */
        int            msg_iovlen;      /* element-count in msg_iov */
        void         * msg_control;     /* ancillary data (cmsghdr struct) */
        socklen_t      msg_controllen;  /* length of ancillary data */
        int            msg_flags;       /* flags returned by recvmsg() */
        ...
    };
    flags:
        MSG_DONTROUTE, MSG_DONTWAIT, MSG_OOB, MSG_PEEK, MSG_WAITALL
    msg_flags:
        MSG_DONTROUTE, MSG_DONTWAIT, MSG_OOB, MSG_PEEK, MSG_WAITALL
        MSG_BCAST, MSG_MCAST, MSG_TRUNC, MSG_CTRUNC, MSG_EOR, MSG_NOTIFICATION
    struct cmsghdr {
        socklen_t  cmsg_len;   /* length in bytes, including this structure */
        int        cmsg_level; /* originating protocol */
        int        cmsg_type;  /* protocol-specific type */
        /* followed by unsigned char cmsg_data[] */
    };

#include <sys/socket.h>
#include <sys/param.h> /* for ALIGN macro on many implementations */
struct cmsghdr * CMSG_FIRSTHDR(struct msghdr * mhdrptr);
struct cmsghdr * CMSG_NXTHDR(struct msghdr * mhdrptr, 
                             struct cmsghdr * cmsgptr);
unsigned char * CMSG_DATA(struct cmsghdr * cmsgptr);

unsigned int CMSG_LENGTH(unsigned int length);
unsigned int CMSG_SPACE(unsigned int length);

usage:
    struct msghdr    msg;
    struct cmsghdr * cmsgptr;
    /* fill in msg structure */
    /* call recvmsg() */
    for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; 
         cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
        if (cmsgptr->cmsg_level == ... && 
            cmsgptr->cmsg_type == ...) {
            u_char * ptr = CMSG_DATA(cmsgptr);
            /* process data */
        }
    }

/dev/poll - interface:
#include <sys/devpoll.h>
struct dvpoll {
    struct pollfd * dp_fds;
    int             dp_nfds;
    int             dp_timeout;
};

#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
int kqueue(void);
int kevent(int kq, const struct kevent * changelist, int nchanges, 
           struct kevent * eventlist, int nevents, 
           const struct timespec * timeout);
void EV_SET(struct kevent * kev, uintptr_t ident, short filter, 
            u_short flags, u_int fflags, intptr_t data, void * udata);
    struct kevent {
        uintptr_t  ident;
        short      filter;
        u_short    flags;
        u_int      fflags;
        intptr_t   data;
        void     * udata;
    };
    flags:
        EV_ADD,     EV_CLEAR,  EV_DELETE,  (value)
        EV_DISABLE, EV_ENABLE, EV_ONESHOT, (value)
        EV_EOF,     EV_ERROR               (result)
    filter:
        EVFILT_AIO, EVFILT_PROC, EVFILT_READ, EVFILT_SIGNAL, 
        EVFILT_TIMER, EVFILT_VNODE, EVFILT_WRITE

示例:

#include <netinet/in.h>

#include "err_exit.h"
#include "my_signal.h"

#define MAXLINE 4096

void 
sig_alrm(int signo)
{
    return;  /* just interrupt the recvfrom() */
}

void 
dg_cli(FILE * fp, int sockfd, const struct sockaddr * pservaddr, 
       socklen_t servlen)
{
    int   n;
    char  sendline[MAXLINE];
    char  recvline[MAXLINE + 1];

    if (my_signal(SIGALRM, sig_alrm) == SIG_ERR) {
        err_exit("my_signal error");
    }

    while (fgets(sendline, MAXLINE, fp) != NULL) {
        n = strlen(sendline);
        if (sendto(sockfd, sendline, n, 0, pservaddr, servlen) != n) {
            err_exit("sendto error");
        }

        alarm(5);
        if ((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {
            if (errno == EINTR) {
                fprintf(stderr, "socket timeout\n");
            }
            else {
                err_exit("recvfrom error");
            }
        }
        else {
            alarm(0);
            recvline[n] = 0;  /* null terminate */
            if (fputs(recvline, stdout) == EOF) {
                err_exit("fputs error");
            }
        }
    }
    if (ferror(fp)) {
        err_exit("fgets error");
    }
}

#include <netinet/in.h>

#include "err_exit.h"
#include "my_signal.h"

void 
connect_alarm(int signo)
{
    return;  /* just interrupt the connect() */
}

int 
connect_timeo(int sockfd, const struct sockaddr * saptr, 
              socklen_t salen, int nsec)
{
    Sigfunc  * sigfunc;
    int        n;

    if ((sigfunc = my_signal(SIGALRM, connect_alarm)) == SIG_ERR) {
        err_exit("my_signal error");
    }

    if (alarm(nsec) != 0) {
        printf("connect_timeo: alarm was already set\n");
    }

    if ((n = connect(sockfd, saptr, salen)) < 0) {
        if (errno == EINTR) {
            errno = ETIMEDOUT;
        }
        if (close(sockfd) == -1) {
            err_exit("close error");
        }
    }

    alarm(0);  /* turn off the alarm */

    /* restore previous signal handler */
    if (my_signal(SIGALRM, sigfunc) == SIG_ERR) {
        err_exit("my_signal error");
    }

    return(n);
}

#include <stdio.h>
#include <sys/select.h>

int 
readable_timeo(int fd, int sec)
{
    fd_set          rset;
    struct timeval  tv;

    FD_ZERO(&rset);
    FD_SET(fd, &rset);

    tv.tv_sec = sec;
    tv.tv_usec = 0;

    return(select(fd + 1, &rset, NULL, NULL, &tv));
}

#include <stdio.h>
#include <sys/select.h>

int 
writeable_timeo(int fd, int sec)
{
    fd_set          wset;
    struct timeval  tv;

    FD_ZERO(&wset);
    FD_SET(fd, &wset);

    tv.tv_sec = sec;
    tv.tv_usec = 0;

    return(select(fd + 1, NULL, &wset, NULL, &tv));
}

#include <netinet/in.h>

#include "err_exit.h"
#include "readable_timeo.h"

#define MAXLINE 4096

void 
dg_cli(FILE * fp, int sockfd, const struct sockaddr * pservaddr, 
       socklen_t servlen)
{
    int   n;
    char  sendline[MAXLINE];
    char  recvline[MAXLINE + 1];

    while (fgets(sendline, MAXLINE, fp) != NULL) {
        n = strlen(sendline);
        if (sendto(sockfd, sendline, n, 0, pservaddr, servlen) != n) {
            err_exit("sendto error");
        }

        if ((n = readable_timeo(sockfd, 5)) < 0) {
            err_exit("readable_timeo error");
        }
        else if (n == 0) {
            fprintf(stderr, "socket timeout\n");
        }
        else {
            if ((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {
                err_exit("recvfrom error");
            }
            recvline[n] = 0;  /* null terminate */
            if (fputs(recvline, stdout) == EOF) {
                err_exit("fputs error");
            }
        }
    }
    if (ferror(fp)) {
        err_exit("fgets error");
    }
}

#include <netinet/in.h>

#include "err_exit.h"

#define MAXLINE 4096

void 
dg_cli(FILE * fp, int sockfd, const struct sockaddr * pservaddr, 
       socklen_t servlen)
{
    int             n;
    char            sendline[MAXLINE];
    char            recvline[MAXLINE + 1];
    struct timeval  tv;

    tv.tv_sec = 5;
    tv.tv_usec = 0;
    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
        err_exit("setsockopt error");
    }

    while (fgets(sendline, MAXLINE, fp) != NULL) {
        n = strlen(sendline);
        if (sendto(sockfd, sendline, n, 0, pservaddr, servlen) != n) {
            err_exit("sendto error");
        }

        if ((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {
            if (errno == EWOULDBLOCK) {
                fprintf(stderr, "socket timeout\n");
            }
            else {
                err_exit("recvfrom error");
            }
        }
        else {
            recvline[n] = 0;  /* null terminate */
            if (fputs(recvline, stdout) == EOF) {
                err_exit("fputs error");
            }
        }
    }
    if (ferror(fp)) {
        err_exit("fgets error");
    }
}

#include "err_exit.h"

#define MAXLINE 4096

/* 
 * we'd better not use standant IO functions with socket 
 */
void 
str_echo(int sockfd)
{
    char   line[MAXLINE];
    FILE * fpin;
    FILE * fpout;

    if ((fpin = fdopen(sockfd, "r")) == NULL) {
        err_exit("fdopen to read error");
    }
    if ((fpout = fdopen(sockfd, "w")) == NULL) {
        err_exit("fdopen to write error");
    }

    while (fgets(line, MAXLINE, fpin) != NULL) {
        if (fputs(line, fpout) == EOF) {
            err_exit("fputs error");
        }
        fflush(fpout); /* default full buffered */
    }
    if (ferror(fpin)) {
        err_exit("fgets error");
    }
}

#include "err_exit.h"

#define MAXLINE 4096

/* 
 * we'd better not use standant IO functions with socket 
 */
void 
str_echo(int sockfd)
{
    char   line[MAXLINE];
    FILE * fpin;
    FILE * fpout;

    if ((fpin = fdopen(sockfd, "r")) == NULL) {
        err_exit("fdopen to read error");
    }
    if ((fpout = fdopen(sockfd, "w")) == NULL) {
        err_exit("fdopen to write error");
    }

    if (setvbuf(fpin, NULL, _IOLBF, 0) != 0) {   /* line buffered */
        err_exit("setvbuf fpin error");
    }
    if (setvbuf(fpout, NULL, _IOLBF, 0) != 0) {  /* line buffered */
        err_exit("setvbuf fpout error");
    }

    while (fgets(line, MAXLINE, fpin) != NULL) {
        if (fputs(line, fpout) == EOF) {
            err_exit("fputs error");
        }
    }
    if (ferror(fpin)) {
        err_exit("fgets error");
    }
}

#include <sys/devpoll.h> /* no such file */

#include "writen.h"
#include "err_exit.h"

void 
str_cli(FILE * fp, int sockfd)
{
    int            stdineof;
    char           buf[MAXLINE];
    int            n;
    int            wfd;
    int            i;
    int            result;
    struct pollfd  pofd[2];
    struct dvpoll  dopoll;

    if ((wfd = open("/dev/poll", O_RDWR, 0)) == -1) {
        err_exit("open error");
    }

    pofd[0].fd = fileno(fp);
    pofd[0].events = POLLIN;
    pofd[0].revents = 0;

    pofd[1].fd = sockfd;
    pofd[1].events = POLLIN;
    pofd[1].revents = 0;

    if (write(wfd, pofd, sizeof(pofd) != sizeof(pofd)) {
        err_exit("write error");
    }

    stdineof = 0;
    for ( ; ; ) {
        /* block until /dev/poll says something is ready */
        dopoll.dp_timeout = -1; /* blocking */
        dopoll.dp_nfds = 2;
        dopoll.dp_fds = pofd;
        if ((result = ioctl(wfd, DP_POLL, &dopoll)) == -1) {
            err_exit("ioctl error");
        }

        /* loop through ready file descriptors */
        for (i = 0; i < result; ++i) {
            if (dopoll.dp_fds[i].fd == sockfd) {
                /* socket is readable */
                if ((n = read(sockfd, buf, MAXLINE)) < 0) {
                    err_exit("read error");
                }
                else if (n == 0) {
                    if (stdineof == 1) {
                        return;  /* normal termination */
                    }
                    else {
                        err_exit("str_cli: server terminated prematurely");
                    }
                }

                if (write(fileno(stdout), buf, n) != n) {
                    err_exit("write error");
                }
            }
            else {
                /* input is readable */
                if ((n = read(fileno(fp), buf, MAXLINE)) < 0) {
                    err_exit("read error");
                }
                else if (n == 0) {
                    stdineof = 1;
                    if (shutdown(sockfd, SHUT_WR) == -1) {  /* send FIN */
                        err_exit("shutdown error");
                    }
                    continue;
                }

                if (writen(sockfd, buf, n) != n) {
                    err_exit("writen error");
                }
            }
        }
    }
}

#include <sys/types.h>
#include <sys/event.h> /* no such file */
#include <sys/time.h>

#include "writen.h"
#include "err_exit.h"

#define MAXLINE 4096

void 
str_cli(FILE * fp, int sockfd)
{
    int              kq;
    int              i;
    int              n;
    int              nev;
    int              stdineof = 0;
    int              isfile;
    char             buf[MAXLINE];
    struct kevent    kev[2];
    struct timespec  ts;
    struct stat      st;

    isfile = ((fstat(fileno(fp), &st) == 0) &&
              (st.st_mode & S_IFMT) == S_IFREG);

    EV_SET(&kev[0], fileno(fp), EVFILT_READ, EV_ADD, 0, 0, NULL);
    EV_SET(&kev[1], sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL);

    kq = kqueue();
    ts.tv_sec = 0;
    ts.tv_nsec = 0;
    kevent(kq, kev, 2, NULL, 0, &ts); /* non-blocking */

    for ( ; ; ) {
        nev = kevent(kq, NULL, 0, kev, 2, NULL); /* blocking */

        for (i = 0; i < nev; ++i) {
            if (kev[i].ident == sockfd) {    /* socket is readable */
                if ((n = read(sockfd, buf, MAXLINE)) < 0) {
                    err_exit("read error");
                }
                else if (n == 0) {
                    if (stdineof == 1) {
                        return;  /* normal termination */
                    }
                    else {
                        err_quit("str_cli: server terminated prematurely");
                    }
                }

                if (write(fileno(stdout), buf, n) != n) {
                    err_exit("write error");
                }
            }
            else if (kev[i].ident == fileno(fp)) {  /* input is readable */
                if ((n = read(fileno(fp), buf, MAXLINE)) < 0) {
                    err_exit("read error");
                }
                else if (n > 0) {
                    if (writen(sockfd, buf, n) != n) {
                        err_exit("writen error");
                    }
                }

                if (n == 0 || (isfile && n == kev[i].data)) {
                    stdineof = 1;
                    if (shutdown(sockfd, SHUT_WR) == -1) {  /* send FIN */
                        err_exit("shutdown error");
                    }
                    kev[i].flags = EV_DELETE;
                    kevent(kq, &kev[i], 1, NULL, 0, &ts);  /* remove kevent */
                }
            }
        }
    }
}

抱歉!评论已关闭.