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 后期都会改 但不影响功能。