ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

select实现简单TCP通信(ubuntu 18.04)

2019-04-13 16:38:36  阅读:273  来源: 互联网

标签:18.04 int ntop sock TCP ubuntu sockfd writen include


一、服务器程序(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(1);
}

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(1);
                }
            }
            printf("%s\n", sock_ntop(addr, sizeof(addr)));
            write(fileno(stdout), buf, n);
            printf("\n");
        }
        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>\n", 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(1);
}

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(1);
                }
            }
            printf("%s\n", sock_ntop(addr, sizeof(addr)));
            write(fileno(stdout), buf, n);
            printf("\n");
        }
        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)
~                                  

 

标签:18.04,int,ntop,sock,TCP,ubuntu,sockfd,writen,include
来源: https://www.cnblogs.com/soldierback/p/10701684.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有