1. 程式人生 > >socket連線庫,相容ipv6,ipv4,為IOS上架做準備

socket連線庫,相容ipv6,ipv4,為IOS上架做準備

1.因為引用了OC的程式碼所以貌似只支援IOS

2.服務端一般來說無要求,並不要求支援IPV6也行

3.原理:引用部落格:http://www.cocoachina.com/bbs/read.php?tid=458416,判斷當前網路是IPV4還是IPV6,然後採取不同連線方式。

4.測試:MAC插網線,然後開啟WIFI,真機測試。 自行百度:MAC開啟IPV6。

過程如下:

1.先域名解析。這裡我用的OC程式碼直接把是否是IPV6和域名解析都做了,如果因為無法返回兩個值頭疼,那就寫兩遍吧。。

上程式碼:

+ (NSString *) getIPWithHostName:(const NSString *)hostName
{
    struct addrinfo * result;
    struct addrinfo * res;
    char ipv4[128];
    char ipv6[128];
    int error;
    BOOL IS_IPV6 = FALSE;
    bzero(&ipv4, sizeof(ipv4));
    bzero(&ipv4, sizeof(ipv6));
    
    error = getaddrinfo([hostName UTF8String], NULL, NULL, &result);
    if(error != 0) {
        NSLog(@"error in getaddrinfo:%d", error);
        return nil;
    }
    for(res = result; res!=NULL; res = res->ai_next) {
        char hostname[1025] = "";
        error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, 1025, NULL, 0, 0);
        if(error != 0) {
            NSLog(@"error in getnameifno: %s", gai_strerror(error));
            continue;
        }
        else {
            switch (res->ai_addr->sa_family) {
                case AF_INET:
                    memcpy(ipv4, hostname, 128);
                    break;
                case AF_INET6:
                    memcpy(ipv6, hostname, 128);
                    IS_IPV6 = TRUE;
                default:
                    break;
            }
            NSLog(@"hostname: %s ", hostname);
        }
    }
    freeaddrinfo(result);
    
    if(IS_IPV6 == TRUE) return [NSString stringWithUTF8String:ipv6];
    return [NSString stringWithUTF8String:ipv4];
}

橋接類請自己寫。


C++連結庫,這裡只是初步做操作,後面重新封裝在來發布
#ifndef CGAME_SOCKET_H
#define CGAME_SOCKET_H

#ifdef WIN32
#include <windows.h>
#include <WinSock.h>
#else
#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SOCKET int
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1

#endif

#include "NetData.h"
#define BLOCKSECONDS	30

typedef void(*RecvCallBack) (const NetData & data);

class CGameSocket {
public:
	CGameSocket(void);
	~CGameSocket(void);

	bool	Connect(const char* pszServerIP, int nServerPort, bool isipv6,int nBlockSec = BLOCKSECONDS, bool bKeepAlive = false);

	bool	Check(void);

	void	Destroy(void);

	int     Send(const char *data, int len);

	int     Send(const NetData & data);
	SOCKET	GetSocket(void) const { return m_sockClient; }

	bool    IsConnected() const;

	void    SetRecvCallBack(RecvCallBack func);
	bool    NRecv();

	SOCKET         m_sockClient;
	static NetData NoData;
private:
	bool    hasError();			
	void    closeSocket();
	fd_set  readset ;
	fd_set  writeset;
	fd_set  exceptset;


	RecvCallBack   m_func;

};

#endif
#include "cocos2d.h"
#include "CGameSocket.h"

#ifdef WIN32
#include <process.h>
#else
#include <pthread.h>
#include <stdlib.h>
#endif

NetData CGameSocket::NoData;

CGameSocket::CGameSocket()
{
    m_sockClient = INVALID_SOCKET;
}

CGameSocket::~CGameSocket()
{
    Destroy();
}

void CGameSocket::closeSocket()
{
#ifdef WIN32
    closesocket(m_sockClient);
    WSACleanup();
#else
    //close(m_sockClient);
#endif
}

bool CGameSocket::Connect(const char* pszServerIP, int nServerPort,bool isipv6 ,int nBlockSec, bool bKeepAlive )
{
    if(!isipv6)
    {
        if (pszServerIP == 0 || strlen(pszServerIP) > 15) {
            return false;
        }
        
#ifdef WIN32
        WSADATA wsaData;
        WORD version = MAKEWORD(2, 0);
        int ret = WSAStartup(version, &wsaData);//win sock start up
        if (ret != 0) {
            return false;
        }
#endif
        
        m_sockClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (m_sockClient == INVALID_SOCKET) {
            closeSocket();
            return false;
        }
        
        if (bKeepAlive)
        {
            int		optval = 1;
            if (setsockopt(m_sockClient, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)))
            {
                closeSocket();
                return false;
            }
        }
        
#ifdef WIN32
        DWORD nMode = 1;
        int nRes = ioctlsocket(m_sockClient, FIONBIO, &nMode);
        if (nRes == SOCKET_ERROR) {
            closeSocket();
            return false;
        }
#else
        fcntl(m_sockClient, F_SETFL, O_NONBLOCK);
#endif
        
        unsigned long serveraddr = inet_addr(pszServerIP);
        if (serveraddr == INADDR_NONE)
        {
            closeSocket();
            return false;
        }
        
        sockaddr_in	addr_in;
        memset((void *)&addr_in, 0, sizeof(addr_in));
        addr_in.sin_family = AF_INET;
        addr_in.sin_port = htons(nServerPort);
        addr_in.sin_addr.s_addr = serveraddr;
        
        if (connect(m_sockClient, (sockaddr *)&addr_in, sizeof(addr_in)) == SOCKET_ERROR) {
            if (hasError()) {
                closeSocket();
                return false;
            }
            else	// WSAWOLDBLOCK
            {
                timeval timeout;
                timeout.tv_sec = nBlockSec;
                timeout.tv_usec = 0;
                FD_ZERO(&readset);
                FD_ZERO(&writeset);
                FD_ZERO(&exceptset);
                FD_SET(m_sockClient, &readset);
                FD_SET(m_sockClient, &writeset);
                FD_SET(m_sockClient, &exceptset);
                
                int ret = select(FD_SETSIZE, &readset, &writeset, &exceptset, &timeout);
                if (ret == 0 || ret < 0) {
                    closeSocket();
                    return false;
                }
                else	// ret > 0
                {
                    ret = FD_ISSET(m_sockClient, &exceptset);
                    if (ret)		// or (!FD_ISSET(m_sockClient, &writeset)
                    {
                        closeSocket();
                        return false;
                    }
                    
                }
            }
        }
        
        
        struct linger so_linger;
        so_linger.l_onoff = 1;
        so_linger.l_linger = 500;
        setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)&so_linger, sizeof(so_linger));
    }
    else
    {
        struct sockaddr_in6 dest;
        if ((m_sockClient = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
        {
            printf("ipv6,未連線");// IPv6
        }
        printf("socket Ok!");
        
        bzero(&dest, sizeof(dest));
        dest.sin6_family = AF_INET6;     // IPv6
        dest.sin6_port = htons(nServerPort);     // IPv6
        if (inet_pton(AF_INET6, pszServerIP, &dest.sin6_addr) < 0 ) {                 // IPv6
            
        }
        printf("address created/n");
        
        int ret = connect(m_sockClient, (struct sockaddr *) &dest, sizeof(dest));
        if ( ret == SOCKET_ERROR ) {
            return false;
        }
        
    }
    
    
    return true;
}




bool CGameSocket::hasError()
{
#ifdef WIN32
    int err = WSAGetLastError();
    if (err != WSAEWOULDBLOCK) {
#else
        int err = errno;
        if (err != EINPROGRESS && err != EAGAIN) {
#endif
            return true;
        }
        
        return false;
    }
    
int CGameSocket::Send(const char *data, int len)
    {
        if (m_sockClient == INVALID_SOCKET)
        {
            return 0;
        }
        
            char m_sendBuffer[1024];    //緩衝區 從1024改過來的
            int nOffset = 0;
            int nSize = len;
            m_sendBuffer[nOffset + 3] = (unsigned char)(nSize >> 0);
            m_sendBuffer[nOffset + 2] = (unsigned char)(nSize >> 8);
            m_sendBuffer[nOffset + 1] = (unsigned char)(nSize >> 16);
            m_sendBuffer[nOffset + 0] = (unsigned char)(nSize >> 24);
        
            memcpy((m_sendBuffer + 4), data, len);
            nSize += 4;
            ssize_t outsize =send(m_sockClient, m_sendBuffer, nSize, 0);
            if (outsize > 0)
            {
                return outsize - 4.0;
            }
            else{
                if (hasError()) {
                    Destroy();
                    return 0;
                }
            }
//        }


        
        return 0;
    }
    
    int CGameSocket::Send(const NetData & data){
        return Send(data.array() , data.length());
    }
    
    
    bool CGameSocket::IsConnected() const{
        if (m_sockClient == INVALID_SOCKET) {
            return false;
        }
        
        return true;
    }
    
    bool CGameSocket::Check(void)
    {
        if (m_sockClient == INVALID_SOCKET) {
            return false;
        }
        
        char buf[1];
        auto ret = recv(m_sockClient, buf, 1, MSG_PEEK);
        if (ret == 0) {
            Destroy();
            return false;
        }
        else if (ret < 0) {
            if (hasError()) {
                Destroy();
                return false;
            }
            else {
                return true;
            }
        }
        else {
            return true;
        }
        
        return true;
    }
    
    void CGameSocket::Destroy(void)
    {
        struct linger so_linger;
        so_linger.l_onoff = 1;
        so_linger.l_linger = 500;
        auto ret = setsockopt(m_sockClient, SOL_SOCKET, SO_LINGER, (const char*)&so_linger, sizeof(so_linger));
        
        closeSocket();
        
        m_sockClient = INVALID_SOCKET;
        
    }
    
    
    
    bool CGameSocket::NRecv(){
        
        if (this->m_sockClient == INVALID_SOCKET)
        {
            return false;
        }
        char lenbuf[4] = { 0 };
        auto i = recv(this->m_sockClient, lenbuf, 4, 0);

        if (i <= 0)
        {
            return false;
        }
        
        int len = *((int*)lenbuf);
        
        char *buf = new char[len];
        i = recv(this->m_sockClient, buf, len, 0);
        if (i > 0)
        {
            NetData data(buf, i);
            this->m_func(data);
            delete[]buf;
            return true;
        }else{
#ifdef WIN32
            CCLOG("error code: %d" , WSAGetLastError());
#endif
        }
        delete[]buf;
        return false;
    }
    
    void CGameSocket::SetRecvCallBack(RecvCallBack func){
        this->m_func = func;
    }

C#的socket I/O  和 上述I/O 後期都會改 但不影響功能。