CMyNetModual.h
//此模块是用来创建socket与服务器通信用的
#ifndef __MY_NET_MODUAL_H__
#define __MY_NET_MODUAL_H__
#include "inc.h"
#define TCP_MODE 1
#define UDP_MODE 2
#define HTTP_GET_MODE 3 //get 方式
#define HTTP_POST_MODE 4 //post 方式
enum HTTP_STATE_ENUM
{
NET_TIME_OUT = -7,
NET_CON_ERROR = -6,
NET_CREATE_ERROR = -5,
NET_READ_ERROR = -4, //读取数据错误
NET_WRITE_ERROR = -3,
NET_CLOSE = -2, //服务器断开网络
NET_ERROR = -1,
NET_CON_SUCCESS = 0,
NET_CON_ING,
NET_CON_WOULDBLOCK, //非阻塞标记
NET_SEND_HEAD,
NET_SEND_POST,
NET_READ_HEAD,
NET_READ,
NET_WRITE,
NET_FINISH,
};
//暂时定为30秒(一秒跑的次数)*30(秒)
#define NETOUTTIMES (60*30)
//读取数据大小
#define NET_BUF_LEN (1024*4)
//定义回调函数指针
//event:事件 index:标志 buf:数据 len:数据长度
//如果收到NET_SEND_POST消息则传NET_DATA_STRUCT(要发送的数据和长度)填充到此指针中
typedef void (*NET_CALLBACK)( int event, int index, void* buf, int len );
//socket的管理类,主要实现创建哪种类型的socket,连接,发送数据,接收数据等
class CMyNetModual
{
public:
//http的方式联网 默认是80 retry默认传0
CMyNetModual(char* Address, int port, int retry, NET_CALLBACK callback ,char* postContent, int postlen );
//socket方式联网 mode = 1表示TCP mode = 0表示UDP 端口默认是80 方式默认是TCP 重试次数默认是3次
CMyNetModual(char* Address, int port, int mode, int retry, NET_CALLBACK callback,char* postContent, int postlen );
~CMyNetModual();
void init(void);
//socket操作
int Create(void);
int Close(void);
int Connect(void);
int Send( void *data, int len );
int Recv( void *data, int len );
int IsConnectError(void);
public:
//网络返回状态200 206是正常其它是错误 -1是没有接收到头
int net_http_status;
//网络状态
int net_status;
//0: UDP, 1: TCP 2:http
int net_mode;
//sock索引
int net_index;
//联网失败重试次数
int net_tolretry;
//当前连接次数
int net_curretry;
//ip地址
char net_ip[32];
int net_port;
//url
char net_url[256];
//时间记录
int timecount;
//sockid句柄
int net_handle;
//接收头数据 post发送的时候用来存储发送的字节数
char net_headbuf[NET_BUF_LEN];
//要接收的数据长度 用于HTTP
int net_total_len;
//已接收的数据长度 用于HTTP
int net_dl_len;
int m_postlen;
NET_CALLBACK net_callback;
public:
//分析adress adress:传进来的地址 host: 主机地址 port: 端口
//返回值:判断地址是否IP -1:错误参数 ip:true or false
int AnalizeAdress( char *adress, char* host );
};
#endif
单个socket的实现管
构建一些创建socket的条件,如服务器地址,端口,发送内容,发送长度,以及网络的回调
void CMyNetModual::init()//初始化成员变量
{
net_status = -1;
net_http_status = -1;
net_mode = 1;
net_index = 0;
net_tolretry = 3;
net_curretry = 0;
memset( net_ip, 0, sizeof(net_ip) );
memset( net_url, 0, sizeof(net_url) );
net_port = 0;
net_callback = 0;
net_handle = 0;
timecount = 0;
net_total_len = 0;
net_dl_len = 0;
m_postlen = 0;
}
//构建一些创建socket的条件,如服务器地址,端口,发送内容,发送长度,以及网络的回调
CMyNetModual::CMyNetModual(char* Address, int port, int retry, NET_CALLBACK callback ,char* postContent, int postlen )
{
init();
if ( retry > 0 )
{
net_tolretry = retry;
}
memcpy( net_url, Address, sizeof(net_url) );
net_port = port;
net_callback = callback;
memset( net_headbuf, 0, NET_BUF_LEN );
if ( postContent )
{
memcpy( net_headbuf, postContent, postlen );
}
m_postlen = postlen;
}
CMyNetModual::CMyNetModual(char* Address, int port, int mode, int retry, NET_CALLBACK callback,char* postContent, int postlen )
{
init();
if ( retry > 0 )
{
net_tolretry = retry;
}
strcpy( (char*)net_url, Address );
net_port = port;
net_callback = callback;
net_mode = mode;
memset( net_headbuf, 0, NET_BUF_LEN );
if ( postContent )
{
memcpy( net_headbuf, postContent, postlen );
}
m_postlen = postlen;
}
//关闭socket
CMyNetModual::~CMyNetModual()
{
if ( net_handle >= 0 )
{
#ifdef _WIN32
closesocket( net_handle );
#else
close( net_handle );
#endif
}
}
当构建好创建一个socket的必须条件后,他应该有创建socket的方法
int CMyNetModual::Create(void)
{
int mode = (net_mode == UDP_MODE) ? SOCK_DGRAM:SOCK_STREAM;
int socketid = socket( AF_INET, mode, 0 ); //得到socket句柄
#ifdef _WIN32
if( socketid < 0 )
{
int error = WSAGetLastError();
CCLog( "network Create socket error = %d", error );
}
#endif
CCLog( "network Create socket id = %d", socketid );
//memset( net_headbuf, 0, sizeof(net_headbuf) );
if ( socketid >= 0 )
{
#ifdef _WIN32
unsigned long ul = 1;
ioctlsocket(socketid, FIONBIO, &ul); //设置为非阻塞模式
#else
int flags, s;
flags = fcntl (socketid, F_GETFL, 0);
if (flags == -1)
{
close(socketid);
return -1;
}
flags |= O_NONBLOCK;
s = fcntl (socketid, F_SETFL, flags);
if (s == -1)
{
close(socketid);
return -1;
}
#endif
net_handle = socketid; //返回socket的句柄
return net_handle;
}
return NET_CREATE_ERROR;
}
其中 win32环境设置和linux环境设置socket的为非阻塞模式不同
socket的关闭操作
int CMyNetModual::Close()
{
if ( net_handle >= 0 )
{
#ifdef _WIN32
closesocket( net_handle );
#else
close( net_handle );
#endif
}
net_handle = -1;
return 0;
}
socket的连接操作
int CMyNetModual::Connect(void)
{
struct sockaddr_in sin = {0};
char host[32] = {0};
struct hostent* hostmsg = NULL;
//先获取IP地址
//重试的时候不用在获取IP地址: strlen( net_ip )
if ( strlen( net_ip ) == 0 && AnalizeAdress( net_url, net_ip ) != 1 )
{
//阻塞模式
CCLog( "network before gethostbyname" );
hostmsg = gethostbyname( (char*)net_ip );
if(hostmsg == NULL)
return NET_CON_ERROR;
CCLog( "network after gethostbyname" );
memset( host, 0, sizeof(host) );
#ifdef _WIN32
struct in_addr addr;
addr.s_addr = *(u_long *)hostmsg->h_addr_list[0];
strcpy( net_ip, (char*)inet_ntoa(addr) );
#else
if( inet_ntop(hostmsg->h_addrtype, (void*)hostmsg->h_addr_list[0], (char*)host, sizeof(host) ) )
{
//IP
memset( net_ip, 0, sizeof(net_ip) );
memcpy( net_ip, host, strlen(host) );
CCLog( "network before connect ip = %s-----", net_ip );
}
else
{
//inet_ntop返回NULL
CCLog( "network before connect ip = ERROR");
return NET_ERROR;
}
#endif
}
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(net_ip);
sin.sin_port = htons(net_port);
CCLog( "network before connect" );
int nRet = connect( net_handle, (struct sockaddr*)&sin, sizeof(sin) );
net_status = NET_CON_ING; //设置当前socket的网络连接状态为连接中
if ( nRet == -1 )
{
//判断是否是阻塞
#ifdef _WIN32
int errValue = WSAGetLastError();
CCLog( "network socket connect = -1 errValue= %d", errValue );
if ( errValue == WSAEWOULDBLOCK )
{
return NET_CON_WOULDBLOCK;
}
else
{
return NET_CON_ERROR;
}
#else
int errValue = errno;
CCLog( "network socket connect errno= %d", errno );
if ( errValue == EINPROGRESS )
{
return NET_CON_WOULDBLOCK;
}
else
{
return NET_CON_ERROR;
}
#endif
}
CCLog( "network socket connect success ret= %d", nRet );
return NET_CON_SUCCESS;
}
封装socket的发送操作 linux 和win32 不同
int CMyNetModual::Send( void *data, int len )
{
#ifdef _WIN32
return send( net_handle, (char*)data, len, 0 );
#else
if ( data )
{
CCLog( "network send data = %s len = %d", (char*)data, len );
}
else
{
CCLog( "data = NULL");
}
int sendlen = send( net_handle, (char*)data, len, MSG_NOSIGNAL );
CCLog( "network sed len = %d", sendlen );
return sendlen;
#endif
}
封装socket对象的接收操作
int CMyNetModual::Recv( void *data, int len )
{
return recv( net_handle, (char*)data, len, 0 );
}
解析主机地址,判断是否为ip地址
//www.xxx.com/xxxxx
//10.0.0.0:xxxx/xxxx
int CMyNetModual::AnalizeAdress( char *adress, char* host )
{
if ( !adress || !host )
{
return -1;
}
char *httpflag = strstr( adress, (char*)"http://" );
//不带http://则指向头
if ( httpflag == NULL )
{
httpflag = adress;
}
else
{
httpflag += strlen( (char*)"http://" );
}
char *endflag = strchr( httpflag, (char)':' );
//不带/则指向尾
if ( endflag == NULL )
{
endflag = strchr( httpflag, (char)'/' );
if ( endflag == NULL )
{
endflag = httpflag + strlen( httpflag );
}
}
//取主机地址
memcpy( host, httpflag, endflag - httpflag );
//判断是否IP
int adress_len = strlen( host );
for ( int i = 0; i < adress_len; i++ )
{
if ( isdigit(host[i]) == 0 && host[i] != '.' )
{
return 0;
}
}
return 1;
}
由此,socket的通信模块已经完成,任何一种通信模式都是一个
CMyNetModual的对象 封装了 创建socket句柄,连接,发送,接收数据等操作