首页
社区
课程
招聘
[原创]UDP发包并设置超时时间
发表于: 2014-9-19 15:30 8064

[原创]UDP发包并设置超时时间

2014-9-19 15:30
8064
初学Winsock编程..
准备从UDP下手..
一开始sendto啥的函数很容易.
recvfrom啥的也很容易
但是...某次我没注意.吧server关了..然后client就准备等到天荒地老去了

然后纠结了下.找了几个同事问问..

发现WSAEnumNetworkEvents这玩意不仅仅是多线程下的处理.还可以用于现在这种加超时的sock
就不用再单独给socket设置个超时时间了
代码如下虽然是个很简单的东西.但是还是希望大家不笑我哇.

与网上随处可见的超时的区别就是这个没给socket去set一个timeout,而是靠wait一个绑定到该socket后的wsaevent

#include <Winsock2.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
BOOL SendUdpAndRecvTimeOut(PCHAR ServerIP,USHORT ServerPort,PVOID SendDate,ULONG SendSize,PVOID RecvDate,ULONG RecvSize,ULONG Timeout)
{
        WSADATA wsaData;
        ZeroMemory(&wsaData,sizeof(WSADATA));

        if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0)//初始化WSA
        {
                return FALSE;
        }
       
        SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//创建socket,SOCK_DGRAM代表UDP
        if(sockSrv == INVALID_SOCKET)
        {
                WSACleanup();
                return FALSE;
        }

        SOCKADDR_IN addr_in;
        ZeroMemory(&addr_in,sizeof(addr_in));
        addr_in.sin_family = AF_INET;
        addr_in.sin_addr.S_un.S_addr = inet_addr(ServerIP);//填写对端IP
        addr_in.sin_port = htons(ServerPort);

        int ret = sendto(sockSrv,(PCHAR)SendDate,SendSize,NULL,(struct sockaddr*)&addr_in,sizeof(addr_in));
        if (ret == SOCKET_ERROR)//发送失败则返回
        {
                closesocket(sockSrv);
                WSACleanup();
                return FALSE;
               
        }
       
        WSAEVENT SockEvent = WSACreateEvent();
        if (WSAEventSelect(sockSrv,SockEvent,FD_READ|FD_OOB) != 0)//将sockt与event关联.当socket发生第三个参数的事件时候将setevent
        {
                closesocket(sockSrv);
                WSACleanup();
                return FALSE;
        }

        if (WSA_WAIT_EVENT_0 != WSAWaitForMultipleEvents(1,&SockEvent,TRUE,Timeout,FALSE))
        {
                WSACloseEvent(SockEvent);
                closesocket(sockSrv);
                WSACleanup();
                return FALSE;//不是成功则返回失败
        }

        WSANETWORKEVENTS NetworkEvents;
        WSAEnumNetworkEvents(sockSrv,SockEvent,&NetworkEvents);//获取触发event的操作类型
        //WSAResetEvent(SockEvent);
        WSACloseEvent(SockEvent);//关闭event

        sockaddr addr_out;
        ZeroMemory(&addr_out,sizeof(addr_out));
        switch(NetworkEvents.lNetworkEvents)//根据触发类型操作
        {
        case FD_READ: //与00b用一个函数
        case FD_OOB:
                int sizeofoutadd = sizeof(addr_out);
                if (SOCKET_ERROR == recvfrom(sockSrv,(PCHAR)RecvDate,RecvSize,MSG_PEEK,&addr_out,&sizeofoutadd))
                {
                        int errod = WSAGetLastError();
                        closesocket(sockSrv);
                        WSACleanup();
                        return FALSE;
                }
                break;
        }

        closesocket(sockSrv);
        WSACleanup();
        return TRUE;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 11007
活跃值: (17509)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
来顶一下楼主,多谢分享经验
2014-9-19 15:40
0
游客
登录 | 注册 方可回帖
返回
//