Chinaunix首页 | 论坛 | 博客
  • 博客访问: 277618
  • 博文数量: 65
  • 博客积分: 3091
  • 博客等级: 中校
  • 技术积分: 705
  • 用 户 组: 普通用户
  • 注册时间: 2005-01-25 09:44
文章存档

2013年(2)

2012年(11)

2011年(12)

2010年(13)

2009年(15)

2008年(12)

分类: 系统运维

2010-01-13 16:31:27

/*
 * name: net_slct.c CEP: Communication End-Point
 * written by saodrin zhang for test
 */
#include
#include
#include
#include

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

#include
#include
#include
#include

#define UINT16 unsigned short int

#ifndef INPORT_ANY
#define INPORT_ANY      0
#endif

#define SVC_PORT        9999

typedef struct NET_INFO_T
{
    int fd;
    unsigned long inet_peer_addr;
    UINT16 inet_peer_port;
}NET_INFO;

int main_serv(int argc, char *argv[]);
int main_clnt(int argc, char *argv[]);

int main(int argc, char *argv[])
{
    int ret;

    if (argc == 1)
        ret = main_serv(argc, argv);
    else
        ret = main_clnt(argc, argv);

    return ret;
}

#define MAX_CNCT_NUM 8
#define BUF_SIZE 256

int main_serv(int argc, char *argv[])
{
    int ret, i, k, n;
    int len;
    int inp_fd, sockfd, cnctfd, sfd, dgrmfd, maxfd;
    int num, entry; /* clntfd[], clntnum */
    struct NET_INFO_T netinfo[MAX_CNCT_NUM];

    int opts, sndFlag;
    fd_set readfds, writefds;
    struct sockaddr_in bindaddr;  //servaddr
    struct sockaddr_in cnctaddr;  //clntaddr
    struct sockaddr_in intfaddr; 
    struct timeval timeout;

    char text[BUF_SIZE], buf[BUF_SIZE];
    char sBuf[MAX_CNCT_NUM][BUF_SIZE];

    maxfd = 0;
    /*inp_fd = open("/dev/tty", O_RDONLY | O_NONBLOCK);*/
    inp_fd = fileno(stdin);
    printf("Inp_fd is %d\n", inp_fd); /* assert(inp_fd >= 0); */
    fcntl(inp_fd, F_SETFL, fcntl(inp_fd, F_GETFL) | O_NONBLOCK);

    /* create TCP socket, assign the Protocol Family for communication */
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("TCP: socket create error!\n");
        return -1;
    }

    memset(&bindaddr, 0, sizeof(struct sockaddr_in));
    /* AF_INET: Address Family */
    bindaddr.sin_family = AF_INET;
    /* INADDR_ANY: address of any interface owned by the host */
    bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    bindaddr.sin_port = htons(SVC_PORT);
    bzero(&(bindaddr.sin_zero), 8); /*  */

    /* 将用于监听的插接口sockfd设置为地址重用方式  */
    opts = 1; /* option enable */
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &opts, sizeof(opts)) < 0)
    {
        close(sockfd);
        printf("TCP: setsockopt error!\n");
        return -1;
    }

    if (bind(sockfd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in)) < 0)
    {
        printf("TCP: bind error!\n");
        return -1;
    }

    /* create UDP socket */
    if ((sfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
    {
        printf("UDP: socket create error!\n");
        return -1;
    }

    memset(&bindaddr, 0, sizeof(struct sockaddr_in));
    /* AF_INET: Address Family */
    bindaddr.sin_family = AF_INET;
    /* INADDR_ANY: address of any interface owned by the host */
    bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    bindaddr.sin_port = htons(SVC_PORT);
    bzero(&(bindaddr.sin_zero), 8); /*  */

    /* 置 socket 为地址重用方式  */
    opts = 1; /* option enable */
    if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *) &opts, sizeof(opts)) < 0)
    {
        close(sfd);
        printf("UDP setsockopt error!\n");
        return -1;
    }

    if (bind(sfd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in)) < 0)
    {
        printf("UDP: bind error!\n");
        return -1;
    }

    for (i = 0; i < MAX_CNCT_NUM; i++)
    {
        netinfo[i].fd = -1; /* -1 indicates available entry for client fd */
    }

    listen(sockfd, 5);
    entry = 0;
    num = 0;

    if (inp_fd >= 0)
    {
        fcntl(inp_fd, F_SETFL, O_NONBLOCK);
    }
    if (sockfd >= 0)
    {
        fcntl(sockfd, F_SETFL, O_NONBLOCK);
    }
    if (sfd >= 0)
    {
        fcntl(sfd, F_SETFL, O_NONBLOCK);
    }

    text[0] = '\0';
    for (i = 0; i < MAX_CNCT_NUM; i++) sBuf[i][0] = '\0';
    sndFlag = 0;
    while (1) /* 轮循、并发或(多路)复用 */
    {
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;

        FD_ZERO(&readfds);
        FD_ZERO(&writefds);

        FD_SET(inp_fd, &readfds);
        maxfd = inp_fd;

        if (sockfd >= 0)
        {
            FD_SET(sockfd, &readfds);
            maxfd = sockfd > maxfd ? sockfd : maxfd;
        }

        if (sfd >= 0)
        {
            FD_SET(sfd, &readfds);
            maxfd = sfd > maxfd ? sfd : maxfd;
        }

        for (i = 0, n = 0; i < MAX_CNCT_NUM && n < num; i++)
        {
            if (netinfo[i].fd > 0)
            {
                FD_SET(netinfo[i].fd, &readfds);
                if (sBuf[i][0] != '\0')
                {
                    /* printf("WR: FD_SET...\n"); */
                    FD_SET(netinfo[i].fd, &writefds);
                }

                maxfd = netinfo[i].fd > maxfd ? netinfo[i].fd : maxfd;
                n++;
            }
        }

        ret = select(maxfd+1, &readfds, &writefds, NULL, &timeout);

        //select error when ret = -1
        if (ret == -1) printf("select error!\n");

        //time out when ret = 0
        //if (ret == 0) printf("select time out.\n");

        //data coming when ret>0
        if (ret > 0)
        {
            /* printf("----------------\n"); */
            if (FD_ISSET(inp_fd, &readfds))
            {
                /*i = read(inp_fd, &ch, 1);
                if('\n' == ch) continue;
                else printf("Input is %c\n", ch);*/
                n = read(inp_fd, buf, BUF_SIZE);
                if (n >= 0)
                {
                    i = 0;
                    k = 0;
                    while (i < n && isspace(buf[i])) i++;
                    while (i < n && !isspace(buf[i]))
                    {
                        buf[k] = buf[i];
                        k++;
                        i++;
                    }
                    i = k < BUF_SIZE ? k : BUF_SIZE-1;
                    buf[i] = '\0';
                    if (i > 0) strcpy(text, buf);
                }
                else
                {
                    printf("RD STDIN error!\n");
                    break;
                }

                if ('\0' == buf[0]) continue;
                else printf("Inputed: %s\n", text);

                if ('q' == text[0])
                {
                    /* close all I/O descriptors and quit */
                    break;
                }
            }

            if (FD_ISSET(sockfd, &readfds))
            {
                len = sizeof(struct sockaddr_in);
                cnctfd = accept(sockfd, (struct sockaddr *)&cnctaddr, (socklen_t *)&len);
                if (cnctfd < 0)
                {
                    if (cnctfd != EWOULDBLOCK && \
                            cnctfd != ECONNABORTED && \
                            cnctfd != EINTR)
                    {
                        shutdown(sockfd, SHUT_RDWR);
                        sockfd = -1; /* error fd */
                        close(sockfd);
                    }
                }
                else
                {
                    len = sizeof(struct sockaddr_in);
                    getsockname(cnctfd, (struct sockaddr *)&intfaddr, (socklen_t *)&len);
                    printf("=>: Connection from %s:%d on %s:%d\n", \
                           inet_ntoa(cnctaddr.sin_addr), ntohs(cnctaddr.sin_port), \
                           inet_ntoa(intfaddr.sin_addr), ntohs(intfaddr.sin_port));
                    if (num == MAX_CNCT_NUM)
                    {
                        shutdown(cnctfd, SHUT_RDWR);
                        close(cnctfd);
                    }
                    else
                    {
                        fcntl(cnctfd, F_SETFL, O_NONBLOCK);
                        netinfo[entry].fd = cnctfd; /* client fd */
                        netinfo[entry].inet_peer_addr = cnctaddr.sin_addr.s_addr;
                        netinfo[entry].inet_peer_port = cnctaddr.sin_port;
                        for (i = 0; i < MAX_CNCT_NUM; i++)
                        {
                            if (netinfo[i].fd < 0)
                            {
                                entry = i;
                                break;
                            }
                        }
                        /* assert(i < MAX_CNCT_NUM); */
                        printf("Accept TCP fd = %d\n", cnctfd);
                        num++;
                    } /* end if (num == MAX_CNCT_NUM) else */
                } /* end if (cnctfd < 0) else */
            } /* end if (FD_ISSET(sockfd, &readfds)) */

            if (FD_ISSET(sfd, &readfds))
            {
                len = sizeof(struct sockaddr_in);
                n = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *)&cnctaddr, (socklen_t *)&len);
                if (n > 0)
                {
                    len = sizeof(struct sockaddr_in);
                    getsockname(cnctfd, (struct sockaddr *)&intfaddr, (socklen_t *)&len);
                    printf("->: Datagraph from %s:%d on %s:%d\n", \
                           inet_ntoa(cnctaddr.sin_addr), ntohs(cnctaddr.sin_port), \
                           inet_ntoa(intfaddr.sin_addr), ntohs(intfaddr.sin_port));
                    buf[n] = '\0';
                    for (i = 0, k = 0; i < MAX_CNCT_NUM && k < num; i++)
                    {
                        if (netinfo[i].fd >= 0)
                        {
                            if (netinfo[i].inet_peer_addr == cnctaddr.sin_addr.s_addr && \
                                    netinfo[i].inet_peer_port == cnctaddr.sin_port)
                            {
                                len = sizeof(int);
                                if (getsockopt(netinfo[i].fd, SOL_SOCKET, SO_TYPE, (char *)&opts, (socklen_t *)&len) == 0 && \
                                        opts == SOCK_DGRAM)
                                    break;
                            }
                            k++;
                        }
                    }
                    /* printf("DEBUG: i = %d, k = %d, num = %d\n", i, k, num); */
                    if (i >= MAX_CNCT_NUM || k >= num) /* not found */
                    {
                        if (num >= MAX_CNCT_NUM) /* no more resource */
                        {
                            printf("UDP discard: %s", buf);
                        }
                        else
                        {
                            /* create UDP socket and set it's endpoint */
                            dgrmfd = socket(PF_INET, SOCK_DGRAM, 0);
                            memset(&bindaddr, 0, sizeof(struct sockaddr_in));
                            bindaddr.sin_family = AF_INET;
                            bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* better to use the address that data arrived.
                                                                             Ref to IP_RECVDSTADDR */
                            bindaddr.sin_port = htons(SVC_PORT);
                            bzero(&(bindaddr.sin_zero), 8);
                            opts = 1; /* option enable */
                            setsockopt(dgrmfd, SOL_SOCKET, SO_REUSEADDR, (char *) &opts, sizeof(opts));
                            /* 在允许使用完全重复的 cep 对 udp socket 进行绑定的系统中,两侧的 cep 都匹配的 socket 会被优先选用来进行通讯 */
                            bind(dgrmfd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in));
                            len = sizeof(struct sockaddr_in);
                            connect(dgrmfd, (struct sockaddr *)&cnctaddr, len);
                            /* add the cnctfd to the CEP array */
                            fcntl(dgrmfd, F_SETFL, O_NONBLOCK);
                            /* assert(entry < MAX_CNCT_NUM); */
                            netinfo[entry].fd = dgrmfd; /* client fd */
                            netinfo[entry].inet_peer_addr = cnctaddr.sin_addr.s_addr;
                            netinfo[entry].inet_peer_port = cnctaddr.sin_port;
                            /* use the supplied fd to communicate later */
                            printf("Supply UDP fd = %d\n", dgrmfd);
                            if (buf[0] != '\0' && text[0] != '\0')
                            {
                                sprintf(sBuf[entry], "%s + ", text);
                                strcat(sBuf[entry], buf);
                            }
                            for (i = 0; i < MAX_CNCT_NUM; i++)
                            {
                                if (netinfo[i].fd < 0)
                                {
                                    entry = i;
                                    break;
                                }
                            }
                            /* assert(i < MAX_CNCT_NUM); */
                            num++;
                        } /* end if (num >= MAX_CNCT_NUM) else */
                    }
                    else
                    {
                        /* printf("UDP socket found: %d\n", netinfo[i].fd); */
                        if (buf[0] != '\0' && text[0] != '\0')
                        {
                            sprintf(sBuf[i], "%s + ", text);
                            strcat(sBuf[i], buf);
                        }
                    } /* end if (i >= MAX_CNCT_NUM || k >= num) else */
                }
                else if (n == 0)
                {
                    printf("UDP RD: peer is closed!\n");
                    for (i = 0, k = 0; i < MAX_CNCT_NUM && k < num; i++)
                    {
                        if (netinfo[i].fd >= 0 && netinfo[i].inet_peer_addr == cnctaddr.sin_addr.s_addr)
                        {
                            shutdown(netinfo[i].fd, SHUT_RDWR);
                            close(netinfo[i].fd);
                            netinfo[i].fd = -1;
                            entry = i < entry ? i : entry;
                            num--;
                        }
                    }
                }
                else
                {
                    shutdown(sfd, SHUT_RDWR);
                    close(sfd);
                    sfd = -1;
                } /* end else if (n == 0) else */
                //k = sendto(sfd, buf, n, 0, (struct sockaddr *)&cnctaddr, sizeof(struct sockaddr));
            } /* end if (FD_ISSET(sfd, &readfds)) */

            for (i = 0, k = 0; i < MAX_CNCT_NUM && k < num; i++)
            {
                if (netinfo[i].fd > 0 && FD_ISSET(netinfo[i].fd, &readfds))
                {
                    n = read(netinfo[i].fd, buf, BUF_SIZE);
                    if (n > 0)
                    {
                        buf[n] = '\0';
                        printf("RD sockfd[%d]: %s", i, buf);
                        if (buf[0] != '\0' && text[0] != '\0')
                        {
                            sprintf(sBuf[i], "%s + ", text);
                            strcat(sBuf[i], buf);
                        }
                        k++;
                    }
                    else if (n == 0)
                    {
                        printf("RD sockfd[%d]: peer is closed.\n", i);
                        shutdown(netinfo[i].fd, SHUT_RDWR);
                        close(netinfo[i].fd);
                        sBuf[i][0] = '\0';
                        netinfo[i].fd = -1;
                        entry = i < entry ? i : entry;
                        num--;
                    }
                    else
                    {
                        switch (errno)
                        {
                        case EAGAIN:
#if EWOULDBLOCK != EAGAIN
                        case EWOULDBLOCK:
#endif
                            k++;
                            break;
                        case EINTR:
                            /* we were stopped _before_ we had a connection */
                        case ECONNABORTED: /* this is a FreeBSD thingy */
                            /* we were stopped _after_ we had a connection */
                            k++;
                            break;
                        case EMFILE: /* out of fds */
                            k++;
                            break;
                        default:
                            perror("readxxxx");
                            printf("errno %d: i = %d, k = %d, sockfd = %d\n", errno, i, k, netinfo[i].fd);
                            shutdown(netinfo[i].fd, SHUT_RDWR);
                            close(netinfo[i].fd);
                            netinfo[i].fd = -1;  /* close it */
                            entry = i < entry ? i : entry;
                            num--;
                            break;
                        } /* end switch (errno) */
                    } /* end if (n > 0) */
                } /* end if (netinfo[i].fd > 0 && FD_ISSET(netinfo[i].fd, &readfds) */
            } /* end for (...; i < MAX_CNCT_NUM && k < num; ...) */

            for (i = 0, k = 0; i < MAX_CNCT_NUM && k < num; i++)
            {
                if (netinfo[i].fd > 0 && FD_ISSET(netinfo[i].fd, &writefds))
                {
                    len = strlen(sBuf[i]);
                    n = write(netinfo[i].fd, sBuf[i], len);
                    if (n > 0) /* assert(n == len); */
                    {
                        printf("WR sockfd[%d]: %s", i, sBuf[i]);
                        sBuf[i][0] = '\0';
                        k++;
                    }
                    else if (n == 0)
                    {
                        printf("WR sockfd[%d]: peer is closed.", i);
                        shutdown(netinfo[i].fd, SHUT_RDWR);
                        close(netinfo[i].fd);
                        sBuf[i][0] = '\0';
                        netinfo[i].fd = -1;
                        entry = i < entry ? i : entry;
                        num--;
                    }
                    else /* error */
                    {
                        switch (errno)
                        {
                        case EAGAIN:
#if EWOULDBLOCK != EAGAIN
                        case EWOULDBLOCK:
#endif
                            k++;
                            break;
                        case EINTR:
                            /* we were stopped _before_ we had a connection */
                        case ECONNABORTED: /* this is a FreeBSD thingy */
                            /* we were stopped _after_ we had a connection */
                            k++;
                            break;
                        case EMFILE: /* out of fds */
                            k++;
                            break;
                        default:
                            perror("write");
                            shutdown(netinfo[i].fd, SHUT_RDWR);
                            close(netinfo[i].fd);
                            netinfo[i].fd = -1;  /* close it */
                            entry = i < entry ? i : entry;
                            num--;
                            break;
                        } /* end switch (errno) */
                    } /* end if (n > 0) */
                } /* end if (netinfo[i].fd > 0 && FD_ISSET(netinfo[i].fd, &readfds)) */
            } /* end for (...; i < MAX_CNCT_NUM && k < num; ...) */
        } /* end if (ret > 0) */
    }
    return 0;
}

int main_clnt(int argc, char *argv[])
{
    int ret, i, n;
    int len;
    int inp_fd, sockfd, sfd, cofd, dgfd, maxfd;

    int opts, sndFlag;
    fd_set readfds, writefds;
    struct sockaddr_in bindaddr;   //local client address
    struct sockaddr_in cnctaddr;   //remote server address
    struct sockaddr_in intfaddr;
    char   intfname[16];
    struct timeval timeout;
    struct hostent    *host;
    struct in_addr servAddr;
    unsigned long servIP;

    char text[BUF_SIZE], buf[BUF_SIZE];

    if (argc < 2)
    {
        return -1;
    }

    host = gethostbyname(argv[1]); /* name is an ASCII or digital notation */
    if (host != NULL)
    {
        memcpy(&servAddr, host->h_addr_list[0], sizeof(struct in_addr));
        servIP = ntohl(servAddr.s_addr);
        printf("destIP = 0x%x\n", servIP);
    }
    else
    {
        printf("Error: gethostbyname\n");
        return -1;
    }

    /*inp_fd = open("/dev/tty", O_RDONLY | O_NONBLOCK);*/
    inp_fd = fileno(stdin);
    printf("Inp_fd is %d\n", inp_fd); /* assert(inp_fd >= 0); */
    fcntl(inp_fd, F_SETFL, fcntl(inp_fd, F_GETFL) | O_NONBLOCK);
    maxfd = inp_fd;

    /* create TCP socket, assign the Protocol Family for communication */
    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
    {
        printf("TCP: socket create error!\n");
        return -1;
    }

    memset(&bindaddr, 0, sizeof(struct sockaddr_in));
    /* AF_INET: Address Family */
    bindaddr.sin_family = AF_INET;
    /* INADDR_ANY: address of any interface owned by the host */
    bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    bindaddr.sin_port = htons(0); /* use SVC_PORT to enable only one client per home */
    bzero(&(bindaddr.sin_zero), 8); /*  */

    /* 置 socket 重新使用  */
    opts = 1; /* option enable */
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *) &opts, sizeof(opts)) < 0)
    {
        close(sockfd);
        printf("setsockopt error!\n");
        return -1;
    }
   
    if (SVC_PORT == ntohs(bindaddr.sin_port))
    {
        if ((n = bind(sockfd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in))) == -1)
        {
            printf("TCP: Default CEP is already used...\n");
            /* mask the following code to enable only one client instance */
            bindaddr.sin_port = htons(0); /* INPORT_ANY */
               n = bind(sockfd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in));
        }
    }
    else
    {
        n = bind(sockfd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in));
    }
  
    if (n == -1)
    {
        printf("TCP bind error!\n");
        return -1;
    }
    else
    {
        len = sizeof(struct sockaddr_in);
        /* getsockname() is used to get the locally-bound endpoint on a bind()'d, connect()'d
         * or accept()'d socket. If the socket is bind()'d with INADDR_ANY and not connect()'d,
         * the address value is unspecified.
         * see also: getpeername()
         */
        if (0 == getsockname(sockfd, (struct sockaddr *)&intfaddr, (socklen_t *)&len))
        {
            printf("TCP bind on port %d\n", ntohs(intfaddr.sin_port));
        }
        else
        {
            printf("TCP bind on unknown port.\n");
        }
    }
   
    memset(&cnctaddr, 0, sizeof(struct sockaddr_in));
    /* AF_INET: Address Family */
    cnctaddr.sin_family = AF_INET;
    /* host address to connect */
    cnctaddr.sin_addr.s_addr = htonl(servIP);
    cnctaddr.sin_port = htons(SVC_PORT);
    bzero(&(cnctaddr.sin_zero), 8); /*  */
    if (connect(sockfd, (struct sockaddr *)&cnctaddr, sizeof(struct sockaddr_in)) == -1)
    {
        /* if (errno == EADDRINUSE) ...*/
        perror("TCP connect");
        return -1;
    }
    else
    {
        len = sizeof(struct sockaddr_in);
        if (0 == getsockname(sockfd, (struct sockaddr *)&intfaddr, (socklen_t *)&len))
        {
            inet_ntop(AF_INET, &intfaddr.sin_addr, intfname, 16);
            printf("TCP Connect to %s:%d on interface %s with port %d\n", \
                   inet_ntoa(cnctaddr.sin_addr), ntohs(cnctaddr.sin_port), \
                   intfname, ntohs(intfaddr.sin_port));
        }
        cofd = sockfd;
    }

    /* create UDP socket */
    if ((sfd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
    {
        printf("UDP: socket create error!\n");
        return -1;
    }

    memset(&bindaddr, 0, sizeof(struct sockaddr_in));
    /* AF_INET: Address Family */
    bindaddr.sin_family = AF_INET;
    /* INADDR_ANY: address of any interface owned by the host */
    bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    bindaddr.sin_port = htons(SVC_PORT);
    bzero(&(bindaddr.sin_zero), 8); /*  */

    /* sfd为UDP插接口,不要设置成地址重用方式;否则当多个插接口使用相同的cep进行 */
    /* 通讯时(绑定和连接返回正常),不能正常收发数据  */
    /* (对TCP插接口,当使用相同的cep绑定时,即使设置成地址重用方式也会返回错误) */
    //opts = 1; /* option enable */
    //if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char *) &opts, sizeof(opts)) < 0)
    //{
    //    close(sfd);
    //    printf("setsockopt error!\n");
    //    return -1;
    //}

    if (bind(sfd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in)) == -1)
    {
        printf("UDP: Default CEP is already used...\n");
        bindaddr.sin_port = htons(0); /* INPORT_ANY */
        if (bind(sfd, (struct sockaddr *)&bindaddr, sizeof(struct sockaddr_in)) == -1)
        {
            printf("UDP bind error!\n");
            return -1;
        }
        else
        {
            len = sizeof(struct sockaddr_in);
            if (0 == getsockname(sfd, (struct sockaddr *)&intfaddr, (socklen_t *)&len))
            {
                printf("UDP bind on port %d\n", ntohs(intfaddr.sin_port));
            }
            else
            {
                printf("UDP bind on unknown port.\n");
            }
        }
    }
    else
    {
        printf("UDP Bind on Default CEP port %d.\n", ntohs(bindaddr.sin_port));
    }

    memset(&cnctaddr, 0, sizeof(struct sockaddr_in));
    /* AF_INET: Address Family */
    cnctaddr.sin_family = AF_INET;
    /* host address to connect */
    cnctaddr.sin_addr.s_addr = htonl(servIP);
    cnctaddr.sin_port = htons(SVC_PORT);
    bzero(&(cnctaddr.sin_zero), 8); /*  */
    if (connect(sfd, (struct sockaddr *)&cnctaddr, sizeof(struct sockaddr_in)) == -1)
    {
        /* if (errno == EADDRINUSE) ...*/
        perror("UDP connect");
        return -1;
    }
    else
    {
        len = sizeof(struct sockaddr_in);
        if (0 == getsockname(sfd, (struct sockaddr *)&intfaddr, (socklen_t *)&len))
        {
            inet_ntop(AF_INET, &intfaddr.sin_addr, intfname, 16);
            printf("UDP Connect to %s:%d on interface %s with port %d\n", \
                   inet_ntoa(cnctaddr.sin_addr), ntohs(cnctaddr.sin_port), \
                   intfname, ntohs(intfaddr.sin_port));
        }
        dgfd = sfd;
    }

    text[0] = '\0';
    sndFlag = 0;
    maxfd = dgfd > cofd ? dgfd : cofd;
    while (1)
    {
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;

        FD_ZERO(&readfds);
        FD_ZERO(&writefds);

        FD_SET(inp_fd, &readfds);
        if (cofd > 0)
        {
            FD_SET(cofd, &readfds);
            maxfd = cofd > maxfd ? cofd : maxfd;
        }
        if (dgfd > 0)
        {
            FD_SET(dgfd, &readfds);
            maxfd = dgfd > maxfd ? dgfd : maxfd;
        }

        if (sndFlag != 0)
        {
            FD_SET(cofd, &writefds);
            FD_SET(dgfd, &writefds);
        }

        ret = select(maxfd+1, &readfds, &writefds, NULL, &timeout);

        //select error when ret = -1
        if (ret == -1) printf("select error\n");

        //time out when ret = 0
        //if (ret == 0) printf("select time out\n");

        //data coming when ret>0
        if (ret > 0)
        {
            if (FD_ISSET(inp_fd, &readfds))
            {
                /*i = read(inp_fd, &ch, 1);
                if('\n' == ch) continue;
                else printf("Input is %c\n", ch);*/
                n = read(inp_fd, text, BUF_SIZE);
                if (n >= 0)
                {
                    text[n] = '\0';
                }
                else
                {
                    printf("RD STDIN error!\n");
                    text[0] = '\0';
                }

                if ('\n' == text[0]) continue;
                else printf("Inputed: %s", text);

                if ('q' == text[0]) break;
                else sndFlag = 1;
            }

            if (FD_ISSET(cofd, &readfds))
            {
                n = recv(cofd, buf, BUF_SIZE, MSG_DONTROUTE);
                if (n > 0)
                {
                    buf[n] = '\0';
                    printf("TCP Recv OK: %s", buf);
                }
                else if (n == 0) /* peer is closed */
                {
                    printf("TCP: Peer is closed ...\n");
                    shutdown(cofd, SHUT_RDWR);
                    close(cofd);
                    break;
                }
                else
                {
                    printf("TCP Recv error!\n");
                }
            }

            if (FD_ISSET(cofd, &writefds))
            {
                if ((n = strlen(text)) > 0)
                {
                    if ((i = send(cofd, text, n, MSG_DONTROUTE)) != n)
                    {
                        printf("TCP: Try to send again...\n");
                        sndFlag = 1;
                    }
                    else
                    {
                        printf("TCP Send OK: %s", text);
                        sndFlag = 0;
                    }
                }
                else
                {
                    sndFlag = 0; /* FD_CLR(cofd, &writefds); */
                    printf("TCP: Nothing to be sent\n");
                    if ((i = write(cofd, "...\n", 4)) != 4)
                        perror("Test write");
                } /* end if ((n = strlen(text)) > 0) */
            } /* end if (FD_ISSET(cofd, &writefds)) */

            if (FD_ISSET(dgfd, &readfds))
            {
                n = recv(dgfd, buf, BUF_SIZE, MSG_DONTROUTE);
                if (n > 0)
                {
                    buf[n] = '\0';
                    printf("UDP Recv OK: %s", buf);
                }
                else if (n == 0) /* peer is closed */
                {
                    printf("UDP: Peer is closed ...\n");
                    shutdown(dgfd, SHUT_RDWR);
                    close(dgfd);
                    break;
                }
                else
                {
                    printf("UDP Recv error!\n");
                }
            }

            if (FD_ISSET(dgfd, &writefds))
            {
                if ((n = strlen(text)) > 0)
                {
                    if ((i = send(dgfd, text, n, MSG_DONTROUTE)) != n)
                    {
                        printf("UDP: Try to send again...\n");
                        sndFlag = 1;
                    }
                    else
                    {
                        printf("UDP Send OK: %s", text);
                        sndFlag = 0;
                    }
                }
                else
                {
                    sndFlag = 0; /* FD_CLR(cofd, &writefds); */
                    printf("UDP: Nothing to be sent\n");
                    if ((i = write(cofd, "...\n", 4)) != 4)
                        perror("Test write");
                } /* end if ((n = strlen(text)) > 0) */
            } /* end if (FD_ISSET(dgfd, &writefds)) */
        } /* end if (ret > 0) */
    } /* end while (1) */

    return ret;
}

/* -------------------------------------------------------------------  */
#if 0
/*
 * recvfromto    Like recvfrom, but also stores the destination
 *        IP address. Useful on multihomed hosts.
 *
 *        Should work on Linux and BSD.
 *
 *        Copyright (C) 2002 Miquel van Smoorenburg.
 *
 *        This program is free software; you can redistribute it and/or
 *        modify it under the terms of the GNU Lesser General Public
 *        License as published by the Free Software Foundation; either
 *        version 2 of the License, or (at your option) any later version.
 */

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

/* Remove this when autoconf can detect this. */
#if defined(IP_PKTINFO) && !defined(HAVE_IP_PKTINFO)
#  define HAVE_IP_PKTINFO 1
#elif defined(IP_RECVDSTADDR) && !defined(HAVE_IP_RECVDSTADDR)
#  define HAVE_IP_RECVDSTADDR
#endif

int recvfromto(int s, void *buf, size_t len, int flags,
               struct sockaddr *from, socklen_t *fromlen,
               struct sockaddr *to, socklen_t *tolen)
{
    struct msghdr msgh;
    struct cmsghdr *cmsg;
    struct iovec iov;
    char cbuf[1024];
    int opt, err;

    /*
     *    If from or to are set, they must be big enough
     *    to store a struct sockaddr_in.
     */
    if ((from && (!fromlen || *fromlen < sizeof(struct sockaddr_in))) ||
            (to   && (!tolen   || *tolen   < sizeof(struct sockaddr_in))))
    {
        errno = EINVAL;
        return -1;
    }
    if (tolen) *tolen = 0;

#ifdef HAVE_IP_PKTINFO
    /*
     *    IP_PKTINFO doesn't provide sin_port so we have to
     *    retrieve it using getsockname().
     */
    if (to)
    {
        struct sockaddr_in si;
        socklen_t l = sizeof(si);

        ((struct sockaddr_in *)to)->sin_family = AF_INET;
        ((struct sockaddr_in *)to)->sin_port = 0;
        l = sizeof(si);
        if (getsockname(s, (struct sockaddr *)&si, &l) == 0)
        {
            ((struct sockaddr_in *)to)->sin_port = si.sin_port;
            ((struct sockaddr_in *)to)->sin_addr = si.sin_addr;
        }
        *tolen = sizeof(struct sockaddr_in);
    }
#endif

    /* Set MSG_DONTWAIT if O_NONBLOCK was set. */
    if (fcntl(s, F_GETFL) & O_NONBLOCK) flags |= MSG_DONTWAIT;

    /* Set up iov and msgh structures. */
    iov.iov_base = buf;
    iov.iov_len  = len;
    msgh.msg_control = cbuf;
    msgh.msg_controllen = sizeof(cbuf);
    msgh.msg_name = from;
    msgh.msg_namelen = fromlen ? *fromlen : 0;
    msgh.msg_iov  = &iov;
    msgh.msg_iovlen = 1;

#ifdef HAVE_IP_PKTINFO
    /* Set the IP_PKTINFO option (Linux). */
    opt = 1;
    setsockopt(s, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
#endif

#ifdef HAVE_IP_RECVDSTADDR
    /* Set the IP_RECVDSTADDR option (BSD). */
    opt = 1;
    setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt));
#endif

    /* Receive one packet. */
    err = recvmsg(s, &msgh, flags);
    if (fromlen) *fromlen = msgh.msg_namelen;

    /* Process auxiliary received data in msgh */
    for (cmsg = CMSG_FIRSTHDR(&msgh);
            cmsg != NULL && cmsg->cmsg_len >= sizeof(*cmsg);
            cmsg = CMSG_NXTHDR(&msgh,cmsg))
    {
#ifdef HAVE_IP_PKTINFO
        if (cmsg->cmsg_level == SOL_IP
                && cmsg->cmsg_type == IP_PKTINFO)
        {
            struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg);
            if (to)
            {
                ((struct sockaddr_in *)to)->sin_addr = i->ipi_addr;
                *tolen = sizeof(struct sockaddr_in);
            }
            break;
        }
#endif

#ifdef HAVE_IP_RECVDSTADDR
        if (cmsg->cmsg_level == IPPROTO_IP
                && cmsg->cmsg_type == IP_RECVDSTADDR)
        {
            struct in_addr *i = (struct in_addr *)CMSG_DATA(cmsg);
            if (to)
            {
                ((struct sockaddr_in *)to)->sin_addr = *i;
                *tolen = sizeof(struct sockaddr_in);
            }
        }
#endif
    }

    return err;
}

#ifdef STANDALONE
#include
#include
#include
#include

/*
 *    Small test program to test recvfromto
 */
int main(int argc, char **argv)
{
    struct sockaddr_in from, to, in;
    char buf[1024];
    int port = 20000;
    int n, s, fl, tl;

    if (argc > 1) port = atoi(argv[1]);

    s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    in.sin_family = AF_INET;
    in.sin_port = htons(port);
    in.sin_addr.s_addr = INADDR_ANY;
    bind(s, (struct sockaddr *)&in, sizeof(in));

    while (1)
    {
        fl = tl = sizeof(struct sockaddr_in);
        memset(&from, 0, sizeof(from));
        memset(&to, 0, sizeof(to));
        if ((n = recvfromto(s, buf, sizeof(buf), 0,
                            (struct sockaddr *)&from, &fl,
                            (struct sockaddr *)&to, &tl)) < 0)
        {
            perror("recvfromto");
            break;
        }
        printf("Received a packet of %d bytes\n", n);
        printf("  src ip:port %s:%d\n",
               inet_ntoa(from.sin_addr), ntohs(from.sin_port));
        printf("  dst ip:port %s:%d\n",
               inet_ntoa(to.sin_addr), ntohs(to.sin_port));
    }

    return 0;
}

#endif /* STANDALON */
/* end */
#endif

阅读(1456) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~