Home C/C++ I/O多路复用中select模型的消息触发形式

    在I/O多路复用中,消息有两种不同的触发方式,分别是:

    水平触发(level-triggered,也被称为条件触发)LT:  只要满足条件,就触发一个事件(只要有数据没有被获取,内核就不断通知你) 。

    边缘触发(edge-triggered)ET: 每当状态变化时,触发一个事件。


    一般在I/O多路复用中,有三个经典的模型,分别是:select、poll和epoll。但是对于后两者,在应用时都会有明确的参数来设置消息触发类型,唯独select没有这种可选的设置,那么select究竟属于哪种触发形式,不妨做个实验。

    实验的基本思路就是,server通过select模型来监听事件,若有事件发生,则一次只接收一个字节的数据,而client会一次性的向server发送大于1字节的报文,若server不断的触发了select的消息通知,则会将client发送来的所有数据全部接收,但若server只触发了一次消息,则不会将完整的数据复制到用户内存中,由此就可判断select的消息触发类型。

    

下面给出实验代码:

//Server

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <time.h>
#include <arpa/inet.h>

int main()
{
    struct sockaddr_in localAddr;
    struct sockaddr_in clientAddr;
    struct timeval timeo;
    int listenSoc;
    int clientSoc;
    int addrLen;
    fd_set fdRead;
    char recvBuff[100];

    memset(&localAddr,NULL,sizeof(localAddr));
    memset(&clientAddr,NULL,sizeof(clientAddr));
    memset(&timeo,NULL,sizeof(timeo));

    timeo.tv_sec=1;

    localAddr.sin_addr.s_addr=INADDR_ANY;
    localAddr.sin_port=htons(7777);
    localAddr.sin_family=AF_INET;

    listenSoc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(listenSoc==-1)
    {
        printf(“create socket failed.\n”);
        return -1;
    }

    if(bind(listenSoc,(struct sockaddr *)&localAddr,sizeof(localAddr))!=0)
    {
        printf(“bind addr failed.\n”);
        return -1;
    }

    if(listen(listenSoc,SOMAXCONN)!=0)
    {
        printf(“listen socket failed.\n”);
        return -1;
    }

    addrLen=sizeof(clientAddr);
    clientSoc=accept(listenSoc,(struct sockaddr *)&clientAddr,&addrLen);
    if(clientSoc==-1)
    {
        printf(“accept conn failed.\n”);
        return -1;
    }

    while(1)
    {
        FD_ZERO(&fdRead);
        FD_SET(clientSoc,&fdRead);

        if(select(clientSoc+1,&fdRead,NULL,NULL,&timeo)<=0)
            continue;
        if(FD_ISSET(clientSoc,&fdRead))
        {
            memset(recvBuff,NULL,sizeof(recvBuff));
            if(recv(clientSoc,recvBuff,1,0)<=0)
            {
                printf(“close conn.\n”);
                return 0;
            }
            printf(“%s”,recvBuff);
        }
    }

    return 0;
}

//Client

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>

int main()
{
    struct sockaddr_in servAddr;
    int servSoc;
    char *sendStr=”Hello,I’m client.\n”;

    memset(&servAddr,NULL,sizeof(servAddr));

    servAddr.sin_addr.s_addr=inet_addr(“127.0.0.1”);
    servAddr.sin_port=htons(7777);
    servAddr.sin_family=AF_INET;

    servSoc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(servSoc==-1)
    {
        printf(“create socket failed.\n”);
        return -1;
    }

    if(connect(servSoc,(struct sockaddr *)&servAddr,sizeof(servAddr))!=0)
    {
        printf(“conn failed.\n”);
        return -1;
    }

    if(send(servSoc,sendStr,strlen(sendStr),0)<=0)
    {
        printf(“send failed.\n”);
        return -1;
    }

    return 0;
}

实验结果:

20160410010643.jpg

由此可得,select模型的消息触发形式为水平触发。

打赏
0 comment

You may also like

Leave a Comment

*

code

error: 未经允许禁止转载!