【编程】select 网络编程demo


I/O服用典型使用在下列网络应用场合:
当客户处理多个描述符(通常是交叉式输入和网络套接字)时,必须使用I/O服用。
一个客户同时处理多个套接字是可能的,不过比较少见。
如果一个TCP服务器既要处监听套接字,又要处理已连接套接字,一般就要使用I/O服用。
如果一个服务器既要使用TCP,又要使用UCP。一般就要使用I/O服用。
如果一个服务器要处理多个服务或多个协议。

1.cli_select.c

客户端从终端读入字符串,再发给服务器;需处理两个句柄。

#include <stdio.h>
#include <string.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>

#define SERV_IP "127.0.0.1"
//#define SERV_IP "192.168.2.1"
#define SERV_PORT 8123
#define MAXLINE 254
#define max(a,b) (a)>=(b)?(a):(b)
int  str_cli (FILE * fp, int sockfd)
{
    int maxfdp1, stdineof;
    fd_set rset;
    char buf[MAXLINE];
    int n;

    stdineof = 0;

    for(;;)
    {
        if (stdineof == 0)
            FD_SET(fileno(fp), &rset);
        FD_SET(sockfd, &rset);
        maxfdp1 = max(fileno(fp), sockfd) +1;

        //printf("maxfdp1 = %d\n", maxfdp1);
        select(maxfdp1, &rset, NULL, NULL, NULL);
        if (FD_ISSET(sockfd, &rset))
        {
            if ((n = read(sockfd, buf, MAXLINE)) == 0)
            {
                if (stdineof == 1)
                    return;
                else
                {
                    printf("strcli:server terminated prematurely\n");
                }
            }
            write(fileno(stdout),buf,n);
        }

        if (FD_ISSET(fileno(fp), &rset))
        {
            if ((n = read(fileno(fp), buf, MAXLINE)) == 0)
            {
                stdineof = 1;
                shutdown(sockfd, SHUT_WR); /*SEND FIN*/
                FD_CLR(fileno(fp), &rset);
                continue;
            }
            write(sockfd, buf, n);
        }
    }
    return 0;
}
void cli_init( int *sockfd)
{
    struct sockaddr_in servaddr;

    *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, SERV_IP, &servaddr.sin_addr);

    connect(*sockfd, (struct sockaddr*) &servaddr, sizeof(servaddr));

    printf("connect\n");
    return;
}
int main(int argc, char *argv[])
{
    int sockfd;
    cli_init( &sockfd);
    str_cli(stdin,  sockfd);    
    return 0;
}

2.ser_select.c

服务器接收客户端发来的字符串,并回传给客户端。单进程监听多个服务器。

/* ************************************************************************
 *       Filename:  ser_select.c
 *    Description:  
 *        Version:  1.0
 *        Created:  08/07/18 02:00:22
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:  YOUR NAME (), 
 *        Company:  
 * ************************************************************************/
#include <stdio.h>
#include <string.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>

#define SERV_PORT 8123
#define MAXLINE 254
#define LISTENQ 5

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);

    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, 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);
        printf("select\n");

        if (FD_ISSET(listenfd, &rset))
        {
            clilen = sizeof(cliaddr);
            connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);
            printf("accept\n");

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

            if (i == FD_SETSIZE)
            {
                printf("too many clients\n");
            }

            FD_SET(connfd, &allset);
            if (connfd > maxfd)
                maxfd = connfd;/* select */
            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 )
                {
                    printf("read n = %d\n", 0);
                    close(sockfd);
                    FD_CLR(sockfd, &allset);
                    client[i] = -1;
                }
                else
                {
                    printf("read n = %d\n", n);
                    write(sockfd, buf, n);
                }
                if (--nready <= 0)
                    break;

            }

        }
    }

    return 0;
}


猜你喜欢

转载自blog.csdn.net/u012335044/article/details/81483469
今日推荐