网络编程学习笔记(非阻塞读和写)

来源:互联网 发布:数据库软件 编辑:程序博客网 时间:2024/06/06 02:24

维护两个缓冲区:to容纳从标准输入到服务器的数据,from容纳从服务器到标准输出的数据

toiptr指向从标准输入读入的数据可以存放的下一个字节,tooptr指下一个必须写入到套接口的字节。有(toiptr - tooptr)个字节需写到套接口。friptr表示从套接口读入的数据可以存放的下一个字节,froptr表示下一个必须写到标准输出的字节

将套接口、标准输入、标准输出设置为非阻塞时,如果写或读没有成功,会返回EWOULDBLOCK

服务器端代码:

#include <sys/socket.h>#include <stdio.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <string.h>#include <time.h>#include <unistd.h>#include <stdlib.h>#include <sys/wait.h>#define SIN_PORT 9999#define BUFLEN 256void str_echo(int fd);void sig_chld(int signo){pid_t pid;int stat;pid = wait(&stat);printf("child %d terminate\n", pid);}int main(int argc, char **argv){    int listenfd, connfd;    pid_t child;    struct sockaddr_in servaddr;    char buf[BUFLEN];    time_t ticks;    listenfd = socket(AF_INET, SOCK_STREAM, 0);    if (listenfd < 0) {        printf("socket error :%s\n", strerror(errno));                return -1;    }    servaddr.sin_family = AF_INET;    servaddr.sin_port = htons(SIN_PORT);    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);            if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {        printf("bind error:%s\n", strerror(errno));        close(listenfd);        return -1;    }            if (listen(listenfd, 3) < 0) {        printf("listen error:%s\n", strerror(errno));        close(listenfd);        return -1;    }    signal(SIGCHLD, sig_chld);        struct sockaddr_in clientaddr;    int len;    for (;;) {        len = sizeof(clientaddr);        connfd = accept(listenfd, (struct sockaddr*)&clientaddr, &len);        if (connfd < 0) {    if (errno == EINTR) continue;    else {            printf("accept error:%s\n", strerror(errno));            close(listenfd);            return -1;    }        }        if ((child = fork()) == 0) {            close(listenfd);            str_echo(connfd);              return 0;        }                close(connfd);            }    return 0;}size_t readn(int fd, void *ptr, size_t n){    char *p = ptr;    size_t nleft = n;    size_t nread;    while (nleft > 0) {        if ((nread = read(fd, p, nleft)) < 0) {            if (errno == EINTR) nread = 0;            else return -1;        } else if (nread == 0) break;        nleft -= nread;        p += nread;    }    return n - nleft;}size_t readline(int fd, void *ptr, size_t maxsize){    char *p = ptr;    size_t rc, n;    char c;    for (n = 1; n < maxsize; n++) {again:        if ((rc = read(fd, &c, 1)) == 1) {            *p++ = c;            if (c == '\n') break;            } else if (rc == 0) {                if (n == 1) return 0;                else break;        } else {            if (errno == EINTR) goto again;            return -1;        }    }    *p = 0;    return n;}size_t writen(int fd, void *ptr, size_t n){    char *p = ptr;    size_t nleft = n,  nwriten;    while (nleft > 0) {        if ((nwriten = write(fd, p, nleft)) <= 0) {            if (errno == EINTR) nwriten = 0;            else return -1;        }        p += nwriten;        nleft -= nwriten;    }    return n;}void str_echo(int fd){    char recvline[BUFLEN];    int n;        for (;;) {        if ((n = readline(fd, recvline, BUFLEN)) == 0) return;         printf("received buf=%s", recvline);        writen(fd, recvline, n);    }}

客户端代码:

#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <fcntl.h>#include <time.h>#include <sys/types.h>#define SERV_PORT 9999#define MAXLINE 128#define MAX(a, b) ((a) < (b) ? (b) : (a))char *gf_time(){struct timeval tv;static char str[30];char *ptr;if (gettimeofday(&tv, NULL) < 0) {fprintf(stderr, "gettimeofday error:%s\n", strerror(errno));return NULL;} ptr = ctime(&tv.tv_sec);strcpy(str, &ptr[11]);snprintf(str + 8, sizeof(str) - 8, ".%06ld", tv.tv_usec);return str;}void str_cli(FILE *fp, int sockfd){int maxfd1, val, stdineof;ssize_t n, nwritten;fd_set rset, wset;char to[MAXLINE], from[MAXLINE];char *toiptr, *tooptr, *friptr, *froptr;val = fcntl(sockfd, F_GETFL, 0);if (fcntl(sockfd, F_SETFL, val | O_NONBLOCK) < 0) {printf("fcntl error:%s\n", strerror(errno));close(sockfd);return;}val = fcntl(STDIN_FILENO, F_GETFL, 0);if (fcntl(STDIN_FILENO, F_SETFL, val | O_NONBLOCK) < 0) {printf("fcntl stdin error:%s\n", strerror(errno));close(sockfd);return;}val = fcntl(STDOUT_FILENO, F_GETFL, 0);if (fcntl(STDOUT_FILENO, F_SETFL, val | O_NONBLOCK) < 0) {printf("fcntl stdout error:%s\n", strerror(errno));close(sockfd);return ;}toiptr = tooptr = to;friptr = froptr = from;stdineof = 0;maxfd1 = MAX(sockfd, MAX(STDIN_FILENO, STDOUT_FILENO)) + 1;for (;;) {FD_ZERO(&rset);FD_ZERO(&wset);if (stdineof == 0 && toiptr < &to[MAXLINE]) {FD_SET(STDIN_FILENO, &rset);}if (friptr < &from[MAXLINE]) {FD_SET(sockfd, &rset);}if (tooptr != toiptr) {FD_SET(sockfd, &wset);}if (froptr != friptr) {FD_SET(STDOUT_FILENO, &wset);}int res;if ((res = select(maxfd1, &rset, &wset, NULL, NULL)) < 0) {if (errno != EINTR) {close(sockfd);return;}}if (FD_ISSET(STDIN_FILENO, &rset)) {if ((n = read(STDIN_FILENO, toiptr, &to[MAXLINE] - toiptr)) < 0) {if (errno != EWOULDBLOCK) {printf("read error from stdin:%s\n", strerror(errno));close(sockfd);return;}} else if (n == 0) {fprintf(stderr, "%s:EOF on stdin\n", gf_time());stdineof = 1;if (toiptr == tooptr) shutdown(sockfd, SHUT_WR);} else {fprintf(stderr, "%s:read %d bytes from stdin\n", gf_time(), n);toiptr += n;FD_SET(sockfd, &wset);}}if (FD_ISSET(sockfd, &rset)) {if ((n = read(sockfd, friptr, &from[MAXLINE] - friptr)) < 0) {if (errno != EWOULDBLOCK) {printf("read error on socket:%s\n", strerror(errno));close(sockfd);return;}} else if (n == 0) {fprintf(stderr, "%s :EOF on socket\n", gf_time());if (stdineof) return;} else {fprintf(stderr, "%s:read %d bytes from socket\n", gf_time(), n);friptr += n;FD_SET(STDOUT_FILENO, &wset);}}if (FD_ISSET(STDOUT_FILENO, &wset) && ((n = friptr - froptr) > 0)) {if ((nwritten = write(STDOUT_FILENO, froptr, n)) < 0) {if (errno != EWOULDBLOCK) {printf("write stdout error:%s\n", strerror(errno));close(sockfd);return;}} else {fprintf(stderr, "%s:write %d bytes to stdout\n", gf_time(), nwritten);froptr += nwritten;if (froptr == friptr) friptr = froptr = from;}}if (FD_ISSET(sockfd, &wset) && ((n = toiptr - tooptr) > 0)) {if ((nwritten = write(sockfd, tooptr, n)) < 0) {if (errno != EWOULDBLOCK) {fprintf(stderr, "write on socket error:%s\n", strerror(errno));close(sockfd);return;}} else {fprintf(stderr, "%s:write %d bytes to socket\n", gf_time(), nwritten);tooptr += nwritten;if (tooptr == toiptr) {toiptr = tooptr = to;if (stdineof) shutdown(sockfd, SHUT_WR);}}}}}int main(int argc, char **argv){struct sockaddr_in servaddr, cliaddr;socklen_t len;int sockfd;servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) < 0) {printf("inet_pton error:%s\n", strerror(errno));return -1;}sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0) {printf("socket error:%s\n", strerror(errno));return -1;}if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {printf("connect error:%s\n", strerror(errno));close(sockfd);return -1;}str_cli(stdin, sockfd);return 0;}



0 0
原创粉丝点击