TCP Echo Server/Client 回射服务器/客户端

回射服务器没有做出错处理:

回射服务器 C语言代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SERV_PORT 5000
#define MAXLINE  64

void str_echo(int fd);
void sig_chld(int signo);

int main(int argc, char **argv)
{
    int listenfd, connfd;
    pid_t childpid;
    socklen_t clilen;
    struct sockaddr_in cliaddr, servaddr;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);
    bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
    listen(listenfd, 5);
    // 获取子进程的结束信号并用sig_chld做处理, signal()函数在多线程显示是没有定义的
    // 一般是用sigaction来替换, 我这图方便
    if (signal(SIGCHLD, sig_chld) == SIG_ERR){
        fprintf(stderr, "can't catch SIGCHLD \n");
        exit(0);
    }
    for ( ; ; ){
        clilen = sizeof(cliaddr);
        if ( (connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen)) < 0){
            if (errno == EINTR) // accept 在阻塞的时候被signal打断会返回EINTR错误存于errno
                continue; // back to for()
            else{
                fprintf(stderr, "accept error\n");
                exit(0);
            }
        }

        if ((childpid = fork()) == 0){ // child
            close(listenfd); // close listening socket
            str_echo(connfd);// process the request
            exit(0);
        }
        close(connfd); // parent closes connected socket
    }
    return 0;
}

void str_echo(int sockfd)
{
    int n;
    char buf[MAXLINE];
again:
    while ( (n = read(sockfd, buf, MAXLINE)))
        write(sockfd, buf, n);
    if (n < 0 && errno == EINTR)
        goto again;
    else if (n < 0)
        printf("str_echo: read error");
}

void sig_chld(int signo)
{
    pid_t pid;
    int stat;
    while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
        printf("child %d terminated\n", pid);// printf() isn't suitable for use here
    return;
}

回射服务单线程select版本

#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define MAXLINE 1024
#define SERV_PORT 5000

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; // 再次执行write()
                        else 
                                return -1; // error
                }

                nleft -= nwritten;
                ptr += nwritten;
        }
        return n;
}

int main(int argc, char **argv)
{
        int i, maxi, maxfd, listenfd, connfd, sockfd;
        int nready, client[FD_SETSIZE];
        ssize_t n;
        fd_set rset, allset;
        char buf[MAXLINE];
        socklen_t clilen;
        struct sockaddr_in cliaddr, servaddr;

        listenfd = socket(AF_INET, SOCK_STREAM, 0);

        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(SERV_PORT);

        bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

        listen(listenfd, 5);

        maxfd = listenfd; // initialize
        maxi = -1;  // index into client[] array
        for (i = 0; i < FD_SETSIZE; ++i)
                client[i] = -1; // -1 indicates available entry
        FD_ZERO(&allset);
        FD_SET(listenfd, &allset);

        for ( ; ; ) {
                rset = allset; // structure assignment
                nready = select(maxfd + 1, &rset, NULL, NULL, NULL);

                if (FD_ISSET(listenfd, &rset)) { // new client connection
                        clilen = sizeof(cliaddr);
                        connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);

                        for (i = 0; i < FD_SETSIZE; ++i) {
                                if (client[i] < 0) {
                                        client[i] = connfd; // save descriptor
                                        break;
                                }
                        }
                        if (i == FD_SETSIZE) {
                                fprintf(stderr, "too many clients");
                                exit(1);
                        }
                        FD_SET(connfd, &allset); // add new descriptor to set
                        if (connfd > maxfd)
                                maxfd = connfd; // for select
                        if (i > maxi)
                                maxi = i; // max index in client[i] array

                        if (--nready <= 0)
                                continue; // no more readable descriptors
                }
                for (i = 0; i <= maxi; ++i) { // check all clients for data
                        if ( (sockfd = client[i]) < 0)
                                continue;
                        if (FD_ISSET(sockfd, &rset)) {
                                if ( (n = read(sockfd, buf, MAXLINE)) == 0) {
                                        // connection closed by client
                                        close(sockfd);
                                        FD_CLR(sockfd, &allset);
                                        client[i] = -1;
                                } else
                                        writen(sockfd, buf, n);
                                if (--nready <= 0)
                                        break; // no more readable descriptors
                        }

                }
        }

        exit(0);
}

回射服务器单线程poll版本

#include  // for OPEN_MAX
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


#define MAXLINE 1024
#define SERV_PORT 5000
#define OPEN_MAX 1024
#define INFTIM -1 

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; // 再次执行write()
                        else 
                                return -1; // error
                }

                nleft -= nwritten;
                ptr += nwritten;
        }
        return n;
}

int main(int argc, char **argv)
{
        int i, maxi, listenfd, connfd, sockfd;
        int nready;

        ssize_t n;
        char buf[MAXLINE];
        socklen_t clilen;
        struct pollfd client[OPEN_MAX];
        struct sockaddr_in cliaddr, servaddr;

        listenfd = socket(AF_INET, SOCK_STREAM, 0);

        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port = htons(SERV_PORT);

        bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

        listen(listenfd, 5);
        client[0].fd = listenfd;
        client[0].events = POLLRDNORM;
        for (i = 0; i < OPEN_MAX; ++i)
                client[i].fd = -1;  // indicates available entry
        maxi = 0;  // max index into client[] array
        for ( ; ; ) {
                nready = poll(client, maxi + 1, INFTIM);
                if (client[0].revents & POLLRDNORM) { // new client connection
                        clilen = sizeof(cliaddr);
                        connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);

                        for (i = 1; i < OPEN_MAX; ++i) {
                                if (client[i].fd < 0) {
                                        client[i].fd = connfd; // save descriptor
                                        break;
                                }
                        }
                        if (OPEN_MAX == i) {
                                printf("too many clients");
                                exit(1);
                        }
                        client[i].events = POLLRDNORM;
                        if (i > maxi)
                                maxi = i;  // max index in client[] array

                        if (--nready <= 0)
                                continue; // no more readable descriptors
                }

                for (i = 1; i <= maxi; ++i) { // check all clients for data
                        if ( (sockfd = client[i].fd) < 0)
                                continue;
                        if (client[i].revents & (POLLRDNORM | POLLERR)) {
                                if ( (n = read(sockfd, buf, MAXLINE)) < 0) {
                                        if (errno == ECONNRESET) {
                                                // connection reset by client
                                                close(sockfd);
                                                client[i].fd = -1;
                                        } else if (0 == n) {
                                                // connection closed by client
                                                close(sockfd);
                                                client[i].fd = -1;
                                        } else 
                                                writen(sockfd, buf, n);
                                        if (--nready <= 0)
                                                break; // no more readable descriptors
                                }
                        }
                }
        }
        return 0;
}

回射客户端C语言代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define SERV_PORT 5000
#define MAXLINE  1024

void str_cli(FILE *fp, int sockfd);
// 这个readline代码很低效,因为它是一个字符一个字符的读取的
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++){
    again:
        if ( (rc = read(fd, &c, 1)) == 1){
            *ptr++ = c;
            if (c == '\n')
                break;  // newline is stored
        } else if (rc == 0){
            *ptr = 0;
            return (n - 1); // EOF, n - 1 bytes
        } else {
            if (errno == EINTR)
                    goto again;
            return -1; /// error, errno set by read()
        }
    }
    *ptr = 0;
    return n;
}

int main(int argc, char **argv)
{
    int sockfd;
    struct sockaddr_in servaddr;

    if (argc != 2){
        fprintf(stderr, "usage: tcpcli ");
        return 1;
    }
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
    inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
    str_cli(stdin, sockfd);  // do it all
    exit(0);
}

void str_cli(FILE *fp, int sockfd)
{
    char sendline[MAXLINE], recvline[MAXLINE];
    while (fgets(sendline, MAXLINE, fp) != NULL){
        write(sockfd, sendline, strlen(sendline));
        if (readline(sockfd, recvline, MAXLINE) == 0)
            printf("str_cli:server terminated prematurely");
        fputs(recvline, stdout);
    }
}

select版本的str_cli函数

void str_cli(FILE *fp, int sockfd)
{
        int maxfdp1;
        fd_set rset;
        char sendline[MAXLINE], recvline[MAXLINE];

        FD_ZERO(&rset);
        for ( ; ; ) {
                FD_SET(fileno(fp), &rset);
                FD_SET(sockfd, &rset);
                maxfdp1 = max(fileno(fp), sockfd) + 1;
                select(maxfdp1, &rset, NULL, NULL, NULL);

                if (FD_ISSET(sockfd, &rset)) { // socket is readable
                        if (readline(sockfd, recvline, MAXLINE) == 0)
                                printf("str_cli: server terminated prematurely");
                        fputs(recvline, stdout);
                }

                if (FD_ISSET(fileno(fp), &rset)) { // input is readable
                        if (NULL == fgets(sendline, MAXLINE, fp))
                                return ;  // all done
                        writen(sockfd, sendline, strlen(sendline));
                }
        }
}

你可能感兴趣的:(服务器后台)