免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5386 | 回复: 14
打印 上一主题 下一主题

[拍砖贴]简单模拟WSAWaitForMultipleEvents [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-19 21:14 |只看该作者 |倒序浏览
最近为了移植windows网络SDK代码到Linux下,在保持代码的统一性前提下,模拟了windows WSAEVENT的相关函数, 幸运的是在该SDK中: DWORD
WSAWaitForMultipleEvents(DWORD cEvents, const WSAEVENT FAR *lphEvents, BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable);
参数fWaitAll, 以及fAlertable都是使用FALSE. 要是有一个TRUE的话就难办了

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

#define __USE_XOPEN
#include <sys/poll.h>

#define TRUE    1
#define FALSE   0
#define BOOL    int

#define DWORD unsigned int
#define FAR

#define WSA_INVALID_PARAMETER   ((DWORD)-3L)
#define WSA_INVALID_EVENT       ((DWORD)-2L)
#define WSA_WAIT_FAILED         ((DWORD)-1L)
#define WSA_WAIT_TIMEOUT        ((DWORD)0)
#define WSA_WAIT_EVENT_0        ((DWORD)1)

#define FLG_WSA_EVENT 0

typedef struct __LNX_EVENT
{
    int flags;
    int lnx_fd[2];
    pthread_mutex_t mutex;
}LNX_EVENT;

typedef void* HANDLE;
typedef LNX_EVENT* WSAEVENT;

HANDLE WSACreateEvent(void)
{
    LNX_EVENT* event = (LNX_EVENT*)malloc(sizeof(LNX_EVENT));
    int retval = pipe(event->lnx_fd);
    if(retval < 0)
    {
        free(event);
        return NULL;
    }

    event->flags = FLG_WSA_EVENT;
    pthread_mutex_init(&(event->mutex), NULL);
    return (HANDLE)event;
}

BOOL WSASetEvent(HANDLE hEvent)
{
    LNX_EVENT* event = (LNX_EVENT*)hEvent;
    if(event->flags != FLG_WSA_EVENT)
    {
        return FALSE;
    }

    pthread_mutex_lock(&(event->mutex));
    struct pollfd fdarray[2];
    memset(fdarray, 0x0, sizeof(struct pollfd) * 2);
   
    fdarray[0].fd = event->lnx_fd[0];
    fdarray[0].events = POLLRDNORM;
   
    fdarray[1].fd = event->lnx_fd[1];
    fdarray[1].events = POLLWRNORM;
   
    int ret = poll(&fdarray[0], 1, 0);
    if(ret > 0 && (fdarray[0].revents & POLLRDNORM))
    {
        char buffer[256] = {0};
        read(event->lnx_fd[0], buffer, 1024);
    }

    ret = poll(&fdarray[1], 1, 0);
    if(ret <= 0)
    {
        pthread_mutex_unlock(&(event->mutex));
        return FALSE;
    }
   
    char w_signal = 'h';
    BOOL bRet = write(event->lnx_fd[1], &w_signal, 1) == 1 ? TRUE : FALSE;
    pthread_mutex_unlock(&(event->mutex));
    return bRet;
}

BOOL WSAResetEvent(HANDLE hEvent)
{
    BOOL bRet = FALSE;
    LNX_EVENT* event = (LNX_EVENT*)hEvent;
    if(event->flags != FLG_WSA_EVENT)
    {
        return FALSE;
    }

    pthread_mutex_lock(&(event->mutex));
    struct pollfd fdarray;
    memset(&fdarray, 0x0, sizeof(struct pollfd));
   
    fdarray.fd = event->lnx_fd[0];
    fdarray.events = POLLRDNORM;
   
    int ret = poll(&fdarray, 1, 0);
    if(ret > 0 && (fdarray.revents & POLLRDNORM))
    {
        char buffer[256] = {0};
        bRet = read(event->lnx_fd[0], buffer, 1024) > 0 ? TRUE : FALSE;
        fprintf(stderr, "Reset the send buffer: %s\n", buffer);
    }

    pthread_mutex_unlock(&(event->mutex));
    return bRet;
}

BOOL WSACloseEvent(HANDLE hEvent)
{
    LNX_EVENT* event = (LNX_EVENT*)hEvent;
    if(event->flags != FLG_WSA_EVENT)
    {
        return FALSE;
    }
   
    close(event->lnx_fd[0]);
    close(event->lnx_fd[1]);
    pthread_mutex_destroy(&(event->mutex));
    free(event);

    return TRUE;
}

DWORD WSAWaitForMultipleEvents(DWORD cEvents, const WSAEVENT FAR *lphEvents, BOOL fWaitAll, DWORD dwTimeout, BOOL fAlertable)
{
    if(cEvents <= 0 || lphEvents == NULL || fWaitAll == TRUE || fAlertable == TRUE)
    {
        return WSA_INVALID_PARAMETER;
    }

    struct pollfd fdarray[cEvents];
    memset(fdarray, 0x0, sizeof(struct pollfd) * cEvents);
   
    int index = 0;
    for(; index < cEvents; index++)
    {
        if(lphEvents[index]->flags != FLG_WSA_EVENT)
        {
            return WSA_INVALID_EVENT;
        }

        fdarray[index].fd = lphEvents[index]->lnx_fd[0];
        fdarray[index].events = POLLRDNORM;
    }

    int ret = poll(fdarray, cEvents, dwTimeout);
    if(ret > 0)
    {
        for(index = 0; index < cEvents; index++)
        {
            if(fdarray[index].revents & POLLRDNORM)
            {
                return WSA_WAIT_EVENT_0 + index;
            }
        }
    }
    else if(ret == 0)
    {
        return WSA_WAIT_TIMEOUT;
    }
   
    return WSA_WAIT_FAILED;
}




[ 本帖最后由 飞雪横天 于 2009-3-19 21:19 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2009-03-19 21:17 |只看该作者

WSAWaitForMultipleEvents测试用例

static void* send_event(void* argptr)
{
    WSAEVENT event = (WSAEVENT)argptr;
    sleep(5);
    WSASetEvent(event);
    WSASetEvent(event);
    pthread_exit(NULL);
    return NULL;
}

int main(int argc, char* argv[])
{
    HANDLE hEvent1 = WSACreateEvent();
    HANDLE hEvent2 = WSACreateEvent();
   
    pthread_t hthread1, hthread2;
    pthread_create(&hthread2, NULL, send_event, hEvent2);
    pthread_create(&hthread1, NULL, send_event, hEvent1);
   
    WSAEVENT events[2] = {hEvent1, hEvent2};
    DWORD ret = WSAWaitForMultipleEvents(2, events, FALSE, 5020, FALSE);
    if(ret == WSA_WAIT_EVENT_0)
    {
        fprintf(stderr, "wait for two events, and the first event: %p signal\n", hEvent1);
        sleep(1);
        WSAResetEvent(hEvent1);
        goto END_EVENT;
    }
    else if (ret == WSA_WAIT_EVENT_0 + 1)
    {
        fprintf(stderr, "wait for two events, and the second event: %p signal\n", hEvent2);
        sleep(1);
        WSAResetEvent(hEvent2);
        goto END_EVENT;
    }
    else
    {
        fprintf(stderr, "wait for two events(:%p, %p) failed\n", hEvent1, hEvent2);
        goto END_EVENT;
    }

END_EVENT:
    pthread_join(hthread1, NULL);
    pthread_join(hthread2, NULL);

    WSACloseEvent(hEvent1);
    WSACloseEvent(hEvent2);
   
    return 0;
}


用poll模拟WSAWaitForMultipleEvents的行为, event用pipe来进行模拟. 整个过程比较简单, 欢迎大家轻点拍砖;

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
3 [报告]
发表于 2009-03-19 22:20 |只看该作者
原帖由 飞雪横天 于 2009-3-19 21:14 发表
最近为了移植windows网络SDK代码到Linux下,在保持代码的统一性前提下,模拟了windows WSAEVENT的相关函数, 幸运的是在该SDK中: DWORD
WSAWaitForMultipleEvents(DWORD cEvents, const WSAEVENT FAR *lphEvents, ...

光看这函数名字就能让我做噩梦。。。

论坛徽章:
0
4 [报告]
发表于 2009-03-20 08:47 |只看该作者

回复 #3 MMMIX 的帖子

看多了就会习惯的

论坛徽章:
0
5 [报告]
发表于 2009-03-20 09:10 |只看该作者
LZ你这个真的管用不?

论坛徽章:
0
6 [报告]
发表于 2009-03-20 11:43 |只看该作者

回复 #5 alexhappy 的帖子

我自己测试过,目前除了参数fWaitAll, 以及fAlertable都是使用FALSE, 其余的功能都测试通过.
这个办法缺点是每个event都使用了两个fd, 而一个进程最多只有1024个fd. 浪费了大量的fd.

这个方法的优点就是可以和网络SOCKET一起用,因为socket本生也是属于fd

论坛徽章:
0
7 [报告]
发表于 2009-03-20 15:32 |只看该作者
看来这个代码都没人拍砖.....失败

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
8 [报告]
发表于 2009-03-20 16:04 |只看该作者
原帖由 飞雪横天 于 2009-3-20 15:32 发表
看来这个代码都没人拍砖.....失败

来这的许多都不懂 Windows 。。。

论坛徽章:
0
9 [报告]
发表于 2009-03-20 16:04 |只看该作者

如果只是为了等待多个套接字, 直接使用select就行了

你还在上面加锁, 用pipe, 这种方法实在不好.
退一步说, 为了等待多个事件, 也应该使用fifo, 配合select....

论坛徽章:
0
10 [报告]
发表于 2009-03-20 19:24 |只看该作者
原帖由 zhaoli_824 于 2009-3-20 16:04 发表
你还在上面加锁, 用pipe, 这种方法实在不好.
退一步说, 为了等待多个事件, 也应该使用fifo, 配合select....


锁的问题倒是不是关键,去掉即可;但是使用fifo,个人感觉不好,因为需要创建fifo文件,不好?


您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP