我的技术规范

C/C++, Algorithm
随笔 - 11, 文章 - 7, 评论 - 1, 引用 - 0
数据加载中……

IPV6来了? UDP AsyncSelect模式


// WinSockIPv6Internel.h.h 
// IPV6 通讯建立的基本实现
// author: panchao 2012

#pragma once

#include <memory>
#include <tchar.h>
#include <string>

#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment( lib, "Ws2_32.lib")

#define WM_WINSOCKIPV6EVENTS 3040 

template < class T>
class CWinSockIPv6Internel : public CMessageMap
{
private:
    typedef CWinSockIPv6Internel<T> thisClass;

    static const int kRECV_BUFFER_SIZE = 8096;

private:
    
    SOCKET socket_;

    std::string local_ipaddr_;
    std::string remote_ipaddr_;

    std::string local_port_;
    std::string remote_port_;

public:

    char recv_buffer_[kRECV_BUFFER_SIZE];

    int recv_length_;

public:

    CWinSockIPv6Internel();

    virtual ~CWinSockIPv6Internel();

private// 

    CWinSockIPv6Internel( const CWinSockIPv6Internel& );

    CWinSockIPv6Internel& operator=( const CWinSockIPv6Internel& );

public:

    // local bind parameter
    const std::string& local_ipaddr() { return local_ipaddr_; } 
    void set_local_ipaddr( const std::string& local_ipaddr ) { local_ipaddr_ = local_ipaddr; }

    const std::string& local_port() { return local_port_; } 
    void set_local_port( const std::string& local_port ) { local_port_ = local_port; }

    // remote bind parameter
    const std::string& remote_ipaddr() { return remote_ipaddr_; } 
    void set_remote_ipaddr( const std::string& remote_ipaddr ) { remote_ipaddr_ = remote_ipaddr; }

    const std::string& remote_port() { return remote_port_; } 
    void set_remote_port( const std::string& remote_port ) { remote_port_ = remote_port; }

public:

    int bind();

    int close();

    int sendto( const char * buf, int len );

protected:

    BEGIN_MSG_MAP( thisClass )
        MESSAGE_HANDLER( WM_WINSOCKIPV6EVENTS, OnWinsockIPv6Events)
    END_MSG_MAP()
    
    LRESULT OnWinsockIPv6Events(UINT, WPARAM, LPARAM, BOOL&);
};




template < class T>
CWinSockIPv6Internel<T>::
CWinSockIPv6Internel() :
    socket_(INVALID_SOCKET),

    local_ipaddr_(),
    remote_ipaddr_(),

    local_port_(),
    remote_port_(),

    recv_length_(0)
{
}

template < class T>
CWinSockIPv6Internel<T>::
~CWinSockIPv6Internel()
{
    close();
}    


template < class T>
int 
CWinSockIPv6Internel<T>::
bind()
{
    if ( socket_ != INVALID_SOCKET)
        return 1;

    WSADATA wsaData;

    if ( ::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0 )
    {
        ::WSACleanup();
        return 9;
    }

    int ret;
    addrinfo hints;
    addrinfo* p_source;

    memset( &hints, 0, sizeof(hints));

    hints.ai_family = AF_INET6;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;
    hints.ai_flags = AI_NUMERICHOST; // Nodename must be a numeric address string

    ret = ::getaddrinfo( local_ipaddr_.c_str(), local_port_.c_str(), &hints, &p_source);
    
    if ( ret != 0 ) {
        ATLASSERT( p_source == NULL );
        return 2;
    }

    ATLASSERT( p_source != NULL );
    socket_ = ::socket( p_source->ai_family, p_source->ai_socktype, p_source->ai_protocol);

    if ( socket_ == INVALID_SOCKET) { 
        ::freeaddrinfo( p_source);
        return 3;
    }

    ret = ::bind ( socket_, p_source->ai_addr, p_source->ai_addrlen);

    ::freeaddrinfo( p_source); // no longer need it.

    
//getsockname

    if ( ret == SOCKET_ERROR) {
        ::closesocket( socket_);
        socket_ = INVALID_SOCKET;
        return 4;
    }

    BOOL broadcast = TRUE;
    ::setsockopt( socket_, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(BOOL));

    ATLASSERT( ::IsWindow(static_cast<T*>(this)->m_hWnd) );

    ret = ::WSAAsyncSelect( socket_, static_cast<T*>(this)->m_hWnd, WM_WINSOCKIPV6EVENTS, FD_READ);

    if ( ret == SOCKET_ERROR ) {
        ::closesocket( socket_);
        socket_ = INVALID_SOCKET;
        return 5;
    }

    return 0;
}

template < class T>
int 
CWinSockIPv6Internel<T>::
close()
{
    if ( socket_ == INVALID_SOCKET)
        return 0;
    
    ::closesocket( socket_);
    socket_ = INVALID_SOCKET;
    
    ::WSACleanup();

    return 0;
}

template < class T>
int 
CWinSockIPv6Internel<T>::
sendto( const char * buf, int len )
{
    if ( socket_ == INVALID_SOCKET)
        return 0;

    int ret;
    addrinfo hints;
    addrinfo* p_destination;

    memset( &hints, 0, sizeof(hints));

    hints.ai_family = AF_INET6;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;
    hints.ai_flags = AI_NUMERICHOST; // Nodename must be a numeric address string

    ret = ::getaddrinfo( remote_ipaddr_.c_str(), remote_port_.c_str(), &hints, &p_destination);
    
    if ( ret != 0 ) {
        ATLASSERT( p_destination == NULL );
        return 2;
    }

    ATLASSERT( p_destination != NULL );

    ret = ::sendto( socket_, buf, len, 0, 
        p_destination->ai_addr, p_destination->ai_addrlen);

    ::freeaddrinfo( p_destination); // no longer need it.
    return ret;
}

template < class T>
LRESULT 
CWinSockIPv6Internel<T>::
OnWinsockIPv6Events(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    if ( socket_ == INVALID_SOCKET)
        return 0;

    int ret;

    sockaddr_in6 recvAddr;
    memset( &recvAddr, 0, sizeof(recvAddr));

    int len = sizeof(recvAddr);

    ret = ::recvfrom( socket_, recv_buffer_, kRECV_BUFFER_SIZE, 0, (SOCKADDR*)&recvAddr, &len);
    
    if ( ret > 0 )
    {
        recv_length_ = ret;

        static_cast<T*>(this)->Fire_DataArrival( recv_length_ );

        recv_length_ = 0;
    }

    return S_OK;
}

posted on 2012-02-18 19:57 panchao 阅读(357) 评论(0)  编辑 收藏 引用 所属分类: utils


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理