TCP回射程序(I/O复用 select)

服务器端 tcpserv.c

#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>

#define LISTENQ 1024
#define MAXLINE 4096
#define SERV_PORT 9877
#define SA struct sockaddr

int main(int argc, char* argv[])
{
    int i, maxi, maxfd, listenfd, connfd, sockfd;
    int nready, client[FD_SETSIZE];

    //pid_t childpid;
    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);

    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, (SA*)&servaddr, sizeof(servaddr));

    listen(listenfd, LISTENQ);

    maxfd = listenfd;

    maxi = -1;

    for(i = 0; i < FD_SETSIZE; i++)
    {
        client[i] = -1;
    }
    FD_ZERO(&allset);
    FD_SET(listenfd, &allset);

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

        if(FD_ISSET(listenfd, &rset)){
            clilen = sizeof(cliaddr);
            connfd = accept(listenfd, (SA*)&cliaddr, &clilen);

            for(i = 0; i < FD_SETSIZE; i++)
            {
                if(client[i] < 0)
                {
                    client[i] = connfd;   //save discriptor
                    break;
                }
            }

            if(i == FD_SETSIZE)
            {
                err_quit("too many clients");
            }

            FD_SET(connfd, &allset);

            if(connfd > maxfd)
            {
                maxfd = connfd;
            }

            if(i > maxi)
            {
                maxi = i;
            }

            if(--nready <= 0)
            {
                continue;
            }
        }

        for(i = 0; i <= maxi; i++)
        {
            if((sockfd = client[i]) < 0)
            {
                continue;
            }

            if(FD_ISSET(sockfd, &rset)){
                if((n = read(sockfd, buf, MAXLINE)) == 0)
                {
                    close(sockfd);
                    FD_CLR(sockfd, &allset);
                    client[i] = -1;
                }
                else
                {
                    writen(sockfd, buf, n);
                }

                if(--nready)
                {
                    break;
                }
            }
        }
    }
    //for(; ; )
    //{
    //    clilen = sizeof(cliaddr);
    //    connfd = accept(listenfd, (SA*)&cliaddr, &clilen);

    //    if((childpid = fork()) == 0)
    //    {
    //        close(listenfd);
    //        str_echo(connfd);
    //        exit(0);
    //    }
    //    close(connfd);
    //}

    exit(0);
}
客户端 tcpcli.c
[cpp]  view plain copy
  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <sys/socket.h>  
  4. #include <string.h>  
  5. #include <arpa/inet.h>  
  6. #include <stdlib.h>  
  7.   
  8. #define SERV_PORT 9877  
  9. #define SA struct sockaddr  
  10.   
  11. int main(int argc, char* argv[])  
  12. {  
  13.     int sockfd;  
  14.     struct sockaddr_in servaddr;  
  15.   
  16.     if(argc != 2)  
  17.     {  
  18.         err_quit("usage: tcpcli <IPaddress>");  
  19.     }  
  20.     sockfd = socket(AF_INET, SOCK_STREAM, 0);  
  21.   
  22.     bzero(&servaddr, sizeof(servaddr));  
  23.   
  24.     servaddr.sin_family = AF_INET;  
  25.     servaddr.sin_port = htons(SERV_PORT);  
  26.     inet_pton(AF_INET, argv[1], &servaddr.sin_addr);  
  27.   
  28.     connect(sockfd, (SA*)&servaddr, sizeof(servaddr));  
  29.   
  30.     str_cli(stdin,sockfd);  
  31.   
  32.     exit(0);  
  33. }  
str_cli.h iew plain copy
  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <sys/socket.h>

  6. #define MAXLINE 4096

  7. #undef max
  8. #define max(x,y) ((x)>(y)?(x):(y))

  9. void str_cli(FILE* fp, int sockfd);
str_cli.c

[cpp]  view plain copy
  1. #include "str_cli.h"

  2. void str_cli(FILE* fp, int sockfd)
  3. {
  4.     int maxfdp1, stdineof;
  5.     fd_set rset;
  6.     char buf[MAXLINE];
  7.     int n;

  8.     stdineof = 0;
  9.     FD_ZERO(&rset);

  10.     for( ; ;)
  11.     {
  12.         if(stdineof == 0)
  13.             FD_SET(fileno(fp), &rset);
  14.         FD_SET(sockfd, &rset);
  15.         maxfdp1 = max(fileno(fp), sockfd) + 1;

  16.         select(maxfdp1, &rset, NULL, NULL, NULL);
  17.         if(FD_ISSET(sockfd, &rset))    //socket is readable
  18.         {
  19.             if((n = read(sockfd, buf, MAXLINE)) == 0)
  20.             {
  21.                 if(stdineof == 1)
  22.                 {
  23.                     return;
  24.                 }
  25.                 else
  26.                 {
  27.                     err_quit("str_cli: server terminated prematurely");
  28.                 }
  29.             }
  30.             write(fileno(stdout), buf, n);
  31.         }

  32.         if(FD_ISSET(fileno(fp), &rset))     //input is readable
  33.         {
  34.             if((n = read(fileno(fp), buf, MAXLINE)) == 0)
  35.             {
  36.                 stdineof = 1;
  37.                 shutdown(sockfd, SHUT_WR);
  38.                 FD_CLR(fileno(fp), &rset);
  39.                 continue;
  40.             }
  41.             writen(sockfd, buf, n);
  42.         }
  43.     }
  44. }
str_echo.h
[cpp]  view plain copy
  1. #include <unistd.h>  
  2. #include <stdlib.h>  
  3. #include <stdio.h>  
  4. #include <string.h>  
  5. #include <errno.h>  
  6.   
  7. #define MAXLINE 4096  
  8.   
  9. void str_echo(int sockfd);  
str_echo.c
[cpp]  view plain copy
  1. #include "str_echo.h"  
  2.   
  3. void str_echo(int sockfd)  
  4. {  
  5.     ssize_t n;  
  6.     char buf[MAXLINE];  
  7.   
  8. again:  
  9.     while((n = read(sockfd, buf, MAXLINE)) > 0)  
  10.     {  
  11.         writen(sockfd, buf, n);  
  12.     }  
  13.       
  14.     if(n < 0 && errno == EINTR)  
  15.     {  
  16.         goto again;  
  17.     }  
  18.     else if(n < 0)  
  19.     {  
  20.         err_sys("str_echo: read error");  
  21.     }  
  22. }  
writen.h
[cpp]  view plain copy
  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <errno.h>  
  5.   
  6. ssize_t writen(int fd, const void*vptr, size_t n);  
writen.c
[cpp]  view plain copy
  1. #include "writen.h"  
  2.   
  3. ssize_t writen(int fd, const void*vptr, size_t n)  
  4. {  
  5.     size_t nleft;  
  6.     ssize_t nwritten;  
  7.     const char *ptr;  
  8.   
  9.     ptr = vptr;  
  10.   
  11.     nleft = n;  
  12.   
  13.     while(nleft > 0)  
  14.     {  
  15.         if((nwritten = write(fd, ptr, nleft)) <= 0)  
  16.         {  
  17.             if(nwritten < 0 && errno == EINTR)  
  18.             {  
  19.                 nwritten = 0;  
  20.             }  
  21.             else  
  22.             {  
  23.                 return(-1);  
  24.             }  
  25.         }  
  26.         nleft -= nwritten;  
  27.         ptr += nwritten;  
  28.     }  
  29.     return(n);  
  30. }  

readline.h

[cpp]  view plain copy
  1. #include <unistd.h>  
  2. #include <stdlib.h>  
  3. #include <errno.h>  
  4.   
  5. ssize_t readline(int fd, void* vptr, size_t maxlen);  
readline.c
[cpp]  view plain copy
  1. #include "readline.h"  
  2.   
  3. ssize_t readline(int fd, void* vptr, size_t maxlen)  
  4. {  
  5.     ssize_t n, rc;  
  6.     char c, *ptr;  
  7.     ptr = vptr;  
  8.   
  9.     for(n = 1; n < maxlen; n++)  
  10.     {      
  11.     again:  
  12.         if((rc = read(fd, &c, 1)) == 1)  
  13.         {  
  14.             *ptr++ = c;  
  15.             if(c == '\n')  
  16.             {  
  17.                 break;     
  18.             }     
  19.         }                          
  20.         else if(rc == 0)     
  21.         {  
  22.             *ptr = 0;  
  23.             return (n-1);     
  24.         }  
  25.         else  
  26.         {  
  27.             if(errno == EINTR)  
  28.             {  
  29.                 goto again;     
  30.             }  
  31.             return(-1);     
  32.         }     
  33.     }  
  34.     *ptr = 0;  
  35.     return(n);  
error.h
[cpp]  view plain copy
  1. #ifndef ERROR_H  
  2. #define ERROR_H  
  3.   
  4. #include <stdio.h>  
  5. #include <stdlib.h>  
  6. #include <string.h>  
  7. #include <stdarg.h>  
  8. #include <unistd.h>  
  9. #include <syslog.h>  
  10. #include <errno.h>  
  11. #include "constant.h"  
  12.   
  13. static void err_doit(intintconst char *, va_list);  
  14.   
  15. void err_ret(const char *fmt, ...);  
  16. void err_sys(const char *fmt, ...);  
  17. void err_dump(const char *fmt, ...);  
  18. void err_msg(const char *fmt, ...);  
  19. void err_quit(const char *fmt, ...);  
  20.   
  21. #endif  
error.c
[cpp]  view plain copy
  1. #include "error.h"  
  2.   
  3. int daemon_proc;        /* set nonzero by daemon_init() */  
  4.   
  5. static void err_doit(intintconst char *, va_list);  
  6.   
  7. /* Nonfatal error related to system call 
  8.  *  * Print message and return */  
  9.   
  10. void err_ret(const char *fmt, ...)  
  11. {  
  12.     va_list ap;  
  13.   
  14.     va_start(ap, fmt);  
  15.     err_doit(1, LOG_INFO, fmt, ap);  
  16.     va_end(ap);  
  17.     return;  
  18. }  
  19.   
  20. /* Fatal error related to system call 
  21.  *  * Print message and terminate */  
  22.   
  23. void err_sys(const char *fmt, ...)  
  24. {  
  25.     va_list ap;  
  26.     va_start(ap, fmt);  
  27.     err_doit(1, LOG_ERR, fmt, ap);  
  28.     va_end(ap);  
  29.     exit(1);  
  30. }  
  31.   
  32. /* Fatal error related to system call 
  33.  *  * Print message, dump core, and terminate */  
  34.   
  35. void err_dump(const char *fmt, ...)  
  36. {  
  37.     va_list ap;  
  38.     va_start(ap, fmt);  
  39.       
  40.     err_doit(1, LOG_ERR, fmt, ap);  
  41.       
  42.     va_end(ap);  
  43.       
  44.     abort();        /* dump core and terminate */  
  45.       
  46.     exit(1);        /* shouldn't get here */  
  47. }  
  48. /* Fatal error unrelated to system call 
  49.  *  * Print message and terminate */  
  50.   
  51. void err_quit(const char *fmt, ...)  
  52. {  
  53.     va_list ap;  
  54.     va_start(ap, fmt);  
  55.       
  56.     err_doit(0, LOG_ERR, fmt, ap);  
  57.       
  58.     va_end(ap);  
  59.       
  60.     exit(1);  
  61. }  
  62.   
  63. /* Print message and return to caller 
  64.  *  * Caller specifies "errnoflag" and "level" */  
  65.   
  66. static void err_doit(int errnoflag, int level, const char *fmt, va_list ap)  
  67. {  
  68.     int errno_save,n;  
  69.     char buf[MAXLINE + 1];  
  70.     errno_save = errno;        /* value caller might want printed */  
  71. #ifdef HAVE_VSNPRINTF  
  72.     vsnprintf(buf, MAXLINE, fmt, ap);    /* safe */  
  73. #else  
  74.     vsprintf(buf, fmt, ap);                    /* not safe */  
  75. #endif  
  76.     n = strlen(buf);  
  77.     if (errnoflag)  
  78.         snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));  
  79.     strcat(buf, "\n");  
  80.       
  81.     if (daemon_proc) {  
  82.         syslog(level, buf);  
  83.     }  
  84.     else   
  85.     {  
  86.         fflush(stdout);        /* in case stdout and stderr are the same */  
  87.   
  88.         fputs(buf, stderr);  
  89.         fflush(stderr);  
  90.     }  
  91.     return;  
  92. }  
constant.h
[cpp]  view plain copy
  1. #ifndef Constant_H  
  2. #define Constant_H  
  3.   
  4. #ifndef MAXLINE  
  5. #define MAXLINE 4096  
  6. #endif  
  7.   
  8. #ifndef LISTENQ  
  9. #define LISTENQ 1024  
  10. #endif  
  11.   
  12. #ifndef BUFFSIZE  
  13. #define BUFFSIZE 8092  
  14. #endif  
  15.   
  16. #endif  

makefile

[cpp]  view plain copy
  1. bins = tcpserv tcpcli  
  2. objs = tcpserv.o tcpcli.o str_echo.o str_cli.o writen.o readline.o error.o  
  3. srcs = tcpserv.c tcpcli.c str_echo.c str_echo.h str_cli.c str_cli.h \  
  4. writen.c writen.h readline.c readline.h error.c error.h  
  5.   
  6. $(bins):$(objs)  
  7.     gcc -o tcpserv tcpserv.o str_echo.o writen.o readline.o error.o  
  8.     gcc -o tcpcli tcpcli.o str_cli.o writen.o readline.o error.o  
  9.   
  10. $(objs):$(srcs)  
  11.     gcc -c tcpserv.c  
  12.     gcc -c tcpcli.c  
  13.     gcc -c str_echo.c str_echo.h error.h  
  14.     gcc -c str_cli.c str_cli.h  
  15.     gcc -c writen.c writen.h  
  16.     gcc -c readline.c readline.h  
  17.     gcc -c error.c error.h  
  18.   
  19. clean:  
  20.     rm -rf $(bins) *.o *.h.gch  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值