zoukankan      html  css  js  c++  java
  • select实现简单TCP通信(ubuntu 18.04)

    一、服务器程序(server.c) 

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/select.h>
    #include <netinet/in.h>
    #include <strings.h>
    
    #define SERV_PORT 9999
    #define MAXLINE 4096
    
    #define SA struct sockaddr
    
    int max(int, int);
    void proSession(FILE*, int, const struct sockaddr*);
    ssize_t writen(int, const void*, size_t);
    char *sock_ntop(const struct sockaddr*, socklen_t);
    
    int main(int argc, char *argv[]) {
        int listenfd, connfd;
        pid_t childpid;
        socklen_t clilen;
        struct sockaddr_in servaddr;
        struct sockaddr_in cliaddr;
        
        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, 1); /* 将套接字转换为监听套接字 */
    
        clilen = sizeof(cliaddr);
        if ( (connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) > 0) {
            proSession(stdin, connfd, (SA *)&cliaddr); /* 处理会话 */
        }
        exit(0);
    }
    
    void proSession(FILE *fp, int sockfd, const struct sockaddr *addr) {
        int maxfdp1, stdineof;
        fd_set rset;
        char buf[MAXLINE];
        int n;
    
        stdineof = 0; 
        FD_ZERO(&rset);
        for ( ; ; ) {
            if (stdineof == 0) {
                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)) {    /* 套接字描述符就绪 */
                if ( (n = read(sockfd, buf, MAXLINE)) == 0) {
                    if (stdineof == 1) {
                        return;
                    } else {
                        exit(0);
                    }
                }
                printf("%s
    ", sock_ntop(addr, sizeof(addr)));
                write(fileno(stdout), buf, n);
                printf("
    ");
            }
            if (FD_ISSET(fileno(fp), &rset)) { /* 输入描述符就绪 */
                if ( (n = read(fileno(fp), buf, MAXLINE)) == 0) {
                    stdineof = 1;
                    shutdown(sockfd, SHUT_WR); /* 发送 FIN */
                    FD_CLR(fileno(fp), &rset);
                    continue;
                }
                writen(sockfd, buf, n);
            }
        }
    }
    
    int max(int numberone, int numbertwo) {
        return ( (numberone >= numbertwo)?numberone:numbertwo);
    }

    二、客户端程序(client.c)

    #include <stdio.h>
    #include <stdlib.h>
    #include <strings.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    
    #define SA struct sockaddr
    #define SERV_PORT 9999
    #define MAXLINE 4096
    
    int max(int, int);
    void proSession(FILE*, int, const struct sockaddr*);
    ssize_t writen(int, const void*, size_t);
    char *sock_ntop(const struct sockaddr*, socklen_t);
    
    int main(int argc, char *argv[]) {
        pid_t childpid;
        int sockfd;
        struct sockaddr_in servaddr;
    
        if (argc != 2) {
            printf("usage: %s <IPaddress>
    ", argv[0]);
            exit(-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);
    
        if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) == 0) {
            proSession(stdin, sockfd, (SA *)&servaddr); /* 处理会话 */
        }
    
        exit(0);
    }
    
    void proSession(FILE *fp, int sockfd, const struct sockaddr* addr) {
        int maxfdp1, stdineof;
        fd_set rset;
        char buf[MAXLINE];
        int n;
    
        stdineof = 0; 
        FD_ZERO(&rset);
        for ( ; ; ) {
            if (stdineof == 0) {
                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)) {    /* 套接字描述符就绪 */
                if ( (n = read(sockfd, buf, MAXLINE)) == 0) {
                    if (stdineof == 1) {
                        return;
                    } else {
                        exit(0);
                    }
                }
                printf("%s
    ", sock_ntop(addr, sizeof(addr)));
                write(fileno(stdout), buf, n);
                printf("
    ");
            }
            if (FD_ISSET(fileno(fp), &rset)) { /* 输入描述符就绪 */
                if ( (n = read(fileno(fp), buf, MAXLINE)) == 0) {
                    stdineof = 1;
                    shutdown(sockfd, SHUT_WR); /* 发送 FIN */
                    FD_CLR(fileno(fp), &rset);
                    continue;
                }
                writen(sockfd, buf, n);
            }
        }
    }
    
    int max(int numberone, int numbertwo) {
        return ( (numberone >= numbertwo)?numberone:numbertwo);
    }

    三、服务器程序或客户端程序用到的程序

     (1)sock_ntop.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <netinet/in.h>
    #include <sys/un.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    
    char *sock_ntop(const struct sockaddr *sa, socklen_t salen) {
        
        char portstr[8];    
        static char str[128];
       
        switch (sa->sa_family) {
            case AF_INET: {
                struct sockaddr_in    *sin = (struct sockaddr_in *) sa;
    
                if (inet_ntop(AF_INET, &sin->sin_addr, str, 
                    sizeof(str)) == NULL) {
                    return(NULL);
                }
                if (ntohs(sin->sin_port) != 0) {
                    snprintf(portstr, sizeof(portstr), ":%d", 
                        ntohs(sin->sin_port));
                    strcat(str, portstr);
                }
                return(str);
            }
            case AF_INET6: {
                struct sockaddr_in6    *sin6 = (struct sockaddr_in6 *) sa;
    
                str[0] = '[';
                if (inet_ntop(AF_INET6, &sin6->sin6_addr, str + 1, 
                    sizeof(str) - 1) == NULL) {
                    return(NULL);
                }
                if (ntohs(sin6->sin6_port) != 0) {
                    snprintf(portstr, sizeof(portstr), "]:%d",
                        ntohs(sin6->sin6_port));
                    strcat(str, portstr);
                    return(str);
                }
                return (str + 1);
            }
            case AF_UNIX: {
                struct sockaddr_un    *unp = (struct sockaddr_un *) sa;
    
                if (unp->sun_path[0] == 0) {
                    strcpy(str, "(no pathname bound)");
                } else {
                    snprintf(str, sizeof(str), "%s", unp->sun_path);
                }
                return(str);
            }
            default: {
                snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d",
                     sa->sa_family, salen);
                return(str);
            }
        }
        return (NULL);
    }

     (2)writen.c

    #include <unistd.h>
    #include <errno.h>
    
    ssize_t writen(int fd, const void *vptr, size_t n) {
        size_t nleft;
        ssize_t nwriten;
        const char *ptr;
    
        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
            if ( (nwriten = write(fd, ptr, nleft)) <= 0) {
                if (nwriten < 0 && errno) {
                    nwriten = 0; /* call write() again */
                } else {
                    return (-1); /* error */
                }
            } 
            nleft -= nwriten;
            ptr += nwriten;
        }
        return (n - nwriten);
    }

    四、Makefile文件

     (1)服务器 

    target=server
    cc=gcc
    $(target):writen.o server.o sock_ntop.o
        $(cc)  sock_ntop.o writen.o server.o -o $(target)
    sock_ntop.o:sock_ntop.c
        $(cc) -c sock_ntop.c -o sock_ntop.o
    writen.o:writen.c
        $(cc) -c writen.c -o writen.o
    server.o:server.c
        $(cc) -c server.c -o server.o
    clean:
        rm -rf *.o $(target)

     (2)客户端

    target=client
    cc=gcc
    $(target):writen.o client.o sock_ntop.o
        $(cc)  writen.o client.o sock_ntop.o -o $(target)
    writen.o:writen.c
        $(cc) -c writen.c -o writen.o
    server.o:client.c
        $(cc) -c client.c -o client.o
    sock_ntop.o:sock_ntop.c
        $(cc) -c sock_ntop.c -o sock_ntop.o
    clean:
        rm -rf *.o $(target)
    ~                                  
  • 相关阅读:
    网页中输出漂亮格式的Php数组神器
    从对轮播图的封装中体会 面对接口 编程的思想
    UITabBarController 详解
    UINavigationController 详解
    UITabBarController 和 UINavigationController 的详解
    【iOS开发】canOpenURL: failed for URL
    SDK里报错[NSConcreteMutableData wbsdk_base64EncodedString]
    UIScrollView 几乎所有的属性和方法
    oracle服务器和客户端字符集的查看和修改
    查看、修改oracle字符集,查看oracle版本
  • 原文地址:https://www.cnblogs.com/soldierback/p/10701684.html
Copyright © 2011-2022 走看看