Linux编程之使用多路复用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27312943/article/details/79108718

1 推荐博客
https://www.cnblogs.com/Anker/archive/2013/08/14/3258674.html
我自己select()函数的使用和使用多路复用改写服务端代码理解的还不是特别深入,推荐上面的博客。
2 使用select()函数改写服务端源代码
服务端:

/*net_selecy.c*/
//多路复用
#include <stdio.h>  
#include <sys/socket.h>  
#include <string.h>  
#include <netinet/in.h>  
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>

#define PORT 4321
#define MAX_QUE_CONN_NM 5
#define BUFFER_SIZE 1024
#define MAX_SOCK_FD FD_SETSIZE

int main()
{
    struct sockaddr_in server_sockaddr,client_sockaddr; 
    fd_set inset,tmp_inset;
    int sockid;  //套接字描述符
    int client_fd;  //接收到的套接字ID
    int i=0;   
    int sin_size;
    char buf[BUFFER_SIZE];
    int fd;
    int recvbytes;

    sockid=socket(AF_INET,SOCK_STREAM,0);
    if(sockid == -1)
    {
        //创建套接字失败
        printf("socket error\n");
        exit(1);
    }   

    server_sockaddr.sin_family=AF_INET; 
    server_sockaddr.sin_port=htons(PORT);  //端口号
    server_sockaddr.sin_addr.s_addr=INADDR_ANY;  //IP地址 //IP地址可以指定,或者使用宏INADDR_ANY
                                                          //表示运行套接字与服务器的任一网络接口进行绑定
    bzero(&(server_sockaddr.sin_zero),8);

    setsockopt(sockid,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));

    if( bind(sockid,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr))  == -1 )
    {
        printf("bind error\n");
        exit(1);    
    }
    printf("bind success\n");


    if( listen(sockid,MAX_QUE_CONN_NM) == -1 )
    {
        printf("listen error\n");   
        exit(1);
    }
    printf("listen...\n");

    /*将指定的文件描述符集清空,在对文件描述符集合进行设置前,
    必须对其进行初始化,如果不清空,由于在系统分配内存空间后,
    通常并不作清空处理,所以结果是不可知的。*/
    FD_ZERO(&inset);

    /**************
    将fd加入set集合
    **************/
    FD_SET(sockid,&inset);

    while(1)
    {
        /*文件描述符集合的备份,这样可以避免每次都进行初始化*/
        tmp_inset=inset;
        sin_size=sizeof(struct sockaddr_in);

        memset(buf,0,sizeof(buf));   
        /*调用select()函数*/
        /*******************************
        函数原型:int select(int maxfd,
                             fd_set *rdset,
                             fd_set *wrset,
                             fd_set *exset,
                             struct timeval *timeout);
        函数参数:maxfd 需要监视的最大的文件描述符值+1
                  rdset 需要检测的可读文件描述符的集合
                  wrset 可写文件描述符的集合
                  exset 异常文件描述符的集合
                  timeout 构用于描述一段时间长度,
                          如果在这个时间内,
                          需要监视的描述符没有事件发生则函数返回,返回值为0
        *******************************/
        if( !(select(MAX_SOCK_FD,&tmp_inset,NULL,NULL,NULL) > 0) )  
        {
            printf("select error\n");               
        }

        for(fd=0;fd<MAX_SOCK_FD;fd++)
        {
            /*FD_ISSET()用于测试指定的文件描述符是否在该集合中*/
            if(FD_ISSET(fd,&tmp_inset) > 0)
            {
                if(fd == sockid)
                {
                    /*服务端接受客户端的请求*/ 
                    if( (client_fd=accept(sockid,(struct sockaddr*)&client_sockaddr,&sin_size)) == -1 )
                    {
                        printf("accept error\n");
                        exit(1);
                    }
                    /*将新连接的客户端套接字加入到观察列表中*/
                    FD_SET(client_fd,&inset);

                    printf("new connection from %d(socket)\n",client_fd);
                }
               else
               {
                        /*处理从客户端发来的消息*/ 
                    if( (recvbytes= recv(client_fd,buf,BUFFER_SIZE,0) )  >0 )
                    {
                        printf("receive data %d\n",strlen(buf));
                        printf("receive a message:%s\n",buf);           
                    }
                    else
                    {
                        close(fd);
                        FD_CLR(fd,&inset);
                        printf("client %d(socket) has left\n",fd);  
                    }

                 }
           }/*end if(FD_ISSET(fd,&tmp_inset) > 0)*/     

        } //end for
    } /*end while(1)*/

    close(sockid);
    exit(0);


}

客户端:

/*client.c*/
#include <stdio.h>  
#include <sys/socket.h>  
#include <string.h>  
#include <netinet/in.h>  
#include <netdb.h>

#define PORT 4321
#define BUFFER_SIZE 1024


int main(int argc,char *argv[])
{
    struct hostent *host;
    int sockid;  //套接字描述符
    int sendbyts;  //实际发送的字节数
    char buf[BUFFER_SIZE];
    struct sockaddr_in serv_addr;

    if(argc<3)
    {
        fprintf(stderr,"USAGE:./client Hostname(or ip address) Text\n");
        exit(1);    
    }

    /*地址解析函数*/
    /***************************
    函数原型:struct hostent *gethostbyname(const char *hostname);
    函数参数:hostname 主机名
    函数返回值:成功 指向hostent的指针
                失败 -1    
    *****************************/
    if( (host=gethostbyname(argv[1])) == NULL )
    {
        printf("gethostbyname error\n");    
        exit(1);
    }

    memset(buf,0,sizeof(buf));
    sprintf(buf,"%s",argv[2]);

    //创建socket

    sockid=socket(AF_INET,SOCK_STREAM,0);
    if(sockid == -1)
    {
        //创建套接字失败
        printf("socket error\n");
        exit(1);
    }
    /*设置socket_in中的相关参数*/
    serv_addr.sin_family=AF_INET; 
    serv_addr.sin_port=htons(PORT);  //端口号
    serv_addr.sin_addr=*((struct in_addr *)host->h_addr);  //IP地址 //IP地址可以指定,或者使用宏INADDR_ANY
                                                          //表示运行套接字与服务器的任一网络接口进行绑定
    bzero(&(serv_addr.sin_zero),8);

    //连接服务器
    /*调用connect()函数主动发起对服务器端的连接*/
    /************************
    函数原型: int connect(int sockfd, const struct sockaddr * addr, socklen_t *addrlen)
    函数参数: sockfd  套接字描述符
               addr    客户端地址
               addrlen 地址长度
    函数返回值: 成功 接收到的非负套接字
                失败 -1
    ***********************/
    if( connect(sockid,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr)) == -1 )
    {
        printf("connect error\n");  
        exit(1);
    }


    /*发送消息给服务端*/
    /*****************
    函数原型:int send(int sockfd,const void *msg,int len,int flags)
    函数参数:sockfd 套接字描述符
              msg 指向要发送数据的指针
              len 数据长度
              flags 一般为0
    函数返回值:成功 实际发送的字节数
                失败 -1   
    ******************/
    if( (sendbyts=send(sockid,buf,sizeof(buf),0)) == -1 )
    {
        printf("send error\n");
        exit(1);    
    }
     sleep(5);
    close(sockid);


    return 0;
}

运行结果
这里写图片描述
服务端

这里写图片描述
客户端1

这里写图片描述
客户端2

猜你喜欢

转载自blog.csdn.net/qq_27312943/article/details/79108718