second commit

This commit is contained in:
HuYingzhuo(hugo/hyzboy) 2022-05-25 19:03:06 +08:00
parent 3b79e74770
commit a9a24d8f80
60 changed files with 7482 additions and 0 deletions

11
CMakeLists.txt Normal file
View File

@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.0)
project(CMNetwork)
include(path_config.cmake)
CMAudioSetup(${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(${CMNETWORK_ROOT_SOURCE_PATH})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/Plug-Ins)

View File

@ -0,0 +1,48 @@
#ifndef HGL_NETWORK_ACCEPT_SERVER_INCLUDE
#define HGL_NETWORK_ACCEPT_SERVER_INCLUDE
#include<hgl/network/ServerSocket.h>
namespace hgl
{
namespace network
{
/**
* 使Accept处理接入的服务器基类
*/
class AcceptServer:public ServerSocket ///使用Accept创建接入的服务器基类
{
char *ipstr;
fd_set accept_set;
struct timeval accept_timeout,ato;
protected:
virtual int CreateServerSocket()=0; ///<创建Server Socket
protected:
double overload_wait;
public:
AcceptServer()
{
overload_wait=HGL_SERVER_OVERLOAD_RESUME_TIME;
ipstr = nullptr;
FD_ZERO(&accept_set);
hgl_zero(accept_timeout);
SetTimeOut(HGL_NETWORK_TIME_OUT);
}
virtual ~AcceptServer(){SAFE_CLEAR(ipstr);}
void SetTimeOut(const double);
virtual int Accept(IPAddress *); ///<接入一个socket连接
};//class AcceptServer
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_ACCEPT_SERVER_INCLUDE

View File

@ -0,0 +1,108 @@
#ifndef HGL_NETWORK_DIRECT_SOCKET_IO_USER_THREAD_INCLUDE
#define HGL_NETWORK_DIRECT_SOCKET_IO_USER_THREAD_INCLUDE
#include<hgl/network/TCPSocket.h>
#ifdef HGL_NETWORK_SCTP_SUPPORT
#include<hgl/network/SCTPSocket.h>
#endif//HGL_NETWORK_SCTP_SUPPORT
#include<hgl/network/SocketInputStream.h>
#include<hgl/network/SocketOutputStream.h>
#include<hgl/io/DataInputStream.h>
#include<hgl/io/DataOutputStream.h>
#include<hgl/thread/Thread.h>
namespace hgl
{
using namespace hgl::io;
namespace network
{
template<typename DIS,typename DOS,typename S>
class DirectSocketIOUserThread:public Thread
{
bool IsExitDelete()const override {return true;} ///<返回在退出线程时,是否删除本对象
protected:
int sock;
IPAddress *addr;
S *s;
SocketInputStream *sis;
SocketOutputStream *sos;
DataInputStream *dis;
DataOutputStream *dos;
public:
bool block; ///<是否使用阻塞模式
double block_send_time; ///<阻塞时间
double block_recv_time;
double wait_time; ///<数据等待时间
public:
DirectSocketIOUserThread(int s,const IPAddress *sa)
{
sock=s;
addr=sa->CreateCopy();
block=true;
block_recv_time=1;
block_send_time=1;
wait_time=10;
}
virtual bool ProcStartThread() override
{
s=new S(sock,addr);
sis=new SocketInputStream(sock);
sos=new SocketOutputStream(sock);
dis=new DIS(sis);
dos=new DOS(sos);
s->SetBlock(block,block_send_time,block_recv_time);
return(true);
}
virtual ~DirectSocketIOUserThread()
{
SAFE_CLEAR(addr);
SAFE_CLEAR(dis);
SAFE_CLEAR(dos);
SAFE_CLEAR(sos);
SAFE_CLEAR(sis);
SAFE_CLEAR(s);
}
virtual bool Update()=0;
virtual bool IdleUpdate(){return(true);}
virtual bool Execute() override
{
int wr=s->WaitRecv(wait_time);
if(wr<0)
RETURN_FALSE;
if(wr==0)
return IdleUpdate();
return Update();
}
};//class DirectSocketIOUserThread
typedef DirectSocketIOUserThread<LEDataInputStream,LEDataOutputStream,TCPSocket> LETCPSocketIOUserThread;
typedef DirectSocketIOUserThread<BEDataInputStream,BEDataOutputStream,TCPSocket> BETCPSocketIOUserThread;
#ifdef HGL_NETWORK_SCTP_SUPPORT
typedef DirectSocketIOUserThread<LEDataInputStream,LEDataOutputStream,SCTPSocket> LESCTPSocketIOUserThread;
typedef DirectSocketIOUserThread<BEDataInputStream,BEDataOutputStream,SCTPSocket> BESCTPSocketIOUserThread;
#endif//HGL_NETWORK_SCTP_SUPPORT
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_DIRECT_SOCKET_IO_USER_THREAD_INCLUDE

View File

@ -0,0 +1,76 @@
#ifndef HGL_NETWORK_HTTP_INPUT_STREAM_INCLUDE
#define HGL_NETWORK_HTTP_INPUT_STREAM_INCLUDE
#include<hgl/io/InputStream.h>
#include<hgl/ut/PList.h>
#include<hgl/network/IP.h>
namespace hgl
{
namespace network
{
using namespace io;
class TCPClient;
/**
* HTTPInputStream流是一个针对HTTP服务器的流式访问类HTTP服务器上下载文件InputStream类派生<br>
* Position和Size也只能读不能修改<br>
*/
class HTTPInputStream:public io::InputStream ///HTTP流式访问类
{
TCPClient *tcp;
InputStream *tcp_is;
private:
char *http_header;
uint http_header_size;
void ParseHttpResponse();
int PraseHttpHeader();
int ReturnError();
protected:
int64 pos;
int64 filelength;
uint response_code; //HTTP响应代码
UTF8String response_info; //HTTP响应信息
UTF8PList response_list; //响应信息
public:
HTTPInputStream();
~HTTPInputStream();
bool Open(IPAddress *,const UTF8String &,const UTF8String &); ///<打开一个网址
void Close() override; ///<
uint GetResponseCode()const{return response_code;} ///<返回HTTP响应代码
const UTF8String & GetResponseInfo()const{return response_info;} ///<返回HTTP响应信息
const UTF8PList & GetResponseList()const{return response_list;} ///<返回HTTP响应信息列表
int64 Read(void *,int64) override; ///<读取数据
int64 Peek(void *,int64) override{return 0;} ///<预览数据
int64 ReadFully(void *buf,int64 buf_size)override{return Read(buf,buf_size);} ///<充分读取,保证读取到指定长度的数据(不计算超时)
bool CanRestart()const override{return false;} ///<是否可以复位
bool CanSeek()const override{return false;} ///<是否可以定位
bool CanSize()const override{return false;} ///<是否可以取得尺寸
bool CanPeek()const override{return false;} ///<是否可以预览数据
bool Restart() override{return false;} ///<复位访问指针
int64 Skip(int64) override{return 0;} ///<跳过指定字节不访问
int64 Seek(int64,SeekOrigin=soBegin) override {return false;} ///<移动访问指针
int64 Tell()const override{return pos;} ///<返回当前访问位置
int64 GetSize()const override{return filelength;} ///<取得流长度
int64 Available()const override{return filelength-pos;} ///<剩下的可以不受阻塞访问的字节数
};//class HTTPInputStream
}//namespace network
using namespace network;
}//namespace hgl
#endif//HGL_NETWORK_HTTP_INPUT_STREAM_INCLUDE

View File

@ -0,0 +1,35 @@
#ifndef HGL_NETWORK_HTTP_TOOLS_INCLUDE
#define HGL_NETWORK_HTTP_TOOLS_INCLUDE
#include<hgl/type/BaseString.h>
#include<hgl/io/OutputStream.h>
namespace hgl
{
namespace network
{
/**
* HTTP/HTTPS所使用的功能实现
*/
namespace http
{
/**
* HTTP/HTTPS链接GET操作得到返回信息<br>
* HTTP信息头
*/
int get(io::OutputStream *,const char *,const char *user_agent=nullptr); ///<http/https get
int post(io::OutputStream *,const char *,const void *,const int,const char *user_agent=nullptr); ///<http/htpps post
inline int post(io::OutputStream *os,const char *url,const UTF8String &post_data,const char *user_agent=nullptr)
{
return post(os,url,post_data.c_str(),post_data.Length(),user_agent);
}
inline int post(io::OutputStream *os,const UTF8String &url,const UTF8String &post_data,const char *user_agent=nullptr)
{
return post(os,url.c_str(),post_data.c_str(),post_data.Length(),user_agent);
}
}//namespace http
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_HTTP_TOOLS_INCLUDE

114
inc/hgl/network/IOSocket.h Normal file
View File

@ -0,0 +1,114 @@
#ifndef HGL_NETWORK_IOSOCKET_INCLUDE
#define HGL_NETWORK_IOSOCKET_INCLUDE
#include<hgl/network/Socket.h>
namespace hgl
{
namespace network
{
/**
* Socket
*/
class IOSocket:public Socket ///传输数据用Socket基类
{
protected:
int64 send_total; ///<发送字节数统计
int64 recv_total; ///<接收字节数统计
double recv_time_out; ///<数据接收超时
double last_recv_time; ///<最后一次接收数据的时间
public:
IOSocket()
{
Clear();
}
virtual ~IOSocket()=default;
virtual void Clear()
{
send_total=0;
recv_total=0;
recv_time_out=HGL_NETWORK_DOUBLE_TIME_OUT;
last_recv_time=0;
}
virtual void CloseSocket()override ///<关闭连接
{
Socket::CloseSocket();
Clear();
}
virtual const double &GetRecvTimeOut()const{return recv_time_out;} ///<取得接收数据超时时间
virtual void SetRecvTimeOut(const double to){recv_time_out=to;} ///<设置接收数据超时时间
public: //事件函数
/**
*
* @param recv_buf_size (:-1)
* @param ct
* @return
*/
virtual int OnRecv(int recv_buf_size=-1,const double ct=0)
{
last_recv_time=ct;
return 0;
}
/**
*
* @param send_buf_size (:-1)
* @param left_bytes (0SOCKET从列表中反复添加删除)
* @return
*/
virtual int OnSend(int send_buf_size/*,int &left_bytes*/)
{
return 0;
}
/**
*
* @param errno_number
*/
virtual void OnError(int errno_number)
{
}
/**
*
*/
virtual void OnClose()
{
}
/**
* 便
* @return socket出错需要退出
*/
virtual bool OnUpdate()=0;
public: //属性函数
const int64 GetSendTotal()const{return send_total;} ///<取得发送字节数统计
const int64 GetRecvTotal()const{return recv_total;} ///<取得接收字节数统计
const void RestartLastRecvTime(){last_recv_time=0;} ///<复位最后获取数据时间
const double GetLastRecvTime()const{return last_recv_time;} ///<取得最后获取数据时间
const bool CheckRecvTimeOut(const double ct) ///<检测是否超时
{
if((last_recv_time>0)
&&(last_recv_time+recv_time_out<ct))
return(true);
return(false);
}
};//class IOSocket
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_IOSOCKET_INCLUDE

440
inc/hgl/network/IP.h Normal file
View File

@ -0,0 +1,440 @@
#ifndef HGL_NETWORK_IP_INCLUDE
#define HGL_NETWORK_IP_INCLUDE
#include<hgl/platform/Platform.h>
#if HGL_OS == HGL_OS_Windows
#include<ws2tcpip.h>
#if SOMAXCONN == 5
#error Please use <winsock2.h>
#endif//
typedef int socklen_t;
typedef ULONG in_addr_t;
#define GetLastSocketError() WSAGetLastError()
#ifndef SOCK_DCCP
#define SOCK_DCCP 6
#endif//SOCK_DCCP
#ifndef SOCK_PACKET
#define SOCK_PACKET 10
#endif//SOCK_PACKET
#ifndef IPPROTO_DCCP
#define IPPROTO_DCCP 33
#endif//IPPROTO_DCCP
#ifndef IPPROTO_UDPLITE
#define IPPROTO_UDPLITE 136
#endif//IPPROTO_UDPLITE
#else
#include<errno.h>
#include<sys/types.h>
#include<sys/ioctl.h>
#include<sys/socket.h>
#include<unistd.h>
#include<netdb.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#define GetLastSocketError() (errno)
#if HGL_OS == HGL_OS_Linux
#include<sys/sendfile.h>
inline int sendfile(int tfd,int sfd,size_t size)
{
return sendfile(tfd,sfd,nullptr,size);
}
#endif//HGL_OS == HGL_OS_Linux
#if HGL_OS == HGL_OS_FreeBSD
#include<sys/uio.h>
inline int sendfile(int tfd,int sfd,size_t size)
{
return sendfile(tfd,sfd,0,size,nullptr,nullptr,0);
}
#endif//HGL_OS == HGL_OS_FreeBSD
#if (HGL_OS == HGL_OS_macOS)||(HGL_OS == HGL_OS_iOS)
#ifndef IPPROTO_UDPLITE
#define IPPROTO_UDPLITE 136
#endif//IPPROTO_UDPLITE
#endif//
#endif//HGL_OS == HGL_OS_Windows
#include<hgl/type/DataType.h>
#include<hgl/type/List.h>
#include<hgl/type/BaseString.h>
#include<hgl/Str.h>
namespace hgl
{
namespace network
{
/**
* IP类型枚举
*/
enum IPType
{
iptNone=0,
iptV4,
iptV6,
iptEnd
};//enum IPType
inline IPType CheckIPType(const char *name)
{
if(!name)return(iptNone);
while(*name)
{
if(*name==':')return(iptV6);
if(*name=='.')return(iptV4);
++name;
}
return(iptNone);
}
struct IPSupport
{
uint family; ///<协议家族AF_INET,AF_INET6,AF_NETBIOS
uint socktype; ///<Socket类型SOCK_STREAM,SOCK_DGRAM,SOCK_RAW,SOCK_RDM,SOCK_SEQPACKET
uint protocol; ///<协议类型IPPROTO_TCP,IPPROTO_UDP,IPPROTO_SCTP
union
{
sockaddr_in ipv4;
sockaddr_in6 ipv6;
};
union
{
char ipv4str[INET_ADDRSTRLEN+1];
char ipv6str[INET6_ADDRSTRLEN+1];
};
};
int GetIPSupport(List<IPSupport> &); ///<取得本机IP支持列表
bool CheckIPSupport(const List<IPSupport> &ips_list,uint family,uint socktype,uint protocol);
bool CheckIPSupport(uint family,uint socktype,uint protocol);
inline bool CheckIPv4SupportTCP (){return CheckIPSupport(AF_INET,SOCK_STREAM, IPPROTO_TCP );}
inline bool CheckIPv4SupportUDP (){return CheckIPSupport(AF_INET,SOCK_DGRAM, IPPROTO_UDP );}
inline bool CheckIPv4SupportUDPLite (){return CheckIPSupport(AF_INET,SOCK_DGRAM, IPPROTO_UDPLITE );}
inline bool CheckIPv4SupportSCTP (){return CheckIPSupport(AF_INET,SOCK_SEQPACKET,IPPROTO_SCTP );}
inline bool CheckIPv6SupportTCP (){return CheckIPSupport(AF_INET6,SOCK_STREAM, IPPROTO_TCP );}
inline bool CheckIPv6SupportUDP (){return CheckIPSupport(AF_INET6,SOCK_DGRAM, IPPROTO_UDP );}
inline bool CheckIPv6SupportUDPLite (){return CheckIPSupport(AF_INET6,SOCK_DGRAM, IPPROTO_UDPLITE );}
inline bool CheckIPv6SupportSCTP (){return CheckIPSupport(AF_INET6,SOCK_SEQPACKET,IPPROTO_SCTP );}
/**
* IP地址类
*/
class IPAddress
{
protected:
int socktype;
int protocol;
const char *protocol_name;
void RefreshProtocolName();
public:
IPAddress()
{
socktype=0;
protocol=0;
protocol_name=nullptr;
}
IPAddress(int s,int p)
{
socktype=s;
protocol=p;
RefreshProtocolName();
}
virtual ~IPAddress()=default;
virtual const int GetFamily()const=0; ///<返回网络家族
const int GetSocketType()const{return socktype;} ///<返回Socket类型
const int GetProtocol()const{return protocol;} ///<返回协议类型
virtual const uint GetIPSize()const=0; ///<取得IP地址的长度
virtual const uint GetSockAddrInSize()const=0; ///<取得SockAddrIn变量长度
virtual const uint GetIPStringMaxSize()const=0; ///<取得IP字符串最大长度
virtual const bool IsBoradcast()const=0; ///<是否为广播
virtual const char *GetProtocolName()const{return protocol_name;} ///<取得协议名称
/**
* IP地址
* @param _name
* @param _port
* @param socktype Socket类型(SOCK_STREAMSOCK_DGRAMSOCK_RAWSOCK_RDMSOCK_SEQPACKET等值),
* @param protocol (IPPROTO_TCPIPPROTO_UDPIPPROTO_SCTP),
*/
virtual bool Set(const char *_name,ushort _port,int socktype,int protocol)=0;
bool SetTCP (const char *_name,ushort _port){return Set(_name,_port,SOCK_STREAM, IPPROTO_TCP );}
bool SetUDP (const char *_name,ushort _port){return Set(_name,_port,SOCK_DGRAM, IPPROTO_UDP );}
bool SetUDPLite (const char *_name,ushort _port){return Set(_name,_port,SOCK_DGRAM, IPPROTO_UDPLITE );}
bool SetSCTP (const char *_name,ushort _port){return Set(_name,_port,SOCK_SEQPACKET, IPPROTO_SCTP );}
const bool IsTCP ()const{if(socktype!=SOCK_STREAM )return(false);if(protocol!=IPPROTO_TCP )return(false);return(true);}
const bool IsUDP ()const{if(socktype!=SOCK_DGRAM )return(false);if(protocol!=IPPROTO_UDP )return(false);return(true);}
const bool IsUDPLite ()const{if(socktype!=SOCK_DGRAM )return(false);if(protocol!=IPPROTO_UDPLITE )return(false);return(true);}
const bool IsSCTP ()const{if(socktype!=SOCK_SEQPACKET )return(false);if(protocol!=IPPROTO_SCTP )return(false);return(true);}
/**
*
*/
virtual void Set(ushort port)=0;
/**
* IP地址到一个socket上
* @param ThisSocket Socket号
* @param reuse IPtrue
*/
virtual bool Bind(int ThisSocket,int reuse=1)const=0;
/**
*
*/
virtual bool GetHostname(UTF8String &)const=0;
virtual sockaddr *GetSockAddr()=0;
virtual void *GetIP()=0;
/**
* IP信息
*/
virtual void GetIP(void *)=0;
/**
*
*/
virtual const ushort GetPort()const=0;
/**
* ,使GetIPStringMaxSize()
*/
virtual void ToString(char *,int)const=0;
/**
* delete[]
*/
virtual char *CreateString()const
{
const int max_size=GetIPStringMaxSize();
char *ipstr=new char[max_size+1];
ToString(ipstr,max_size);
return ipstr;
}
/**
*
*/
virtual IPAddress *CreateCopy()const=0;
/**
* IP地址副本
*/
virtual IPAddress *Create()const=0;
/**
* IP地址是否一样
*/
virtual bool Comp(const IPAddress *)const=0;
};//class IPAddress
/**
* IPv4地址
*/
class IPv4Address:public IPAddress
{
sockaddr_in addr;
public:
IPv4Address(){hgl_zero(addr);}
IPv4Address(const uint32 _addr,ushort port,int _socktype,int _protocol):IPAddress(_socktype,_protocol)
{
Set(_addr,port);
}
IPv4Address(const char *name,ushort port,int _socktype,int _protocol)
{
Set(name,port,_socktype,_protocol);
}
IPv4Address(ushort port,int _socktype,int _protocol)
{
Set(nullptr,port,_socktype,_protocol);
}
IPv4Address(const IPv4Address *src)
{
hgl_cpy(addr,src->addr);
socktype=src->socktype;
protocol=src->protocol;
}
const int GetFamily()const override{return AF_INET;}
const uint GetIPSize()const override{return sizeof(in_addr);}
const uint GetSockAddrInSize()const override{return sizeof(sockaddr_in);}
const uint GetIPStringMaxSize()const override{return INET_ADDRSTRLEN+6;}
const bool IsBoradcast()const override{return(addr.sin_addr.s_addr==htonl(INADDR_BROADCAST));}
bool Set(const char *name,ushort port,int _socktype,int _protocol) override;
void Set(const uint32 _addr,ushort port)
{
hgl_zero(addr);
addr.sin_family =AF_INET;
addr.sin_addr.s_addr=_addr;
addr.sin_port =htons(port);
}
void Set(ushort port) override;
bool Bind(int ThisSocket,int reuse=1)const override;
bool GetHostname(UTF8String &)const override;
sockaddr *GetSockAddr()override{return (sockaddr *)&addr;}
void *GetIP() override {return &(addr.sin_addr);}
void GetIP(void *data) override { memcpy(data,&(addr.sin_addr),sizeof(in_addr)); }
const uint32 GetInt32IP()const{return addr.sin_addr.s_addr;}
const ushort GetPort()const override;
static void ToString(char *str,const int,const in_addr *);
static void ToString(char *str,const int,const sockaddr_in *);
void ToString(char *str,const int)const override;
static int GetDomainIPList(List<in_addr> &addr_list,const char *domain,int _socktype,int _protocol); ///<取得当指定域名的IPv4地址列表
static int GetLocalIPList(List<in_addr> &addr_list,int _socktype,int _protocol); ///<取得本机的IPv4地址列表
IPAddress *CreateCopy()const override{return(new IPv4Address(this));}
IPAddress *Create()const override{return(new IPv4Address());}
bool Comp(const IPAddress *ipa)const override;
};//class IPv4Address
/**
* IPv6地址
*/
class IPv6Address:public IPAddress
{
sockaddr_in6 addr;
public:
IPv6Address(){hgl_zero(addr);}
IPv6Address(const in6_addr *ip,ushort port,int _socktype,int _protocol):IPAddress(_socktype,_protocol)
{
hgl_zero(addr);
addr.sin6_family=AF_INET6;
memcpy(&(addr.sin6_addr),ip,sizeof(in6_addr));
addr.sin6_port=htons(port);
}
IPv6Address(const char *name,ushort port,int _socktype,int _protocol)
{
Set(name,port,_socktype,_protocol);
}
IPv6Address(ushort port,int _socktype,int _protocol)
{
Set(nullptr,port,_socktype,_protocol);
}
IPv6Address(const IPv6Address *src)
{
hgl_cpy(addr,src->addr);
socktype=src->socktype;
protocol=src->protocol;
}
const int GetFamily()const override{return AF_INET6;}
const uint GetIPSize()const override{return sizeof(in6_addr);}
const uint GetSockAddrInSize()const override{return sizeof(sockaddr_in6);}
const uint GetIPStringMaxSize()const override{return INET6_ADDRSTRLEN+6;}
const bool IsBoradcast()const override{return(false);}
bool Set(const char *name,ushort port,int _socktype,int _protocol) override;
void Set(ushort port) override;
bool Bind(int ThisSocket,int reuse=1)const override;
bool GetHostname(UTF8String &)const override;
sockaddr *GetSockAddr() override{return (sockaddr *)&addr;}
void *GetIP() override {return &(addr.sin6_addr);}
void GetIP(void *data) override{memcpy(data,&(addr.sin6_addr),sizeof(in6_addr));}
const ushort GetPort()const override;
static void ToString(char *str,const int,const in6_addr *);
static void ToString(char *str,const int,const sockaddr_in6 *);
void ToString(char *str,const int)const override;
static int GetDomainIPList(List<in6_addr> &addr_list,const char *domain,int _socktype,int _protocol); ///<取得指定域名的IPv6地址列表
static int GetLocalIPList(List<in6_addr> &addr_list,int _socktype,int _protocol); ///<取得本机的IPv6地址列表
IPAddress *CreateCopy()const override{return(new IPv6Address(this));}
IPAddress *Create()const override{return(new IPv6Address());}
bool Comp(const IPAddress *ipa)const override;
};//class IPv6Address
inline IPv4Address *CreateIPv4TCP (const char *name,ushort port){return(new IPv4Address(name,port,SOCK_STREAM, IPPROTO_TCP));}
inline IPv6Address *CreateIPv6TCP (const char *name,ushort port){return(new IPv6Address(name,port,SOCK_STREAM, IPPROTO_TCP));}
inline IPv4Address *CreateIPv4UDP (const char *name,ushort port){return(new IPv4Address(name,port,SOCK_DGRAM, IPPROTO_UDP));}
inline IPv6Address *CreateIPv6UDP (const char *name,ushort port){return(new IPv6Address(name,port,SOCK_DGRAM, IPPROTO_UDP));}
inline IPv4Address *CreateIPv4UDPLite (const char *name,ushort port){return(new IPv4Address(name,port,SOCK_DGRAM, IPPROTO_UDPLITE));}
inline IPv6Address *CreateIPv6UDPLite (const char *name,ushort port){return(new IPv6Address(name,port,SOCK_DGRAM, IPPROTO_UDPLITE));}
inline IPv4Address *CreateIPv4SCTP (const char *name,ushort port){return(new IPv4Address(name,port,SOCK_SEQPACKET, IPPROTO_SCTP));}
inline IPv6Address *CreateIPv6SCTP (const char *name,ushort port){return(new IPv6Address(name,port,SOCK_SEQPACKET, IPPROTO_SCTP));}
inline IPv4Address *CreateIPv4TCP (const uint32 &ip,ushort port){return(new IPv4Address(ip,port,SOCK_STREAM, IPPROTO_TCP));}
inline IPv4Address *CreateIPv4UDP (const uint32 &ip,ushort port){return(new IPv4Address(ip,port,SOCK_DGRAM, IPPROTO_UDP));}
inline IPv4Address *CreateIPv4UDPLite (const uint32 &ip,ushort port){return(new IPv4Address(ip,port,SOCK_DGRAM, IPPROTO_UDPLITE));}
inline IPv4Address *CreateIPv4SCTP (const uint32 &ip,ushort port){return(new IPv4Address(ip,port,SOCK_SEQPACKET, IPPROTO_SCTP));}
inline IPv6Address *CreateIPv6TCP (const in6_addr *ip,ushort port){return(new IPv6Address(ip,port,SOCK_STREAM, IPPROTO_TCP));}
inline IPv6Address *CreateIPv6UDP (const in6_addr *ip,ushort port){return(new IPv6Address(ip,port,SOCK_DGRAM, IPPROTO_UDP));}
inline IPv6Address *CreateIPv6UDPLite (const in6_addr *ip,ushort port){return(new IPv6Address(ip,port,SOCK_DGRAM, IPPROTO_UDPLITE));}
inline IPv6Address *CreateIPv6SCTP (const in6_addr *ip,ushort port){return(new IPv6Address(ip,port,SOCK_SEQPACKET, IPPROTO_SCTP));}
inline IPv4Address *CreateIPv4TCP (ushort port){return(new IPv4Address(port,SOCK_STREAM, IPPROTO_TCP));}
inline IPv6Address *CreateIPv6TCP (ushort port){return(new IPv6Address(port,SOCK_STREAM, IPPROTO_TCP));}
inline IPv4Address *CreateIPv4UDP (ushort port){return(new IPv4Address(port,SOCK_DGRAM, IPPROTO_UDP));}
inline IPv6Address *CreateIPv6UDP (ushort port){return(new IPv6Address(port,SOCK_DGRAM, IPPROTO_UDP));}
inline IPv4Address *CreateIPv4UDPLite (ushort port){return(new IPv4Address(port,SOCK_DGRAM, IPPROTO_UDPLITE));}
inline IPv6Address *CreateIPv6UDPLite (ushort port){return(new IPv6Address(port,SOCK_DGRAM, IPPROTO_UDPLITE));}
inline IPv4Address *CreateIPv4SCTP (ushort port){return(new IPv4Address(port,SOCK_SEQPACKET, IPPROTO_SCTP));}
inline IPv6Address *CreateIPv6SCTP (ushort port){return(new IPv6Address(port,SOCK_SEQPACKET, IPPROTO_SCTP));}
inline IPv4Address *CreateIPv4UDPBoradcast (ushort port){return(new IPv4Address(htonl(INADDR_BROADCAST),port,SOCK_DGRAM, IPPROTO_UDP));}
inline IPv4Address *CreateIPv4UDPLiteBoradcast (ushort port){return(new IPv4Address(htonl(INADDR_BROADCAST),port,SOCK_DGRAM, IPPROTO_UDPLITE));}
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_IP_TOOL_INCLUDE

View File

@ -0,0 +1,17 @@
#ifndef HGL_NETWORK_JAVA_DIRECT_SOCKET_IO_USER_THREAD_INCLUDE
#define HGL_NETWORK_JAVA_DIRECT_SOCKET_IO_USER_THREAD_INCLUDE
#include<hgl/network/DirectSocketIOUserThread.h>
#include<hgl/io/JavaInputStream.h>
#include<hgl/io/JavaOutputStream.h>
namespace hgl
{
using namespace hgl::io;
namespace network
{
typedef DirectSocketIOUserThread<JavaInputStream,JavaOutputStream> JavaDirectSocketIOUserThread;
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_JAVA_DIRECT_SOCKET_IO_USER_THREAD_INCLUDE

View File

@ -0,0 +1,163 @@
#ifndef HGL_NETWORK_MULTI_THREAD_TCP_SERVER_INCLUDE
#define HGL_NETWORK_MULTI_THREAD_TCP_SERVER_INCLUDE
#include<hgl/network/TCPAccept.h>
#include<hgl/network/TCPServer.h>
#include<hgl/network/MultiThreadAccept.h>
#include<hgl/network/SocketManageThread.h>
#include<hgl/Time.h>
namespace hgl
{
namespace network
{
/**
* 线TCP服务器
*/
template<typename USER_ACCEPT,typename SOCKET_MANAGE_THREAD> class MTTCPServer
{
protected:
class Accept2SocketManageThread:public AcceptThread
{
SOCKET_MANAGE_THREAD *sm_thread;
public:
using AcceptThread::AcceptThread;
void SetSocketManage(SOCKET_MANAGE_THREAD *smt)
{
sm_thread=smt;
}
bool OnAccept(int client_sock,IPAddress *ip_address) override
{
if(!sm_thread)return(false);
USER_ACCEPT *us;
us=new USER_ACCEPT(client_sock,ip_address); //这个new非常占时间未来放到各自的线程去做
auto &sl=sm_thread->JoinBegin();
sl.Add(us);
sm_thread->JoinEnd();
return(true);
}
};//class Accept2SocketManageThread:public AcceptThread
protected:
IPAddress * server_ip=nullptr;
TCPServer server;
MultiThreadAccept<Accept2SocketManageThread> accept_manage;
MultiThreadManage<SOCKET_MANAGE_THREAD> sock_manage;
protected:
virtual SOCKET_MANAGE_THREAD *CreateSocketManageThread(int max_user)
{
SocketManage *sm=new SocketManage(max_user);
SOCKET_MANAGE_THREAD *smt=new SOCKET_MANAGE_THREAD(sm);
return smt;
}
public:
/**
*
*/
struct InitInfomation
{
IPAddress * server_ip =nullptr; ///<服务器IP地址
bool port_reuse =false; ///<端口复用
bool ipv6_only =false; ///<是否使用IPv6 Only
bool block =true; ///<是否使用阻塞模式
uint defer_accept_time =1; ///<延迟Accept成功超时时间,单位:秒(第一次收到数据才会成功Accept这里指从connect到第一个包的超时时间)
double accept_time_out =1; ///<Accept超时时间,单位:秒
uint max_user =1024; ///<最大用户数量
uint thread_count =4; ///<线程数量
};//struct MTTCPServerInitInfomation
bool Init(InitInfomation &info)
{
if(!info.server_ip)return(false);
if(info.max_user<=0)return(false);
if(info.thread_count<=0)return(false);
if(!server.CreateServer(info.server_ip,info.max_user,info.port_reuse))
return(false);
if(info.server_ip->GetFamily()==AF_INET6) //如果是IPv6地址
server.SetIPv6Only(info.ipv6_only); //设置是否仅使用IPv6,这个有可能失败,但是不管它
server.SetBlock(true); //设置使用阻塞模式
#if HGL_OS != HGL_OS_Windows
server.SetDeferAccept(info.defer_accept_time); //指定时间内收到数据才会产生accept
#endif
server.SetTimeOut(info.accept_time_out); //设置accept超时时间
if(!accept_manage.Init(&server,info.thread_count))
return(false);
for(int i=0;i<info.thread_count;i++)
{
Accept2SocketManageThread *at=accept_manage.GetAcceptThread(i);
SOCKET_MANAGE_THREAD *smt=CreateSocketManageThread(info.max_user);
at->SetSocketManage(smt);
sock_manage.Add(smt);
}
if(!sock_manage.Start())
return(false);
if(!accept_manage.Start())
{
sock_manage.Close();
return(false);
}
server_ip=info.server_ip;
return(true);
}
int IsLive()
{
return(sock_manage.IsLive()+accept_manage.IsLive());
}
bool Wait(const double &time_out=HGL_NETWORK_TIME_OUT)
{
WaitTime(time_out);
const int live_s=sock_manage.IsLive();
const int live_a=accept_manage.IsLive();
if(live_s+live_s<=0)
return(false);
#ifdef _DEBUG
std::cout<<"live accept thread "<<live_a<<", sock thread: "<<live_s<<std::endl;
#endif//_DEBUG
return(true);
}
};//template<typename USER_ACCEPT,typename SOCKET_MANAGE_THREAD> class MTTCPServer
template<typename USER_ACCEPT>
using MTTCPServerStd=MTTCPServer<USER_ACCEPT,SocketManageThread<USER_ACCEPT>>;
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_MULTI_THREAD_TCP_SERVER_INCLUDE

View File

@ -0,0 +1,88 @@
#ifndef HGL_NETWORK_MULTI_THREAD_ACCEPT_INCLUDE
#define HGL_NETWORK_MULTI_THREAD_ACCEPT_INCLUDE
#include<hgl/thread/Thread.h>
#include<hgl/type/Stack.h>
#include<hgl/thread/Semaphore.h>
namespace hgl
{
namespace network
{
class IPAddress;
class AcceptServer;
using IPAddressStack=Stack<IPAddress *>;
/**
* Socket接入线程
*/
class AcceptThread:public Thread
{
AcceptServer *server;
Semaphore *active_semaphore;
protected:
IPAddressStack ip_stack; ///<IP地址空间堆栈会提前分配好空间供未来使用
public:
AcceptThread(AcceptServer *,Semaphore *);
virtual ~AcceptThread()=default;
bool Execute() override;
public:
/**
*
* @param sock Socket值
* @param addr ip地址(:delete)
*/
virtual bool OnAccept(int sock,IPAddress *addr)=0; ///<接入一个新Socket
};//class AcceptThread:public Thread
/**
* Socket接入线程管理模板
*/
template<typename ACCEPT_THREAD> class MultiThreadAccept
{
MultiThreadManage<ACCEPT_THREAD> accept_thread_manage;
Semaphore active_semaphore;
public:
virtual ~MultiThreadAccept()=default;
bool Init(AcceptServer *server,const uint thread_count)
{
if(!server)return(false);
if(thread_count<=0)return(false);
for(int i=0;i<thread_count;i++)
accept_thread_manage.Add(new ACCEPT_THREAD(server,&active_semaphore));
return(true);
}
ACCEPT_THREAD *GetAcceptThread(const int index)
{
return accept_thread_manage.GetThread(index);
}
bool Start (){return accept_thread_manage.Start()>0;}
int IsLive (){return accept_thread_manage.IsLive();}
bool Close (){return accept_thread_manage.Close();}
/**
*
*/
bool Wait(const double &time_over=5)
{
return active_semaphore.Acquire(time_over);
}
};//template<typename ACCEPT_THREAD> class MultiThreadAccept
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_MULTI_THREAD_ACCEPT_INCLUDE

View File

@ -0,0 +1,28 @@
#ifndef HGL_NETWORK_SCTP_CLIENT_INCLUDE
#define HGL_NETWORK_SCTP_CLIENT_INCLUDE
#include<hgl/network/SCTPSocket.h>
namespace hgl
{
namespace network
{
/**
* SCTP一对一模式(one to one,tcp-style)<br>
* SCTP一对一模式(one to one,tcp-style)
*/
class SCTPO2OClient:public SCTPO2OSocket ///SCTP Client (tcp-style)
{
public:
SCTPO2OClient();
SCTPO2OClient(int);
~SCTPO2OClient();
virtual bool Connect(const sockaddr_in &); ///<连接到服务器
bool Connect(const char *,int); ///<接连到服务器
};//class SCTPO2OClient:public Socket
}//namespace network
using namespace network;
}//namespace hgl
#endif//HGL_NETWORK_SCTP_CLIENT_INCLUDE

View File

@ -0,0 +1,48 @@
#ifndef HGL_NETWORK_SCTP_SERVER_INCLUDE
#define HGL_NETWORK_SCTP_SERVER_INCLUDE
#include<hgl/network/AcceptServer.h>
#include<hgl/network/SCTPSocket.h>
namespace hgl
{
namespace network
{
/**
* SCTP一对一模式(one to one,tcp-style)
*/
class SCTPO2OServer:public AcceptServer
{
int CreateServerSocket() override final; ///<创建Server Socket
};//class SCTPO2OServer
/**
* SCTP一对多模式(one to many,udp-style)
*/
class SCTPO2MServer:public SCTPO2MSocket
{
public:
virtual bool CreateServer(const sockaddr_in &,const uint ml=HGL_SERVER_LISTEN_COUNT); ///<创建服务器
bool CreateServer(const char *,uint,const uint ml=HGL_SERVER_LISTEN_COUNT); ///<创建服务器
bool CreateServer(uint port,const uint ml=HGL_SERVER_LISTEN_COUNT) ///<创建服务器
{return CreateServer(nullptr,port,ml);}
virtual void CloseServer(); ///<关闭服务器
/**
* 使
* @param block 使(true/false)
* @param sto (: )
* @param rto (: )
*/
void SetBlock(bool block,double sto=HGL_NETWORK_TIME_OUT,
double rto=HGL_NETWORK_TIME_OUT) ///<设置是否使用堵塞方式
{
SetSocketBlock(ThisSocket,block,sto,rto);
}
void SetAutoClose(const int to); ///<设置自动关闭时间
};//class SCTPO2MServer
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_SCTP_SERVER_INCLUDE

View File

@ -0,0 +1,76 @@
#ifndef HGL_NETWORK_SCTP_SOCKET_INCLUDE
#define HGL_NETWORK_SCTP_SOCKET_INCLUDE
#include<hgl/network/Socket.h>
#include<hgl/MemBlock.h>
#include<netinet/sctp.h>
namespace hgl
{
namespace network
{
/**
* sctp socket功能基类
*/
class SCTPSocket:public Socket
{
protected:
int out_max_stream;
int in_max_stream;
int init_max_attempts;
int init_max_init_timeo;
sockaddr_in address;
bool GetMsg();
bool InitDataIOEvent();
bool InitMsg(int out_stream=0,int in_stream=0,int attempts=0,int init_time_out=0);
protected:
void ProcDisconnect()=default;
int ProcRecv(int)=default;
int ProcSend(int,int &)=default;
public:
virtual bool SetNodelay(bool); ///<设置是否使用无延迟方式
virtual bool SetMaxStream(int); ///<设置最大流数
public:
SCTPSocket();
virtual ~SCTPSocket()=default;
virtual void UseSocket(int,const sockaddr_in *addr=nullptr); ///<使用指定socket
};//class SCTPSocket
class SCTPO2OSocket:public SCTPSocket
{
struct sctp_sndrcvinfo sri_recv;
struct sctp_sndrcvinfo sri_send;
public:
using SCTPSocket::SCTPSocket;
virtual ~SCTPO2OSocket()=default;
virtual bool SendMsg(const void *,int len,uint16 stream); ///<发送一个数据包
virtual bool RecvMsg(MemBlock<char> *,uint16 &stream); ///<接收一个数据包
};
class SCTPO2MSocket:public SCTPSocket
{
public:
using SCTPSocket::SCTPSocket;
virtual ~SCTPO2MSocket()=default;
virtual bool Create(); ///<创建一个Socket
virtual bool SendMsg(const sockaddr_in *,void *,int len,uint16); ///<发送一个数据包
virtual bool RecvMsg(sockaddr_in &,void *,int max_len,int &len,uint16 &); ///<接收一个数据包
};//
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_SCTP_SOCKET_INCLUDE

View File

@ -0,0 +1,51 @@
#ifndef HGL_NETWORK_ThisSocket_INCLUDE
#define HGL_NETWORK_ThisSocket_INCLUDE
#include<hgl/network/Socket.h>
namespace hgl
{
namespace network
{
/**
* Socket共用基类
*/
class ServerSocket ///服务器端Socket共用基类
{
protected:
int ThisSocket;
IPAddress *server_address;
virtual int CreateServerSocket()=0; ///<创建Server Socket
public:
ServerSocket();
virtual ~ServerSocket();
const IPAddress *GetServerAddress()const{return server_address;} ///<取得服务器IP地址
IPAddress *CreateIPAddress()const
{return server_address?server_address->Create():nullptr;} ///<创建一个空的IP地址空间
bool CreateIPAddress(IPAddress **ip_buffer,int count)const; ///<创建多个空的IP地址空间
virtual bool CreateServer(const IPAddress *,const uint ml=HGL_SERVER_LISTEN_COUNT,bool reuse=false); ///<创建服务器
virtual void CloseServer(); ///<关闭服务器
/**
* 使
* @param block 使(true/false)
* @param sto (: )
* @param rto (: )
*/
void SetBlock(bool block,double sto=HGL_NETWORK_TIME_OUT,
double rto=HGL_NETWORK_TIME_OUT) ///<设置是否使用堵塞方式
{
SetSocketBlock(ThisSocket,block,sto,rto);
}
bool SetIPv6Only(bool); ///<设置仅使用IPv6
};//class ServerSocket
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_ThisSocket_INCLUDE

155
inc/hgl/network/Socket.h Normal file
View File

@ -0,0 +1,155 @@
#ifndef HGL_SOCKET_INCLUDE
#define HGL_SOCKET_INCLUDE
#include<hgl/network/IP.h>
//#define HGL_RECV_BYTE_COUNT ///<接收字节数统计(调试用)
//#define HGL_SEND_BYTE_COUNT ///<发送字节数统计(调试用)
//#define HGL_SOCKET_SEND_LIMIT_SIZE ///<发送限制包尺寸,默认为不限制
namespace hgl
{
namespace io
{
class DataInputStream;
class DataOutputStream;
}//namespace io
namespace network ///网络相关处理模块名字空间
{
constexpr uint HGL_NETWORK_MAX_PORT =65535; ///<最大端口号
constexpr uint HGL_NETWORK_IPv4_STR_MIN =7; ///<IPv4字符串最小字符数(0.0.0.0)
constexpr uint HGL_NETWORK_IPV4_STR_MAX =21; ///<IPv4字符串最大长度(255.255.255.255:65535)
enum SocketError
{
nseNoError =0, ///<没有错误
nseInt =4, ///<系统中断呼叫一般出现在Debug时的人工中断
nseIOError =5, ///<I/O错误
nseTooManyLink =24, ///<太多连接
nseBrokenPipe =32, ///<管道破裂,一般是因为发送到一半对方断开所引起
#if HGL_OS == HGL_OS_Windows
nseWouldBlock =WSAEWOULDBLOCK,
nseSoftwareBreak=WSAECONNABORTED, ///<我方软件主动断开
nsePeerBreak =WSAECONNRESET, ///<对方主动断开
nseTimeOut =WSAETIMEDOUT, ///<超时
#else
nseWouldBlock =EWOULDBLOCK, ///<请再次尝试(EAGIN/EWOULDBLACK值是一样的)
nseSoftwareBreak=ECONNABORTED, ///<我方软件主动断开
nsePeerBreak =ECONNRESET, ///<对方主动断开
nseTimeOut =ETIMEDOUT, ///<超时
#endif//
};//enum SocketError
/**
* Raw Packet length:
* UDP: MTU - IPHeader(20) - UDPHeader(8)
* TCP: MTU - IPHeader(20) - TCPHeader(20)
*
* Normal MTU:
* 1500 (Ethernet, DSL broadband)
* 1492 (PPPoE broadband)
* 576 (dial-up)
*/
constexpr uint HGL_SERVER_LISTEN_COUNT =SOMAXCONN; ///<Server最大监听数量
//Linux 是 128
//winsock 1.x SOMAXCONN是5
//winsock 2.x SOMAXCONN是0x7fffffff
constexpr uint HGL_NETWORK_TIME_OUT =HGL_TIME_ONE_MINUTE; ///<默认超时时间
constexpr uint HGL_NETWORK_HEART_TIME =HGL_NETWORK_TIME_OUT/2; ///<默认心跳时间(注:心跳并不是每隔指定时间都发送,而是离上一次发送任意封包超过指定时间才发送)
constexpr uint HGL_NETWORK_DOUBLE_TIME_OUT =HGL_NETWORK_TIME_OUT*2; ///<2次超时时间
constexpr uint HGL_SERVER_OVERLOAD_RESUME_TIME =10; ///<服务器超载再恢复等待时间
constexpr uint HGL_TCP_BUFFER_SIZE =HGL_SIZE_1KB*256; ///<TCP缓冲区大小
typedef int32 HGL_PACKET_SIZE; ///<包长度数据类型定义
typedef uint32 HGL_PACKET_TYPE; ///<包类型数据类型定义
constexpr uint HGL_PACKET_SIZE_BYTES =sizeof(HGL_PACKET_SIZE); ///<包长度数据类型字节数
constexpr uint HGL_PACKET_TYPE_BYTES =sizeof(HGL_PACKET_TYPE); ///<包类型数据类型字节数
constexpr uint HGL_PACKET_HEADER_BYTES =HGL_PACKET_SIZE_BYTES+HGL_PACKET_TYPE_BYTES; ///<包头数据类型字节数
class Socket;
class IOSocket;
#if HGL_OS == HGL_OS_Windows
bool InitWinSocket();
#endif//HGL_OS == HGL_OS_Windows
}//namespace network
namespace network
{
int CreateSocket(const IPAddress *); ///<创建Socket
void CloseSocket(int); ///<关闭socket
bool Connect(int,IPAddress *); ///<连接一个地址
void SetSocketBlock(int ThisSocket,bool block,double send_time_out=HGL_NETWORK_TIME_OUT,
double recv_time_out=HGL_NETWORK_TIME_OUT); ///<设置socket是否使用阻塞方式
void SetSocketLinger(int ThisSocket,int time_out); ///<设置Socket关闭时的确认数据发送成功超时时间
const os_char *GetSocketString(int);
#define GetLastSocketErrorString() GetSocketString(GetLastSocketError())
bool Read(io::DataInputStream *dis,IPAddress *addr);
bool Write(io::DataOutputStream *dos,const IPAddress *addr);
/**
* Socket通信类的基类
*/
class Socket ///Socket基类
{
protected:
IPAddress *ThisAddress; ///<本Socket地址
bool InitSocket(const IPAddress *); ///<创建Socket
public: //属性
int ThisSocket; ///<当前socket编号
public: //方法
Socket();
Socket(int,const IPAddress *);
virtual ~Socket();
const IPAddress *GetAddress()const{return ThisAddress;} ///<取得当前Socket的IP地址
virtual bool UseSocket(int,const IPAddress *); ///<使用这个Socket与地址
virtual bool ReCreateSocket(); ///<使用现有地址重新创建Socket
virtual void CloseSocket(); ///<关闭连接
/**
* 使
* @param block 使(true/false)
* @param sto (: )
* @param rto (: )
*/
void SetBlock(bool block,double sto=HGL_NETWORK_TIME_OUT,
double rto=HGL_NETWORK_TIME_OUT) ///<设置是否使用堵塞方式
{
SetSocketBlock(ThisSocket,block,sto,rto);
}
// public: //被动事件函数
//
// virtual void ProcDisconnect()=0; ///<断线事件处理函数
};//class Socket
}//namespace network
using namespace network;
}//namespace hgl
#endif//HGL_SOCKET_INCLUDE

View File

@ -0,0 +1,24 @@
#ifndef HGL_NETWORK_SOCKET_EVENT_INCLUDE
#define HGL_NETWORK_SOCKET_EVENT_INCLUDE
#include<hgl/platform/Platform.h>
#include<hgl/type/List.h>
namespace hgl
{
namespace network
{
struct SocketEvent
{
int sock;
union
{
int size; //数据长度(此属性为BSD系统独有)
int error; //错误号
};
};//struct SocketEvent
using SocketEventList=List<SocketEvent>;
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_SOCKET_EVENT_INCLUDE

View File

@ -0,0 +1,56 @@
#ifndef HGL_NETWORK_SOCKET_INPUT_STREAM_INCLUDE
#define HGL_NETWORK_SOCKET_INPUT_STREAM_INCLUDE
#include<hgl/io/InputStream.h>
namespace hgl
{
template<typename T> class MemBlock;
namespace network
{
/**
* Socket输入流TCPSCTP协议在无包封装处理的情况下
*/
class SocketInputStream:public io::InputStream
{
protected:
int sock;
MemBlock<char> *mb;
int64 total; //累计字节数
public:
SocketInputStream(int=0);
~SocketInputStream();
void SetSocket(int s)
{
sock=s;
total=0;
}
int64 GetTotal()const{return total;} ///<取得累计字节数
void Close(){} ///<关闭输入流
int64 Read(void *,int64); ///<从socket中读取指定的字节数
int64 Peek(void *,int64); ///<从socket中读取指定的字节数但不从缓存队列中删除
int64 ReadFully(void *,int64); ///<充分读取指定字节的数据
bool CanRestart()const{return false;} ///<是否可以复位
bool CanSeek()const{return false;} ///<是否可以定位
bool CanSize()const{return false;} ///<是否可以取得尺寸
bool CanPeek()const{return true;} ///<是否可以预览数据
bool Restart(){return false;} ///<复位访问指针
int64 Skip(int64); ///<跳过指定字节不访问
int64 Seek(int64,io::SeekOrigin=io::soBegin){return -1;} ///<移动访问指针
int64 Tell()const{return -1;} ///<返回当前访问位置
int64 GetSize()const{return -1;} ///<取得流长度
int64 Available()const; ///<剩下的可以不受阻塞访问的字节数
};//class SocketInputStream
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_SOCKET_INPUT_STREAM_INCLUDE

View File

@ -0,0 +1,68 @@
#ifndef HGL_NETWORK_SOCKET_MANAGE_INCLUDE
#define HGL_NETWORK_SOCKET_MANAGE_INCLUDE
#include<hgl/type/Map.h>
#include<hgl/network/SocketEvent.h>
#include<hgl/network/TCPAccept.h>
namespace hgl
{
namespace network
{
class SocketManageBase;
/**
* Socket管理类Update内处理socket的轮循和处理事件(recv还是send)<br>
* 线线使
*/
class SocketManage
{
protected:
using SocketList=Map<int,TCPAccept *>;
protected:
SocketList socket_list;
SocketManageBase *manage; ///<实际的Socket管理器
SocketEventList sock_recv_list,
sock_send_list,
sock_error_list;
Set<TCPAccept *> error_set;
protected:
void ProcSocketRecvList();
void ProcSocketSendList();
void ProcSocketErrorList();
void ProcErrorList();
public:
const Set<TCPAccept *> &GetErrorSocketSet(){return error_set;} ///<获取错误SOCKET合集
public:
SocketManage(int max_user);
virtual ~SocketManage();
bool Join(TCPAccept *s);
int Join(TCPAccept **s_list,int count);
bool Unjoin(TCPAccept *s);
int Unjoin(TCPAccept **s_list,int count);
/**
* (Socket,Socket<br>
* Update中轮循到的错误/Socket列表Update时清除Update后GetErrorSocketSet获取错误Socket合集并处理出错Socket
*/
virtual int Update(const double &time_out=HGL_NETWORK_TIME_OUT);
virtual void Clear();
};//class SocketManage
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_SOCKET_MANAGE_INCLUDE

View File

@ -0,0 +1,153 @@
#ifndef HGL_NETWORK_SOCKET_MANAGE_THREAD_INCLUDE
#define HGL_NETWORK_SOCKET_MANAGE_THREAD_INCLUDE
#include<hgl/network/SocketManage.h>
#include<hgl/thread/Thread.h>
#include<hgl/thread/SwapData.h>
namespace hgl
{
namespace network
{
/**
* Socket管理器线程
*/
template<typename USER_ACCEPT> class SocketManageThread:public Thread
{
public:
using AcceptSocketList=List<USER_ACCEPT *>; ///<工作对象列表定义
protected:
SocketManage *sock_manage;
protected:
SemSwapData<AcceptSocketList> join_list; ///<待添加的Socket对象列表
SemSwapData<AcceptSocketList> unjoin_list; ///<待移出的Socket对象列表
virtual void OnSocketClear(USER_ACCEPT *us){delete us;} ///<Socket清理事件
virtual void OnSocketError(USER_ACCEPT *us){OnSocketClear(us);} ///<Socket出错处理事件
template<typename ST>
void ClearAcceptSocketList(ST &sl)
{
const int count=sl.GetCount();
USER_ACCEPT **us=sl.GetData();
for(int i=0;i<count;i++)
{
OnSocketClear(*us);
++us;
}
sl.ClearData();
}
virtual bool Join(USER_ACCEPT *us){return sock_manage->Join(us);} ///<单个工作对象接入处理函数
virtual bool Unjoin(USER_ACCEPT *us){return sock_manage->Unjoin(us);} ///<单个工作对象退出处理函数
/**
*
*/
void ProcJoinList()
{
AcceptSocketList &usl=join_list.GetReceive();
const int count=usl.GetCount();
USER_ACCEPT **us=usl.GetData();
for(int i=0;i<count;i++)
{
Join(*us);
++us;
}
usl.ClearData();
}
/**
* 退
*/
void ProcUnjoinList()
{
AcceptSocketList &usl=unjoin_list.GetReceive();
const int count=usl.GetCount();
USER_ACCEPT **us=usl.GetData();
for(int i=0;i<count;i++)
{
Unjoin(*us);
++us;
}
usl.ClearData();
}
public:
SocketManageThread(SocketManage *sm)
{
sock_manage=sm;
}
virtual ~SocketManageThread()
{
SAFE_CLEAR(sock_manage);
}
virtual void ProcEndThread() override
{
ClearAcceptSocketList(join_list.GetReceive());
join_list.Swap();
ClearAcceptSocketList(join_list.GetReceive());
sock_manage->Clear();
//unjoin_list中的理论上都已经在wo_list/join_list里了所以不需要走Clear直接清空列表
unjoin_list.GetReceive().ClearData();
unjoin_list.Swap();
unjoin_list.GetReceive().ClearData();
}
virtual bool Execute() override
{
if(join_list.TrySemSwap())
ProcJoinList();
if(unjoin_list.TrySemSwap())
ProcUnjoinList();
sock_manage->Update(0.1); //这里写0.1秒只是为了不卡住主轮循。这是个错误的设计未来要将epoll(recv)完全独立一个线程跑
const auto &error_set=sock_manage->GetErrorSocketSet();
USER_ACCEPT **us=(USER_ACCEPT **)error_set.GetData();
for(int i=0;i<error_set.GetCount();i++)
{
OnSocketError(*us);
++us;
}
return(true);
}
public:
virtual AcceptSocketList & JoinBegin(){return join_list.GetPost();} ///<开始添加要接入的Socket对象
virtual void JoinEnd() ///<结束添加要接入的Socket对象
{
join_list.ReleasePost();
join_list.PostSem();
}
virtual AcceptSocketList & UnjoinBegin(){return unjoin_list.GetPost();}///<开始添加要退出的Socket对象
virtual void UnjoinEnd() ///<结束添加要退出的Socket对象
{
unjoin_list.ReleasePost();
unjoin_list.PostSem();
}
};//template<typename USER_ACCEPT> class SocketManageThread:public Thread
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_SOCKET_MANAGE_THREAD_INCLUDE

View File

@ -0,0 +1,54 @@
#ifndef HGL_NETWORK_SOCKET_OUTPUT_STREAM_INCLUDE
#define HGL_NETWORK_SOCKET_OUTPUT_STREAM_INCLUDE
#include<hgl/io/OutputStream.h>
namespace hgl
{
namespace network
{
/**
* Socket输出流TCPSCTP协议在无包封装处理的情况下
*/
class SocketOutputStream:public io::OutputStream
{
protected:
int sock;
int64 total; //累计字节数
public:
SocketOutputStream(int s=-1)
{
SetSocket(s);
}
~SocketOutputStream()=default;
void SetSocket(int s)
{
sock=s;
total=0;
}
void Close(){} ///<关闭输出流
int64 GetTotal()const{return total;} ///<取得累计字节数
int64 Write(const void *,int64); ///<向socket中写入指定的字节数
int64 WriteFully(const void *,int64); ///<充分写入指定字节的数据
bool CanRestart()const{return false;} ///<是否可以复位
bool CanSeek()const{return false;} ///<是否可以定位
bool CanSize()const{return false;} ///<是否可以取得尺寸
bool Restart(){return false;} ///<复位访问指针
int64 Seek(int64,io::SeekOrigin=io::soBegin){return -1;} ///<移动访问指针
int64 Tell()const{return -1;} ///<返回当前访问位置
int64 GetSize()const{return -1;} ///<取得流长度
int64 Available()const; ///<剩下的可以不受阻塞写入的字节数
};//class SocketOutputStream
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_SOCKET_OUTPUT_STREAM_INCLUDE

View File

@ -0,0 +1,83 @@
#ifndef HGL_NETWORK_TCP_ACCEPT_INCLUDE
#define HGL_NETWORK_TCP_ACCEPT_INCLUDE
#include<hgl/network/TCPSocket.h>
#include<hgl/type/MemBlock.h>
namespace hgl
{
namespace network
{
/**
* TCPAccept与SocketManage
*
* TCPAccept:
* SocketManage: TCPAccept进行管理的对象
* SocketManageThread: SocketManage的异步封装
*
* :
* 1.SocketManage通过OnSocketRecv函数通知TCPAccept接收数据
* 2.TCPAccept在收满4个字节的包长后MultiLevelMemoryPool申请缓冲区
* 3.TCPAccept收满一个包后OnRecvPacket事件函数通知开发者有包了
* 4.TCPAccept将缓冲区送回BufferPool
*/
using PACKET_SIZE_TYPE=uint32; ///<描述包长度的数据类型
constexpr uint PACKET_SIZE_TYPE_BYTES=sizeof(PACKET_SIZE_TYPE); ///<描述包长度的数据类型的字节长度
class SocketInputStream;
class SocketOutputStream;
/**
* TCP服务器接入用户处理基类Server管理器提供统一调用接口<br>
* *******************************************************************<br>
* 线
*/
class TCPAccept:public TCPSocket
{
protected:
SocketInputStream *sis=nullptr;
SocketOutputStream *sos=nullptr;
protected://事件函数由SocketManage调用
friend class SocketManage;
virtual int OnSocketRecv(int)=0; ///<Socket接收处理函数
virtual int OnSocketSend(int){return 0;} ///<Socket发送处理函数
virtual void OnSocketError(int)=0; ///<Socket错误处理函数
bool Send(void *,const uint); ///<发送原始数据
public:
using TCPSocket::TCPSocket;
virtual ~TCPAccept();
};//class TCPAccept:public TCPSocket
class TCPAcceptPacket:public TCPAccept
{
protected:
MemBlock<uchar> recv_buffer;
uint recv_length=0;
uint64 recv_total=0;
protected:
virtual int OnSocketRecv(int) override; ///<Socket接收处理函数
public:
TCPAcceptPacket(); ///<本类构造函数
TCPAcceptPacket(int,IPAddress *); ///<本类构造函数
virtual ~TCPAcceptPacket()=default;
virtual bool SendPacket(void *,const PACKET_SIZE_TYPE &); ///<发包
virtual bool OnRecvPacket(void *,const PACKET_SIZE_TYPE &)=0; ///<接收包事件函数
};//class TCPAcceptPacket:public TCPAccept
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_TCP_ACCEPT_INCLUDE

View File

@ -0,0 +1,52 @@
#ifndef HGL_TCP_CLIENT_INCLUDE
#define HGL_TCP_CLIENT_INCLUDE
#include<hgl/network/TCPSocket.h>
#include<hgl/io/InputStream.h>
#include<hgl/io/OutputStream.h>
namespace hgl
{
namespace network
{
/**
* TCP客户端处理类线2线
*/
class TCPClient:public TCPSocket ///TCP客户端处理类
{
io::InputStream *sis;
io::OutputStream *sos;
char *ipstr;
virtual void InitPrivate(int);
public:
double Heart; ///<心跳间隔时间(单位:秒默认参见HGL_TCP_HEART_TIME)
double TimeOut; ///<超时时间(单位:秒默认参见HGL_NETWORK_TIME_OUT)
public:
TCPClient(); ///<本类构造函数
TCPClient(int,const IPAddress *); ///<本类构造函数
virtual ~TCPClient(); ///<本类析构函数
virtual bool Connect(); ///<连接到服务器
virtual bool CreateConnect(const IPAddress *); ///<创建一个连接
virtual void Disconnect(); ///<断开连接
virtual bool UseSocket(int,const IPAddress *addr) override; ///<使用指定socket
const char *GetIPString()const{return ipstr;} ///<取得IP可视字符串
public:
virtual io::InputStream *GetInputStream(){return sis;} ///<取得输入流
virtual io::OutputStream *GetOutputStream(){return sos;} ///<取得输出流
};//class TCPClient
TCPClient *CreateTCPClient(IPAddress *);
}//namespace network
using namespace network;
}//namespace hgl
#endif//HGL_TCP_CLIENT_INCLUDE

View File

@ -0,0 +1,26 @@
#ifndef HGL_TCP_SERVER_INCLUDE
#define HGL_TCP_SERVER_INCLUDE
#include<hgl/network/AcceptServer.h>
namespace hgl
{
namespace network
{
/**
* TCPServer是对应TCP连接处理的通用服务器端
*/
class TCPServer:public AcceptServer ///TCP服务器端实现基类
{
int CreateServerSocket() override final; ///<创建一个服务器用Socket
public:
#if (HGL_OS != HGL_OS_Windows)&&(HGL_OS != HGL_OS_macOS)
void SetDeferAccept(const int); ///<设置推迟Accept
#endif//no windows&mac
};//class TCPServer
}//namespace network
using namespace network;
}//namespace hgl
#endif//HGL_TCP_SERVER_INCLUDE

View File

@ -0,0 +1,43 @@
#ifndef HGL_TCP_SOCKET_INCLUDE
#define HGL_TCP_SOCKET_INCLUDE
#include<hgl/network/Socket.h>
namespace hgl
{
namespace network
{
int CreateTCPConnect(IPAddress *); ///<创建一个tcp连接
/**
* TCP连接处理基类<br>
* Recv/Send函数以及缓冲区recv/send都只是针对缓冲区的send/recv在各自的派生类中
*/
class TCPSocket:public Socket ///TCP连接处理基类
{
protected:
timeval time_out;
fd_set local_set,recv_set,err_set;
void ResetConnect();
public: //方法
TCPSocket() :Socket() {}
TCPSocket(int sock,const IPAddress *addr):Socket(sock,addr){ResetConnect();}
virtual ~TCPSocket()=default; ///<本类析构函数
bool SetNodelay(bool); ///<设置是否使用无延迟方式
void SetKeepAlive(bool,const int=7200,const int=75,const int=9); ///<设置自动保持连接机制
virtual bool UseSocket(int,const IPAddress *) override; ///<使用指定socket
virtual bool IsConnect(); ///<当前socket是否在连接状态
virtual int WaitRecv(double); ///<等待可接收数据
};//class TCPSocket
}//namespace network
using namespace network;
}//namespace hgl
#endif//HGL_TCP_SOCKET_INCLUDE

104
inc/hgl/network/UdpSocket.h Normal file
View File

@ -0,0 +1,104 @@
#ifndef HGL_UDPSOCKET_INCLUDE
#define HGL_UDPSOCKET_INCLUDE
#include<hgl/type/DataType.h>
#include<hgl/network/Socket.h>
namespace hgl
{
namespace network
{
/**
* 使UDP协议的通信
*/
class UDPSocket:public Socket ///UDP通信类
{
IPAddress *bind_addr;
IPAddress *tar_addr;
public: //事件函数
virtual int ProcRecv(int=-1){return -1;}
virtual int ProcSend(int,int &left_bytes){return -1;}
public:
UDPSocket(); ///<本类构造函数
virtual ~UDPSocket(); ///<本类析构函数
virtual bool Create(const IPAddress *); ///<创建一个udp,并绑定一个IP地址与指定端口
// virtual bool Create(int family); ///<创建一个udp
uint GetBindPort()const{return bind_addr->GetPort();} ///<取得绑定端口
bool SetSendAddr(const IPAddress *); ///<设定发送地址
int SendPacket(const void *,int); ///<发送数据包
int SendPacket(IPAddress *,const void *,int); ///<向指定地址发送数据包
int RecvPacket(void *,int,IPAddress *); ///<接收数据包
};//class UDPSocket
/**
* UDPLite协议封装使用
*/
class UDPLiteSocket:public UDPSocket
{
public:
virtual ~UDPLiteSocket()=default;
bool Create(const IPAddress *)override; ///<创建一个udp lite,并绑定一个IP地址与指定端口
// bool Create(int family)override; ///<创建一个udp lite
void SetChecksumCoverage(int send_val=20,int recv_val=20); ///<设定UDPLite检验位长度,最小20
};//class UDPLiteSocket
/**
* 使UDPSocket
*/
template<typename BASE> class _UDPSocketCB:public BASE
{
public: //事件函数
DefEvent(void, OnDisconnect, (BASE *));
DefEvent(int, OnRecv, (BASE *,int));
DefEvent(int, OnSend, (BASE *,int,int &));
virtual void ClearEvent()
{
OnDisconnect=nullptr;
OnRecv =nullptr;
OnSend =nullptr;
}
public:
_UDPSocketCB(){ClearEvent();} ///<本类构造函数
virtual ~_UDPSocketCB()=default;
virtual void ProcDisconnect()
{
SafeCallEvent(OnDisconnect,(this));
}
virtual int ProcRecv(int size)
{
if(OnRecv==nullptr)return(-1);
return OnRecv(this,size);
}
virtual int ProcSend(int size,int &left_bytes)
{
if(OnSend==nullptr)return(-1);
return OnSend(this,size,left_bytes);
}
};//class _UDPSocketCB
using UDPSocketCB =_UDPSocketCB<UDPSocket>;
using UDPLiteSocketCB =_UDPSocketCB<UDPLiteSocket>;
}//namespace network
using namespace network;
}//namespace hgl
#endif//HGL_UDPSOCKET_INCLUDE

View File

@ -0,0 +1,13 @@
#ifndef HGL_NETWORK_WEBSOCKET_INCLUDE
#define HGL_NETWORK_WEBSOCKET_INCLUDE
#include<hgl/type/BaseString.h>
namespace hgl
{
namespace network
{
bool GetWebSocketInfo(UTF8String &sec_websocket_key,UTF8String &sec_websocket_protocol,uint &sec_websocket_version,const char *data,const uint size);
void MakeWebSocketAccept(UTF8String &result,const UTF8String &sec_websocket_key,const UTF8String &sec_websocket_protocol);
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_WEBSOCKET_INCLUDE

View File

@ -0,0 +1,82 @@
#ifndef HGL_NETWORK_WEBSOCKET_ACCEPT_INCLUDE
#define HGL_NETWORK_WEBSOCKET_ACCEPT_INCLUDE
#include<hgl/network/TCPAccept.h>
#include<hgl/type/BaseString.h>
namespace hgl
{
namespace network
{
/**
* WebSocket接入管理
*/
class WebSocketAccept:public TCPAccept
{
#ifdef _DEBUG
MemBlock<char> data_out_str;
#endif//_DEBUG
protected:
MemBlock<uchar> recv_buffer;
uint recv_length=0;
uint64 recv_total=0;
protected:
virtual int OnSocketRecv(int) override; ///<Socket接收处理函数
void WebSocketHandshake();
int SendFrame(uint8,void *,uint32,bool);
protected:
uint msg_opcode;
bool msg_fin;
bool msg_masked;
uint msg_header_size;
uint64 msg_length;
uint64 msg_full_length;
uint last_opcode;
protected: //WebSocket支持
/**
* WebSocket
* @param accept_protocol WebSocket协议
* @param protocol WebSocket协议
* @param version WebSocket版本
* @return
*/
virtual bool OnHandshake(UTF8String &accept_protocol,const UTF8String &protocol,uint version)
{
accept_protocol=protocol; //原样接收,如有需求请自行重载此函数处理
return(true);
}
public:
WebSocketAccept(); ///<本类构造函数
WebSocketAccept(int,IPAddress *); ///<本类构造函数
virtual ~WebSocketAccept()=default;
virtual void OnPing(){}
virtual void OnPong(){}
virtual bool OnBinary(void *,uint32,bool)=0;
virtual bool OnText(char *,uint32,bool)=0;
virtual void OnError(){}
bool SendPing();
bool SendPong();
bool SendBinary(void *,uint32,bool=true);
bool SendText(void *,uint32,bool=true);
bool SendText(const UTF8String &str)
{
return SendText(str.c_str(),str.Length());
}
};//class WebSocketAccept:public TCPAccept
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_WEBSOCKET_ACCEPT_INCLUDE

View File

@ -0,0 +1,92 @@
#ifndef HGL_NETWORK_WINDOW_FIREWALL_INCLUDE
#define HGL_NETWORK_WINDOW_FIREWALL_INCLUDE
struct INetFwProfile;
namespace hgl
{
namespace network
{
const int FW_MAX_ERROR_MESSAGE=256;
enum FW_ERROR_CODE
{
FW_NOERROR = 0,
FW_ERR_INITIALIZED, // Already initialized or doesn't call Initialize()
FW_ERR_CREATE_SETTING_MANAGER, // Can't create an instance of the firewall settings manager
FW_ERR_LOCAL_POLICY, // Can't get local firewall policy
FW_ERR_PROFILE, // Can't get the firewall profile
FW_ERR_FIREWALL_IS_ENABLED, // Can't get the firewall enable information
FW_ERR_FIREWALL_ENABLED, // Can't set the firewall enable option
FW_ERR_INVALID_ARG, // Invalid Arguments
FW_ERR_AUTH_APPLICATIONS, // Failed to get authorized application list
FW_ERR_APP_ENABLED, // Failed to get the application is enabled or not
FW_ERR_CREATE_APP_INSTANCE, // Failed to create an instance of an authorized application
FW_ERR_SYS_ALLOC_STRING, // Failed to alloc a memory for BSTR
FW_ERR_PUT_PROCESS_IMAGE_NAME, // Failed to put Process Image File Name to Authorized Application
FW_ERR_PUT_REGISTER_NAME, // Failed to put a registered name
FW_ERR_ADD_TO_COLLECTION, // Failed to add to the Firewall collection
FW_ERR_REMOVE_FROM_COLLECTION, // Failed to remove from the Firewall collection
FW_ERR_GLOBAL_OPEN_PORTS, // Failed to retrieve the globally open ports
FW_ERR_PORT_IS_ENABLED, // Can't get the firewall port enable information
FW_ERR_PORT_ENABLED, // Can't set the firewall port enable option
FW_ERR_CREATE_PORT_INSTANCE, // Failed to create an instance of an authorized port
FW_ERR_SET_PORT_NUMBER, // Failed to set port number
FW_ERR_SET_IP_PROTOCOL, // Failed to set IP Protocol
FW_ERR_EXCEPTION_NOT_ALLOWED, // Failed to get or put the exception not allowed
FW_ERR_NOTIFICATION_DISABLED, // Failed to get or put the notification disabled
FW_ERR_UNICAST_MULTICAST, // Failed to get or put the UnicastResponses To MulticastBroadcast Disabled Property
};
/**
* Windows 访<br>
* Kim Youngjin
*/
class WinFireWall
{
INetFwProfile* m_pFireWallProfile;
public:
enum PROTOCOL
{
ANY=256,
UDP=17,
TCP=6,
};
public:
WinFireWall();
~WinFireWall();
FW_ERROR_CODE Init();
FW_ERROR_CODE Close();
FW_ERROR_CODE CheckFirewall(bool &);
FW_ERROR_CODE OpenFirewall();
FW_ERROR_CODE CloseFirewall();
FW_ERROR_CODE CheckApplication(const wchar_t *,bool &);
FW_ERROR_CODE AddApplication(const wchar_t *,const wchar_t *);
FW_ERROR_CODE RemoveApplication(const wchar_t *);
FW_ERROR_CODE CheckPort(unsigned int,PROTOCOL,bool &);
FW_ERROR_CODE OpenPort(unsigned int,PROTOCOL,const wchar_t *);
FW_ERROR_CODE ClosePort(unsigned int,PROTOCOL);
FW_ERROR_CODE IsExceptionNotAllowed(bool &);
FW_ERROR_CODE SetExceptionNotAllowed(bool);
FW_ERROR_CODE IsNotificationDiabled(bool &);
FW_ERROR_CODE SetNotificationDiabled(bool);
FW_ERROR_CODE IsUnicastResponsesToMulticastBroadcastDisabled(bool &);
FW_ERROR_CODE SetUnicastResponsesToMulticastBroadcastDisabled(bool);
};
}//namespace network
using namespace network;
}//namespace hgl
#endif//HGL_NETWORK_WINDOW_FIREWALL_INCLUDE

9
path_config.cmake Normal file
View File

@ -0,0 +1,9 @@
macro(CMNetworkSetup CMNETWORK_ROOT_PATH)
message("CMNETWORK_ROOT_PATH: " ${CMNETWORK_ROOT_PATH})
set(CMNETWORK_ROOT_INCLUDE_PATH ${CMNETWORK_ROOT_PATH}/inc)
set(CMNETWORK_ROOT_SOURCE_PATH ${CMNETWORK_ROOT_PATH}/src)
include_directories(${CMNETWORK_ROOT_INCLUDE_PATH})
endmacro()

80
src/AcceptServer.cpp Normal file
View File

@ -0,0 +1,80 @@
#include<hgl/network/AcceptServer.h>
#include<hgl/LogInfo.h>
#include<hgl/Time.h>
namespace hgl
{
void SetTimeVal(timeval &tv,const double t_sec);
namespace network
{
/**
*
* @return >0
* @return =0
* @return <0
*/
int AcceptServer::Accept(IPAddress *addr)
{
if(!addr)
return(-1);
socklen_t sockaddr_size=server_address->GetSockAddrInSize();
if(accept_timeout.tv_sec
||accept_timeout.tv_usec)
{
int result;
hgl_cpy(ato,accept_timeout); //下面的select会将数据清0,所以必须是复制一份出来用
FD_ZERO(&accept_set);
FD_SET(ThisSocket,&accept_set);
result=select(ThisSocket+1,&accept_set,nullptr,nullptr,&ato);
if(result<=0)
return(0);
}
int new_sock=accept(ThisSocket,addr->GetSockAddr(),&sockaddr_size);
if(new_sock<0)
{
const int err=GetLastSocketError();
if(err==nseTimeOut //超时
||err==nseNoError // 0 没有错误
||err==4 //Interrupted system call(比如ctrl+c,一般DEBUG下才有)
||err==11 //资源临时不可用
)
return(0);
LOG_HINT(OS_TEXT("AcceptServer Accept error,errno=")+OSString(err));
if(err==nseTooManyLink) //太多的人accept
{
WaitTime(overload_wait); //强制等待指定时间
return(0);
}
return(-1);
}
const int IP_STR_MAX_SIZE=server_address->GetIPStringMaxSize();
if(!ipstr)
ipstr=new char[IP_STR_MAX_SIZE+1];
addr->ToString(ipstr,IP_STR_MAX_SIZE);
LOG_INFO(U8_TEXT("AcceptServer Accept IP:")+UTF8String(ipstr)+U8_TEXT(" ,sock:")+UTF8String(new_sock));
return(new_sock);
}
void AcceptServer::SetTimeOut(const double time_out)
{
SetTimeVal(accept_timeout,time_out);
}
}//namespace network
}//namespace hgl

107
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,107 @@
SET(NETWORK_BASE_SOURCE
IPAddress.cpp
Socket.cpp
)
SET(NETWORK_UDP_SOURCE
UdpSocket.cpp)
IF(BUILD_NETWORK_UDP_LITE)
SET(NETWORK_UDP_SOURCE ${NETWORK_UDP_SOURCE} UdpLiteSocket.cpp)
ENDIF()
SET(NETWORK_TCP_COMMON_SOURCE
TCPSocket.cpp
SocketInputStream.cpp
SocketOutputStream.cpp
)
SET(NETWORK_TCP_CLIENT_SOURCE
TCPClient.cpp)
SET(NETWORK_TCP_SERVER_SOURCE
ServerSocket.cpp
AcceptServer.cpp
MultiThreadAccept.cpp
TCPServer.cpp
TCPAccept.cpp
TCPAcceptPacket.cpp
SocketManage.cpp
)
SET(NETWORK_SCTP_SOURCE
SCTPSocket.cpp
SCTPO2OClient.cpp
SCTPO2OServer.cpp
SCTPO2MServer.cpp
)
SET(NETWORK_HTTP_SOURCE
HTTPInputStream.cpp
# HTTPOutputStream.cpp
HTTPTools.cpp
WebApi_Currency.cpp)
SET(NETWORK_WEBSOCKET_SOURCE
WebSocket.cpp
WebSocketAccept.cpp)
SOURCE_GROUP("Base" FILES ${NETWORK_BASE_SOURCE})
SOURCE_GROUP("Transport\\UDP" FILES ${NETWORK_UDP_SOURCE})
SOURCE_GROUP("Transport\\TCP" FILES ${NETWORK_TCP_COMMON_SOURCE})
SOURCE_GROUP("Transport\\TCP\\Client" FILES ${NETWORK_TCP_CLIENT_SOURCE})
SOURCE_GROUP("Transport\\TCP\\Server" FILES ${NETWORK_TCP_SERVER_SOURCE})
SOURCE_GROUP("Application\\HTTP" FILES ${NETWORK_HTTP_SOURCE})
SOURCE_GROUP("Application\\WebSocket" FILES ${NETWORK_WEBSOCKET_SOURCE})
IF(BUILD_NETWORK_SCTP)
SOURCE_GROUP("Transport\\SCTP" FILES ${NETWORK_SCTP_SOURCE})
SET(NETWORK_BASE_SOURCE ${NETWORK_BASE_SOURCE} ${NETWORK_SCTP_SOURCE})
ENDIF(BUILD_NETWORK_SCTP)
IF(WIN32)
SET(NETWORK_OS_SOURCE
SocketManageSelect.cpp
WinFireWall.cpp)
ENDIF(WIN32)
IF(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
SET(NETWORK_OS_SOURCE SocketManageEpoll.cpp)
ENDIF(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
IF(APPLE)
SET(NETWORK_OS_SOURCE SocketManageKqueue.cpp)
elseif(APPLE)
IF(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
SET(NETWORK_OS_SOURCE SocketManageKqueue.cpp)
ENDIF(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
IF(${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
SET(NETWORK_OS_SOURCE SocketManageKqueue.cpp)
ENDIF(${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
IF(${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
SET(NETWORK_OS_SOURCE SocketManageKqueue.cpp)
ENDIF(${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
ENDIF(APPLE)
SET(NETWORK_OS_SOURCE_GROUP ${CMAKE_SYSTEM_NAME})
SOURCE_GROUP(${NETWORK_OS_SOURCE_GROUP} FILES ${NETWORK_OS_SOURCE})
SET(CM_NETWORK_ALL_SOURCE
${NETWORK_BASE_SOURCE}
${NETWORK_UDP_SOURCE}
${NETWORK_TCP_COMMON_SOURCE}
${NETWORK_TCP_CLIENT_SOURCE}
${NETWORK_TCP_SERVER_SOURCE}
${NETWORK_WEBSOCKET_SOURCE}
${NETWORK_OS_SOURCE}
WebapiUserAgent.cpp)
IF(WIN32)
add_cm_library(CMNetwork "CM" ${CM_NETWORK_ALL_SOURCE})
ELSE()
add_cm_library(CMNetwork "CM" ${CM_NETWORK_ALL_SOURCE} ${NETWORK_HTTP_SOURCE})
ENDIF()

271
src/HTTPInputStream.cpp Normal file
View File

@ -0,0 +1,271 @@
#include<hgl/network/HTTPInputStream.h>
#include<hgl/network/TCPClient.h>
#include<hgl/LogInfo.h>
#include<hgl/type/Smart.h>
namespace hgl
{
namespace network
{
namespace
{
constexpr char HTTP_REQUEST_HEADER_BEGIN[]= " HTTP/1.1\r\n"
"Host: ";
constexpr uint HTTP_REQUEST_HEADER_BEGIN_SIZE=sizeof(HTTP_REQUEST_HEADER_BEGIN)-1;
constexpr char HTTP_REQUEST_HEADER_END[]= "\r\n"
"Accept: */*\r\n"
"User-Agent: Mozilla/5.0\r\n"
"Connection: Keep-Alive\r\n\r\n";
constexpr uint HTTP_REQUEST_HEADER_END_SIZE=sizeof(HTTP_REQUEST_HEADER_END)-1;
constexpr uint HTTP_HEADER_BUFFER_SIZE=HGL_SIZE_1KB;
}
HTTPInputStream::HTTPInputStream()
{
tcp=nullptr;
pos=-1;
filelength=-1;
tcp_is=nullptr;
http_header=new char[HTTP_HEADER_BUFFER_SIZE];
http_header_size=0;
response_code=0;
}
HTTPInputStream::~HTTPInputStream()
{
Close();
delete[] http_header;
}
/**
*
* @param host www.hyzgame.org.cn 127.0.0.1
* @param filename /download/hgl.rar
* @return
*/
bool HTTPInputStream::Open(IPAddress *host_ip,const UTF8String &host_name,const UTF8String &filename)
{
Close();
response_code=0;
response_info.Clear();
response_list.Clear();
if(!host_ip)
RETURN_FALSE;
if(filename.IsEmpty())
RETURN_FALSE;
tcp=CreateTCPClient(host_ip);
char *host_ip_str=host_ip->CreateString();
SharedArray<char> self_clear(host_ip_str);
if(!tcp)
{
LOG_ERROR(U8_TEXT("Connect to HTTPServer failed: ")+UTF8String(host_ip_str));
RETURN_FALSE;
}
//设定为非堵塞模式
tcp->SetBlock(false);
//发送HTTP GET请求
int len=0;
len =strcpy(http_header ,HTTP_HEADER_BUFFER_SIZE ,"GET ",4);
len+=strcpy(http_header+len,HTTP_HEADER_BUFFER_SIZE-len,filename.c_str(), filename.Length());
len+=strcpy(http_header+len,HTTP_HEADER_BUFFER_SIZE-len,HTTP_REQUEST_HEADER_BEGIN, HTTP_REQUEST_HEADER_BEGIN_SIZE);
len+=strcpy(http_header+len,HTTP_HEADER_BUFFER_SIZE-len,host_name.c_str(), host_name.Length());
len+=strcpy(http_header+len,HTTP_HEADER_BUFFER_SIZE-len,HTTP_REQUEST_HEADER_END, HTTP_REQUEST_HEADER_END_SIZE);
OutputStream *tcp_os=tcp->GetOutputStream();
if(tcp_os->WriteFully(http_header,len)!=len)
{
LOG_ERROR(U8_TEXT("Send HTTP Get Info failed:")+UTF8String(host_ip_str));
delete tcp;
tcp=nullptr;
RETURN_FALSE;
}
*http_header=0;
tcp_is=tcp->GetInputStream();
return(true);
}
/**
* HTTP流
*/
void HTTPInputStream::Close()
{
pos=0;
filelength=-1;
SAFE_CLEAR(tcp);
*http_header=0;
http_header_size=0;
}
constexpr char HTTP_HEADER_SPLITE[]="\r\n";
constexpr uint HTTP_HEADER_SPLITE_SIZE=sizeof(HTTP_HEADER_SPLITE)-1;
void HTTPInputStream::ParseHttpResponse()
{
char *offset=strstr(http_header,http_header_size,HTTP_HEADER_SPLITE,HTTP_HEADER_SPLITE_SIZE);
if(!offset)
return;
response_info.Set(http_header,offset-http_header);
char *first=strchr(http_header,' ');
if(!first)
return;
++first;
char *second=strchr(first,' ');
stou(first,second-first,response_code);
while(true)
{
first=offset+HTTP_HEADER_SPLITE_SIZE;
second=strchr(first,':',http_header_size-(first-http_header));
if(!second)break;
UTF8String key;
UTF8String value;
key.Set(first,second-first);
first=second+2;
second=strstr(first,http_header_size-(first-http_header),HTTP_HEADER_SPLITE,HTTP_HEADER_SPLITE_SIZE);
if(!second)break;
value.Set(first,second-first);
offset=second;
response_list.Add(key,value);
}
}
constexpr char HTTP_HEADER_FINISH[]="\r\n\r\n";
constexpr uint HTTP_HEADER_FINISH_SIZE=sizeof(HTTP_HEADER_FINISH)-1;
constexpr char HTTP_CONTENT_LENGTH[]="Content-Length: ";
constexpr uint HTTP_CONTENT_LENGTH_SIZE=sizeof(HTTP_CONTENT_LENGTH)-1;
int HTTPInputStream::PraseHttpHeader()
{
char *offset;
int size;
offset=strstr(http_header,http_header_size,HTTP_HEADER_FINISH,HTTP_HEADER_FINISH_SIZE);
if(!offset)
return 0;
ParseHttpResponse();
*offset=0;
size=http_header_size-(offset-http_header)-HTTP_HEADER_FINISH_SIZE;
if(response_code==200)
{
offset=strstr(http_header,http_header_size,HTTP_CONTENT_LENGTH,HTTP_CONTENT_LENGTH_SIZE);
if(offset)
{
offset+=HTTP_CONTENT_LENGTH_SIZE;
stou(offset,filelength);
}
//有些HTTP下载就是不提供文件长度
pos=size;
return(pos);
}
else
{
LOG_ERROR(U8_TEXT("HTTPServer error info: ")+UTF8String(http_header));
return(-1);
}
}
int HTTPInputStream::ReturnError()
{
const int err=GetLastSocketError();
if(err==nseWouldBlock)return(0); //不能立即完成
if(err==0)return(0);
LOG_ERROR(OSString("Socket Error: ")+GetSocketString(err));
Close();
RETURN_ERROR(-2);
}
/**
* HTTP流中读取数据,
* @param buf
* @param bufsize ,1024
* @return >=0
* @return -1
*/
int64 HTTPInputStream::Read(void *buf,int64 bufsize)
{
if(!tcp)
RETURN_ERROR(-1);
int readsize;
if(response_code==0) //HTTP头尚未解析完成
{
readsize=tcp_is->Read(http_header+http_header_size,HTTP_HEADER_BUFFER_SIZE-http_header_size);
if(readsize<=0)
return ReturnError();
http_header_size+=readsize;
readsize=PraseHttpHeader();
if(readsize==-1)
{
Close();
RETURN_ERROR(-3);
}
if(pos>0)
memcpy(buf,http_header+http_header_size-pos,pos);
return(pos);
}
else
{
readsize=tcp_is->Read((char *)buf,bufsize);
if(readsize<=0)
return ReturnError();
pos+=readsize;
return(readsize);
}
}
}//namespace network
}//namespace hgl

66
src/HTTPOutputStream.cpp Normal file
View File

@ -0,0 +1,66 @@
/*
//////////////////////////////////////////////////////////////////
//SDK post (masterz)
///////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "winsock.h"
#pragma comment(lib,"ws2_32.lib")
#define winsock_version 0x0101
void main()
{
//I create C:\Inetpub\wwwroot\test\test.asp ,start the web service
//start my program, the result is OK.
//If it works,it is written by masterz,otherwise I don't know who write it.
SOCKADDR_IN saServer;
LPHOSTENT lphostent;
WSADATA wsadata;
SOCKET hsocket;
int nRet;
const char* host_name="127.0.0.1";
char* req="POST /test/test.asp HTTP/1.0\r\n"
"From: local\r\n"
"User-Agent: post_test/1.0\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: 20\r\n\r\n"
"type=12345&name=aaaa";
if(WSAStartup(winsock_version,&wsadata))
printf("can't initial socket");
lphostent=gethostbyname(host_name);
if(lphostent==nullptr)
printf("lphostent is null");
hsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
saServer.sin_family = AF_INET;
// Use def. now, need to handle general case
saServer.sin_port = htons(80);
saServer.sin_addr = *((LPIN_ADDR)*lphostent->h_addr_list);
nRet = connect(hsocket, (LPSOCKADDR)&saServer, sizeof(SOCKADDR_IN));
if (nRet == SOCKET_ERROR)
{
printf("can't connect");
closesocket(hsocket);
return;
}
else
printf("connected with %s\n",host_name);
nRet = send(hsocket, req, strlen(req), 0);
if (nRet == SOCKET_ERROR)
{
printf("send() failed");
closesocket(hsocket);
}
else
printf("send() OK\n");
char dest[1000];
nRet=1;
while(nRet>0)
{
nRet=recv(hsocket,(LPSTR)dest,sizeof(dest),0);
if(nRet>0)
dest[nRet]=0;
else
dest[0]=0;
printf("\nReceived bytes:%d\n",nRet);
printf("Result:\n%s",dest);
}
} */

85
src/HTTPTools.cpp Normal file
View File

@ -0,0 +1,85 @@
#include<hgl/network/HTTPTools.h>
#include<hgl/LogInfo.h>
#include<curl/curl.h>
namespace hgl
{
namespace network
{
namespace http
{
namespace
{
size_t http_get_to_output_stream(void *ptr,size_t size,size_t number,void *stream)
{
io::OutputStream *os=(io::OutputStream *)stream;
int ss=size*number;
os->WriteFully(ptr,ss);
return ss;
}
}
/**
* http get指令
* @param os
* @param url
* @return
* @return <0
*/
int get(io::OutputStream *os,const char *url,const char *user_agent)
{
LOG_INFO(U8_TEXT("http get,url:")+UTF8String(url));
CURLcode res;
CURL *curl=curl_easy_init();
if(!curl)
return(-1);
int cur=os->Tell();
curl_easy_setopt(curl,CURLOPT_URL,url);
if(user_agent)
curl_easy_setopt(curl,CURLOPT_USERAGENT,user_agent);
curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1); //重定向支持
curl_easy_setopt(curl,CURLOPT_TIMEOUT,30);
curl_easy_setopt(curl,CURLOPT_WRITEDATA,os);
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,http_get_to_output_stream);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
return(os->Tell()-cur);
}
int post(io::OutputStream *os,const char *url,const void *post_data,const int post_data_size,const char *user_agent)
{
CURLcode res;
CURL *curl=curl_easy_init();
if(!curl)
return(-1);
int cur=os->Tell();
curl_easy_setopt(curl,CURLOPT_URL,url);
if(user_agent)
curl_easy_setopt(curl,CURLOPT_USERAGENT,user_agent);
curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1); //重定向支持
curl_easy_setopt(curl,CURLOPT_TIMEOUT,30);
curl_easy_setopt(curl,CURLOPT_POSTFIELDS,post_data);
curl_easy_setopt(curl,CURLOPT_POSTFIELDSIZE,post_data_size);
curl_easy_setopt(curl,CURLOPT_WRITEDATA,os);
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,http_get_to_output_stream);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
return(os->Tell()-cur);
}
}//namespace http
}//namespace network
}//namespace hgl

434
src/IPAddress.cpp Normal file
View File

@ -0,0 +1,434 @@
#include<hgl/network/IP.h>
#include<hgl/LogInfo.h>
namespace hgl
{
namespace network
{
bool FillAddr(sockaddr_in &addr,const char *name,int socktype,int protocol)
{
if(name)
{
struct addrinfo hints, *answer;
hgl_zero(hints);
hints.ai_family = AF_INET;
hints.ai_socktype=socktype;
hints.ai_protocol=protocol;
if (getaddrinfo(name, nullptr, &hints, &answer)) //此函数最低WindowsXP SP2
RETURN_FALSE;
memcpy(&addr,answer->ai_addr,sizeof(sockaddr_in));
freeaddrinfo(answer);
}
else
{
hgl_zero(addr);
addr.sin_family=AF_INET;
}
return(true);
}
bool FillAddr(sockaddr_in6 &addr,const char *name,int socktype,int protocol)
{
if(name)
{
struct addrinfo hints, *answer;
hgl_zero(hints);
hints.ai_family = AF_INET6;
hints.ai_socktype=socktype;
hints.ai_protocol=protocol;
if (getaddrinfo(name, nullptr, &hints, &answer)) //此函数最低WindowsXP SP2
RETURN_FALSE;
memcpy(&addr,answer->ai_addr,sizeof(sockaddr_in6));
freeaddrinfo(answer);
}
else
{
hgl_zero(addr);
addr.sin6_family=AF_INET6;
}
return(true);
}
/**
* /IP和port到当前socket
* @param ThisSocket socket
* @param addr ip/port
* @param reuse ,1
* @return
*/
template<typename SockAddr,typename SockAddrIn>
bool BindAddr(int ThisSocket,const SockAddrIn &addr,int reuse=1)
{
const int val = reuse;
#if HGL_OS == HGL_OS_Windows
setsockopt(ThisSocket, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(BOOL)); //win下的BOOL本质也是int所以唯一区分只在于val的传入类型
#else
setsockopt(ThisSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int));
#endif//HGL_OS == HGL_OS_Windows
if (bind(ThisSocket, (SockAddr *)&addr, sizeof(SockAddrIn)))
{
LOG_ERROR(OS_TEXT("Bind Socket Error! errno: ") + OSString(GetLastSocketError()));
return(false);
}
return(true);
}
bool GetHostname(UTF8String &name,const sockaddr *addr)
{
char hostname[NI_MAXHOST];
char server_info[NI_MAXSERV];
if(getnameinfo(addr,sizeof(struct sockaddr),hostname,NI_MAXHOST,server_info,NI_MAXSERV,NI_NUMERICSERV))
return(false);
name=hostname;
return(true);
}
void AddAddrToList(List<in_addr> &addr_list, const sockaddr_in *sai)
{
addr_list.Add(sai->sin_addr);
}
void AddAddrToList(List<in6_addr> &addr_list, const sockaddr_in6 *sai)
{
addr_list.Add(sai->sin6_addr);
}
template<int FAMILY,typename InAddr,typename SockAddrIn>
int GetIPList(List<InAddr> &addr_list,const char *addr_string, int socktype,int protocol)
{
struct addrinfo hints, *answer, *ptr;
hgl_zero(hints);
hints.ai_family = FAMILY;
hints.ai_socktype=socktype;
hints.ai_protocol=protocol;
if (getaddrinfo(addr_string, nullptr, &hints, &answer)) //此函数最低Windows 2003/Vista
return(-1);
int count = 0;
for (ptr = answer; ptr; ptr = ptr->ai_next)
{
AddAddrToList(addr_list,(SockAddrIn *)(ptr->ai_addr));
++count;
}
freeaddrinfo(answer);
return(count);
}
/**
* IP支持情况
* @return
* @return -1
* @return -2
*/
int GetIPSupport(List<IPSupport> &ipsl)
{
char hostname[NI_MAXHOST];
if(gethostname(hostname, NI_MAXHOST))
return(-1);
struct addrinfo hints, *answer, *ptr;
hgl_zero(hints);
if (getaddrinfo(hostname, nullptr, &hints, &answer)) //此函数最低Windows 2003/Vista
return(-1);
int count = 0;
for (ptr = answer; ptr; ptr = ptr->ai_next)
{
IPSupport s;
s.family =ptr->ai_family;
s.socktype =ptr->ai_socktype;
s.protocol =ptr->ai_protocol;
if(ptr->ai_family==AF_INET)
{
memcpy(&(s.ipv4),ptr->ai_addr,ptr->ai_addrlen);
inet_ntop(AF_INET,&(s.ipv4.sin_addr),s.ipv4str,INET_ADDRSTRLEN);
}
else
if(ptr->ai_family==AF_INET6)
{
memcpy(&(s.ipv6),ptr->ai_addr,ptr->ai_addrlen);
inet_ntop(AF_INET6,&(s.ipv6.sin6_addr),s.ipv6str,INET6_ADDRSTRLEN);
}
ipsl.Add(s);
++count;
}
freeaddrinfo(answer);
return(count);
}
/**
* IP类型是否在支持列表中
* @param ips_list IP协议支持列表
* @param family IP家族
* @param socktype socket类型
* @param protocol
* @return
*/
bool CheckIPSupport(const List<IPSupport> &ips_list,uint family,uint socktype,uint protocol)
{
int count=ips_list.GetCount();
if(count<=0)
return(false);
const IPSupport *ips=ips_list.GetData();
while(count--)
{
if(ips->family==family
&&ips->socktype==socktype
&&ips->protocol==protocol)
return(true);
++ips;
}
return(false);
}
/**
*
* @param family IP家族
* @param socktype socket类型
* @param protocol
* @return
*/
bool CheckIPSupport(uint family,uint socktype,uint protocol)
{
List<IPSupport> ips_list;
const int count=GetIPSupport(ips_list);
if(count<=0)return(false);
return CheckIPSupport(ips_list,family,socktype,protocol);
}
namespace
{
const char *protocol_name_tcp="TCP";
const char *protocol_name_udp="UDP";
const char *protocol_name_udp_lite="UDPLite";
const char *protocol_name_sctp="SCTP";
const char *protocol_name_unknow="unknow protocol";
}
void IPAddress::RefreshProtocolName()
{
if(IsTCP ())protocol_name=protocol_name_tcp;else
if(IsUDP ())protocol_name=protocol_name_udp;else
if(IsUDPLite())protocol_name=protocol_name_udp_lite;else
if(IsSCTP ())protocol_name=protocol_name_sctp;else
protocol_name=protocol_name_unknow;
}
}//namespace network
namespace network
{
bool IPv4Address::Set(const char *name,ushort port,int _socktype,int _protocol)
{
socktype=_socktype;
protocol=_protocol;
if(!FillAddr(addr,name,socktype,protocol))
RETURN_FALSE;
addr.sin_port=htons(port);
RefreshProtocolName();
return(true);
}
void IPv4Address::Set(ushort port)
{
hgl_zero(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
}
bool IPv4Address::Bind(int ThisSocket,int reuse)const{return BindAddr<sockaddr,sockaddr_in>(ThisSocket,addr,reuse);}
bool IPv4Address::GetHostname(UTF8String &name)const{return hgl::network::GetHostname(name,(sockaddr *)&addr);}
const ushort IPv4Address::GetPort()const{return addr.sin_port;}
void IPv4Address::ToString(char *str,const int max_size,const in_addr *ip_addr)
{
inet_ntop(AF_INET,(void *)&ip_addr,str,INET_ADDRSTRLEN);
}
void IPv4Address::ToString(char *str,const int max_size,const sockaddr_in *ip_addr)
{
ToString(str,max_size,&(ip_addr->sin_addr));
int size=strlen(str);
str[size]=':';
hgl::utos(str+size+1,max_size-1-size,ip_addr->sin_port);
}
void IPv4Address::ToString(char *str,int max_size)const
{
ToString(str,max_size,&addr);
}
/**
* IPv4地址列表
* @param addr_list
* @param domain
* @param _socktype Socket类型(SOCK_STREAMSOCK_DGRAMSOCK_RAWSOCK_RDMSOCK_SEQPACKET等值),
* @param _protocol (IPPROTO_TCPIPPROTO_UDPIPPROTO_SCTP),
* @return ,-1
*/
int IPv4Address::GetDomainIPList(List<in_addr> &addr_list,const char *domain,int socktype,int protocol)
{
return GetIPList<AF_INET,in_addr,sockaddr_in>(addr_list,domain,socktype,protocol);
}
/**
* IPv4地址列表
* @param addr_list
* @param _socktype Socket类型(SOCK_STREAMSOCK_DGRAMSOCK_RAWSOCK_RDMSOCK_SEQPACKET等值),
* @param _protocol (IPPROTO_TCPIPPROTO_UDPIPPROTO_SCTP),
* @return ,-1
*/
int IPv4Address::GetLocalIPList(List<in_addr> &addr_list,int _socktype,int _protocol)
{
char hostname[NI_MAXHOST];
if(gethostname(hostname, NI_MAXHOST))
return(-1);
return GetDomainIPList(addr_list,hostname,_socktype,_protocol);
}
bool IPv4Address::Comp(const IPAddress *ipa)const
{
if(this==ipa)return(true);
if(!ipa)return(false);
if(ipa->GetFamily()!=AF_INET)return(false);
if(ipa->GetProtocol()!=protocol)return(false);
return (memcmp(&addr,&(((IPv4Address *)ipa)->addr),sizeof(sockaddr_in))==0);
}
}//namespace network
namespace network
{
bool IPv6Address::Set(const char *name,ushort port,int _socktype,int _protocol)
{
socktype=_socktype;
protocol=_protocol;
if(!FillAddr(addr,name,socktype,protocol))
RETURN_FALSE;
addr.sin6_port=htons(port);
RefreshProtocolName();
return(true);
}
void IPv6Address::Set(ushort port)
{
hgl_zero(addr);
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(port);
}
bool IPv6Address::Bind(int ThisSocket,int reuse)const{return BindAddr<sockaddr,sockaddr_in6>(ThisSocket,addr,reuse);}
bool IPv6Address::GetHostname(UTF8String &name)const{return hgl::network::GetHostname(name,(sockaddr *)&addr);}
const ushort IPv6Address::GetPort()const{return addr.sin6_port;}
void IPv6Address::ToString(char *str,const int max_size,const in6_addr *ip_addr)
{
inet_ntop(AF_INET6, (void *)&ip_addr,str,INET6_ADDRSTRLEN);
}
void IPv6Address::ToString(char *str,const int max_size,const sockaddr_in6 *ip_addr)
{
ToString(str,max_size,&(ip_addr->sin6_addr));
int size=strlen(str);
str[size]=':';
hgl::utos(str+size+1,max_size-1-size,ip_addr->sin6_port);
}
void IPv6Address::ToString(char *str,const int max_size)const
{
IPv6Address::ToString(str,max_size,&addr);
}
/**
* IPv6地址列表
* @param addr_list
* @param domain
* @param _socktype Socket类型(SOCK_STREAMSOCK_DGRAMSOCK_RAWSOCK_RDMSOCK_SEQPACKET等值),
* @param _protocol (IPPROTO_TCPIPPROTO_UDPIPPROTO_SCTP),
* @return ,-1
*/
int IPv6Address::GetDomainIPList(List<in6_addr> &addr_list,const char *domain,int socktype,int protocol)
{
return GetIPList<AF_INET6,in6_addr,sockaddr_in6>(addr_list,domain,socktype,protocol);
}
/**
* IPv6地址列表
* @param addr_list
* @param _socktype Socket类型(SOCK_STREAMSOCK_DGRAMSOCK_RAWSOCK_RDMSOCK_SEQPACKET等值),
* @param _protocol (IPPROTO_TCPIPPROTO_UDPIPPROTO_SCTP),
* @return ,-1
*/
int IPv6Address::GetLocalIPList(List<in6_addr> &addr_list,int _socktype,int _protocol)
{
char hostname[NI_MAXHOST];
if(gethostname(hostname, NI_MAXHOST))
return(-1);
return GetDomainIPList(addr_list,hostname,_socktype,_protocol);
}
bool IPv6Address::Comp(const IPAddress *ipa)const
{
if(this==ipa)return(true);
if(!ipa)return(false);
if(ipa->GetFamily()!=AF_INET6)return(false);
if(ipa->GetProtocol()!=protocol)return(false);
return (memcmp(&addr,&(((IPv6Address *)ipa)->addr),sizeof(sockaddr_in6))==0);
}
}//namespace network
}//namespace hgl

65
src/MultiThreadAccept.cpp Normal file
View File

@ -0,0 +1,65 @@
#include<hgl/network/MultiThreadAccept.h>
#include<hgl/network/AcceptServer.h>
#include<hgl/Time.h>
namespace hgl
{
namespace network
{
namespace
{
void PreMalloc(IPAddressStack &ip_stack,ServerSocket *server)
{
int count=ip_stack.GetCount();
ip_stack.SetMax(count+1024);
server->CreateIPAddress(ip_stack.GetData()+count,1024);
ip_stack.SetCount(count+1024);
}
}//namespace
AcceptThread::AcceptThread(AcceptServer *as,Semaphore *sem)
{
server=as;
active_semaphore=sem;
if(!server)
return;
PreMalloc(ip_stack,server);
}
bool AcceptThread::Execute()
{
if(!server)return(false);
IPAddress *client_ip;
int client_sock;
if(ip_stack.GetCount()<=0)
PreMalloc(ip_stack,server);
ip_stack.Pop(client_ip);
client_sock=server->Accept(client_ip);
if(client_sock<0)
{
ip_stack.Push(client_ip);
return(false);
}
active_semaphore->Post(); //发一个信号证明自己活着
if(client_sock>0)
{
if(!OnAccept(client_sock,client_ip))
CloseSocket(client_sock);
}
return(true);
}//bool AcceptThread::Execute()
}//namespace network
}//namespace hgl

72
src/SCTPO2MServer.cpp Normal file
View File

@ -0,0 +1,72 @@
#include<hgl/network/SCTPServer.h>
#include<hgl/LogInfo.h>
#include<netinet/sctp.h>
namespace hgl
{
namespace network
{
/**
*
* @param addr
* @param max_listen ()
* @return
*/
bool SCTPO2MServer::CreateServer(const sockaddr_in &addr,const uint max_listen)
{
if(!SCTPO2MSocket::Create())
return(false);
if(!BindAddr(ThisSocket,addr))
{
CloseSocket();
return(false);
}
listen(ThisSocket,max_listen);
return(true);
}
/**
*
* @param hostname
* @param port
* @param max_listen ()
* @return
*/
bool SCTPO2MServer::CreateServer(const char *hostname,uint port,const uint max_listen)
{
sockaddr_in addr;
if(!FillAddr(&addr,hostname,port))
return(false);
if(!CreateServer(addr,max_listen))
{
LOG_HINT(OS_TEXT("ServerSocket::CreateServer failed,Listen Port: ")+OSString(port));
return(false);
}
LOG_HINT(u8"ServerSocket Listen Address: "+UTF8String(hostname));
LOG_HINT(OS_TEXT("ServerSocket Listen Port: ")+OSString(port));
return(true);
}
void SCTPO2MServer::CloseServer()
{
CloseSocket();
}
/**
*
* @param to
*/
void SCTPO2MServer::SetAutoClose(const int to)
{
setsockopt(ThisSocket,IPPROTO_SCTP,SCTP_AUTOCLOSE,&to,sizeof(int));
}
}//namespace network
}//namespace hgl

75
src/SCTPO2OClient.cpp Normal file
View File

@ -0,0 +1,75 @@
#include<hgl/network/SCTPClient.h>
#include<hgl/LogInfo.h>
#include<netinet/sctp.h>
namespace hgl
{
namespace network
{
SCTPO2OClient::SCTPO2OClient()
{
}
SCTPO2OClient::SCTPO2OClient(int sock)
{
UseSocket(sock);
}
SCTPO2OClient::~SCTPO2OClient()
{
}
/**
*
* @param addr
* @return
*/
bool SCTPO2OClient::Connect(const sockaddr_in &addr)
{
CloseSocket();
if(!CreateSocket(AF_INET,SOCK_STREAM,IPPROTO_SCTP))
return(false);
if(connect(ThisSocket,(sockaddr *)&addr,sizeof(addr)))
{
os_char ipstr[32];
SockToStr(addr,ipstr,true);
LOG_HINT(OS_TEXT("Don't Connect to SCTPServer ")+OSString(ipstr));
CloseSocket();
return(false);
}
// LOG_INFO(u"connect "+u8_to_u16(host)+u':'+UTF16String(port)+u" ok,socket:"+UTF16String(ThisSocket));
InitDataIOEvent();
GetMsg();
//SetBlock(true,TimeOut); //阻塞模式
return(true);
}
/**
*
* @param host
* @param port
* @return
*/
bool SCTPO2OClient::Connect(const char *host,int port)
{
sockaddr_in addr;
if(FillAddr(&addr,host,port)==false)
{
LOG_HINT(OS_TEXT("SCTP connect error in ")+OSString(host)+OS_TEXT(":")+OSString(port));
CloseSocket();
return(false);
}
return Connect(addr);
}
}//namespace network
}//namespace hgl

12
src/SCTPO2OServer.cpp Normal file
View File

@ -0,0 +1,12 @@
#include<hgl/network/SCTPServer.h>
namespace hgl
{
namespace network
{
int SCTPO2OServer::CreateServerSocket()
{
return socket(AF_INET,SOCK_STREAM,IPPROTO_SCTP);
}
}//namespace network
}//namespace hgl

227
src/SCTPSocket.cpp Normal file
View File

@ -0,0 +1,227 @@
#include<hgl/network/SCTPSocket.h>
namespace hgl
{
namespace network
{
SCTPSocket::SCTPSocket()
{
memset(&address,0,sizeof(sockaddr_in));
}
bool SCTPSocket::InitDataIOEvent()
{
struct sctp_event_subscribe events;
hgl_zero(events);
events.sctp_data_io_event=1;
return(setsockopt(ThisSocket,SOL_SCTP,SCTP_EVENTS,(const void *)&events,sizeof(events))!=-1);
}
bool SCTPSocket::GetMsg()
{
sctp_initmsg msg;
socklen_t len;
len=sizeof(sctp_initmsg);
if(getsockopt(ThisSocket,IPPROTO_SCTP,SCTP_INITMSG,(void *)&msg,&len)==-1)
return(false);
out_max_stream =msg.sinit_num_ostreams;
in_max_stream =msg.sinit_max_instreams;
init_max_attempts =msg.sinit_max_attempts;
init_max_init_timeo =msg.sinit_max_init_timeo;
return(true);
}
/**
* sctp socket
* @param this_socket socket号
* @param out_stream sctp流数(0)
* @param in_stream sctp流数(-1out_stream,0)
* @param attempts (0)
* @param init_time_out init定时器超时时间单位为毫秒(0)
* @return
*/
bool SCTPSocket::InitMsg(int out_stream,int in_stream,int attempts,int init_time_out)
{
sctp_initmsg msg;
if(in_stream==-1)
in_stream=out_stream;
msg.sinit_num_ostreams=out_stream; //允许发送的最大sctp流数
msg.sinit_max_instreams=in_stream; //允许输入的最大sctp流数
msg.sinit_max_attempts=attempts; //重传多少次才认为不可达(0表示不设置)
msg.sinit_max_init_timeo=init_time_out; //重传超时时间,单位毫秒(0表示不设置)
return(setsockopt(ThisSocket,IPPROTO_SCTP,SCTP_INITMSG,(void *)&msg,sizeof(sctp_initmsg))!=-1);
}
/**
* 使()
* @param no_delay
*/
bool SCTPSocket::SetNodelay(bool no_delay)
{
int flag=(no_delay?1:0);
return(setsockopt(ThisSocket,IPPROTO_SCTP,SCTP_NODELAY,(void *)&flag,sizeof(flag))!=-1);
}
bool SCTPSocket::SetMaxStream(int ms)
{
out_max_stream=ms;
in_max_stream=ms;
return InitMsg(ThisSocket,ms,ms);
}
void SCTPSocket::UseSocket(int s,const sockaddr_in *sa)
{
ThisSocket=s;
InitDataIOEvent();
GetMsg();
if(sa)
memcpy(&address,sa,sizeof(sockaddr_in));
else
memset(&address,0,sizeof(sockaddr_in));
}
/**
*
* @param buf
* @param len
* @param stream
* @return
*/
bool SCTPO2OSocket::SendMsg(const void *buf,int len,uint16 stream)
{
if(!buf||len<=0)
return(false);
if(stream>=out_max_stream)
return(false);
size_t result_size=sctp_sendmsg(ThisSocket,buf,len,
nullptr, //目标地址,一对一模式不需要设置
0, //上一个参数的长度
0, //ppid 净荷协议标识符
0, //flags
stream, //
0, //time to live 生命周期
0); //context 上下文
//两段代码效果一样
// hgl_zero(sri_send);
// sri_send.sinfo_stream=stream;
//
// size_t result_size=sctp_send(ThisSocket,buf,len,&sri_send,0);
return(result_size==len);
}
/**
*
* @param stream
* @return
*/
bool SCTPO2OSocket::RecvMsg(MemBlock<char> *mb,uint16 &stream)
{
if(!mb)return(false);
int flags;
int len;
int off=0;
hgl_zero(sri_recv);
while(true)
{
len=sctp_recvmsg(ThisSocket,mb->GetData()+off,mb->GetMaxBytes()-off,
nullptr, //来源地址,一对一模式不需要
0, //上一个参数的长度
&sri_recv,
&flags);
if(len<0)
return(false);
std::cout<<"sctp_recvmsg return "<<len<<", flags="<<flags
<<", ssn:"<<sri_recv.sinfo_ssn
<<", flags:"<<sri_recv.sinfo_flags
<<", ppid:"<<sri_recv.sinfo_ppid
<<", tsn:"<<sri_recv.sinfo_tsn
<<", assoc_id:"<<sri_recv.sinfo_assoc_id
<<std::endl;
if(flags&MSG_EOR)
{
mb->SetLength(len);
stream=sri_recv.sinfo_stream;
return(true);
}
off+=len;
mb->SetLength(mb->GetMaxLength()+1024);
}
}
bool SCTPO2MSocket::Create()
{
int s=socket(AF_INET,SOCK_SEQPACKET,IPPROTO_SCTP);
if(s<0)
return(false);
UseSocket(s);
return(true);
}
bool SCTPO2MSocket::SendMsg(const sockaddr_in *sa,void *buf,int len,uint16 stream)
{
if(!sa||!buf||len<=0)
return(false);
const socklen_t sal=sizeof(sockaddr_in);
size_t result_size=sctp_sendmsg(ThisSocket,buf,len,
(sockaddr *)sa, //目标地址
sal, //上一个参数的长度
0, //ppid
0, //flags
stream, //
0, //time to live
0); //context
return(result_size==len);
}
bool SCTPO2MSocket::RecvMsg(sockaddr_in &sa,void *buf,int max_len,int &len,uint16 &stream)
{
struct sctp_sndrcvinfo sndrcvinfo;
int flags;
socklen_t sal=sizeof(sockaddr_in);
hgl_zero(sndrcvinfo);
len=sctp_recvmsg(ThisSocket,buf,max_len,
(sockaddr *)&sa, //来源地址
&sal, //上一个参数的长度
&sndrcvinfo,
&flags);
if(len<0)
return(false);
stream=sndrcvinfo.sinfo_stream;
return(true);
}
}//namespace network
}//namespace hgl

88
src/ServerSocket.cpp Normal file
View File

@ -0,0 +1,88 @@
#include<hgl/network/ServerSocket.h>
#include<hgl/LogInfo.h>
namespace hgl
{
namespace network
{
ServerSocket::ServerSocket()
{
ThisSocket=-1;
server_address=nullptr;
}
ServerSocket::~ServerSocket()
{
CloseServer();
}
/**
* IP地址空间
* @param ip_buffer IP地址空间的缓冲区
* @param count IP地址空间数量
* @return
*/
bool ServerSocket::CreateIPAddress(IPAddress **ip_buffer,int count)const
{
if(!server_address)return(false);
if(!ip_buffer)return(false);
if(count<=0)return(false);
for(int i=0;i<count;i++)
{
*ip_buffer=server_address->Create();
ip_buffer++;
}
return(true);
}
/**
*
* @param addr
* @param max_listen ()
* @param reuse IP地址
* @return
*/
bool ServerSocket::CreateServer(const IPAddress *addr,const uint max_listen,bool reuse)
{
ThisSocket=CreateServerSocket();
if(ThisSocket<0)
{
LOG_HINT(OS_TEXT("Create TCP Server Socket Failed!"));
return(false);
}
if(!addr->Bind(ThisSocket,reuse))
{
CloseSocket(ThisSocket);
return(false);
}
server_address=addr->CreateCopy();
listen(ThisSocket,max_listen);
return(true);
}
void ServerSocket::CloseServer()
{
CloseSocket(ThisSocket);
ThisSocket=-1;
SAFE_CLEAR(server_address);
}
bool ServerSocket::SetIPv6Only(bool only)
{
if (ThisSocket == -1)return(false);
if (server_address->GetFamily() != AF_INET6)return(false);
int on = only?1:0;
return(setsockopt(ThisSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on, sizeof(on)) == 0);
}
}//namespace network
}//namespace hgl

497
src/Socket.cpp Normal file
View File

@ -0,0 +1,497 @@
#include<hgl/network/Socket.h>
#include<hgl/LogInfo.h>
#include<time.h>
#include<iostream>
#if HGL_OS != HGL_OS_Windows
#include<netinet/tcp.h>
#if HGL_OS == HGL_OS_Solaris
#include<sys/filio.h>
#endif//HGL_OS == HGL_OS_Solaris
#endif//HGL_OS != HGL_OS_Windows
//setsockopt函数的Windows下使用参数格式请参见http://msdn.microsoft.com/en-us/library/windows/desktop/ms740476(v=vs.85).aspx
namespace hgl
{
void SetTimeVal(timeval &tv,const double t_sec);
namespace network
{
#if HGL_OS == HGL_OS_Windows
namespace
{
static bool winsocket_init=false;
}//namespace
bool InitWinSocket()
{
if(winsocket_init)return(true);
WSADATA wsa;
winsocket_init=(WSAStartup(MAKEWORD(2,2),&wsa)==NO_ERROR);
return(winsocket_init);
}
#endif//HGL_OS == HGL_OS_Windows
int CreateSocket(const IPAddress *addr)
{
if(!addr)
RETURN_ERROR(-1);
#if HGL_OS == HGL_OS_Windows
if(!InitWinSocket())
RETURN_ERROR(-2);
#endif//HGL_OS == HGL_OS_Windows
const int protocol=addr->GetProtocol();
int s=socket(addr->GetFamily(),
addr->GetSocketType(),
addr->GetProtocol());
if(s<0)
{
const int sock_error=GetLastSocketError(); //在这里定义一个,是为了调试方便可以查看
LOG_ERROR(OS_TEXT("CreateSocket(domain=")+OSString(addr->GetFamily())+
OS_TEXT(",type=")+OSString(addr->GetSocketType())+
OS_TEXT(",protocol=")+OSString(protocol)+
OS_TEXT(") return ")+OSString(s)+
OS_TEXT("; errno ")+OSString(sock_error));
RETURN_ERROR(-3);
}
LOG_INFO(U8_TEXT("Create ")+UTF8String(addr->GetProtocolName())+U8_TEXT(" Socket OK: ")+UTF8String(s));
return s;
}
/**
* socket到指定地址
*/
bool Connect(int sock,IPAddress *addr)
{
if(sock<0||!addr)
RETURN_FALSE;
if(connect(sock,addr->GetSockAddr(),addr->GetSockAddrInSize()))
RETURN_FALSE;
return(true);
}
// static atom_int socket_count=0;
Socket::Socket()
{
ThisAddress=nullptr;
ThisSocket=-1;
// LOG_INFO(u8"Socket Count ++: "+UTF8String(++socket_count));
}
Socket::Socket(int sock,const IPAddress *addr)
{
ThisSocket=sock;
if(addr)
ThisAddress=addr->CreateCopy();
else
ThisAddress=nullptr;
}
Socket::~Socket()
{
CloseSocket();
// LOG_INFO(u8"Socket Count --: "+UTF8String(--socket_count));
}
bool Socket::InitSocket(const IPAddress *addr)
{
if(!addr)
RETURN_FALSE;
SAFE_CLEAR(ThisAddress);
#if HGL_OS == HGL_OS_Windows
if(!InitWinSocket())
RETURN_FALSE;
#endif//HGL_OS == HGL_OS_Windows
ThisSocket=CreateSocket(addr);
if(ThisSocket<0)
RETURN_FALSE;
ThisAddress=addr->CreateCopy();
return(true);
}
/**
* 使Socket
*/
bool Socket::UseSocket(int sock,const IPAddress *addr)
{
if(sock<0||!addr)
RETURN_FALSE;
SAFE_CLEAR(ThisAddress);
ThisSocket=sock;
ThisAddress=addr->CreateCopy();
return(true);
}
/**
* 使Socket
*/
bool Socket::ReCreateSocket()
{
if(!ThisAddress)
RETURN_FALSE;
if(ThisSocket!=-1)
hgl::CloseSocket(ThisSocket);
ThisSocket=CreateSocket(ThisAddress);
if(ThisSocket!=-1)
return(true);
RETURN_FALSE;
}
/**
*
*/
void Socket::CloseSocket()
{
if(ThisSocket==-1)
return;
hgl::CloseSocket(ThisSocket);
ThisSocket=-1;
}
struct SocketErrorMessage //socket错误信息
{
int number; //编号
os_char recountal[256]; //详细叙述
};
const SocketErrorMessage tab[]=
{
{0, OS_TEXT("没有错误")},
#if HGL_OS != HGL_OS_Windows
// //errno-base.h
{EPERM ,OS_TEXT("Operation not permitted")},
{ENOENT ,OS_TEXT("No such file or directory")},
{ESRCH ,OS_TEXT("No such process")},
{EINTR ,OS_TEXT("Interrupted system call")},
{EIO ,OS_TEXT("I/O error")},
{ENXIO ,OS_TEXT("No such device or address")},
{E2BIG ,OS_TEXT("Argument list too long")},
{ENOEXEC ,OS_TEXT("Exec format error")},
{EBADF ,OS_TEXT("Bad file number")},
{ECHILD ,OS_TEXT("No child processes")},
{EAGAIN ,OS_TEXT("Try again")},
{ENOMEM ,OS_TEXT("Out of memory")},
{EACCES ,OS_TEXT("Permission denied")},
{EFAULT ,OS_TEXT("Bad address")},
{ENOTBLK ,OS_TEXT("Block device required")},
{EBUSY ,OS_TEXT("Device or resource busy")},
{EEXIST ,OS_TEXT("File exists")},
{EXDEV ,OS_TEXT("Cross-device link")},
{ENODEV ,OS_TEXT("No such device")},
{ENOTDIR ,OS_TEXT("Not a directory")},
{EISDIR ,OS_TEXT("Is a directory")},
{EINVAL ,OS_TEXT("Invalid argument")},
{ENFILE ,OS_TEXT("File table overflow")},
{EMFILE ,OS_TEXT("Too many open files")},
{ENOTTY ,OS_TEXT("Not a typewriter")},
{ETXTBSY ,OS_TEXT("Text file busy")},
{EFBIG ,OS_TEXT("File too large")},
{ENOSPC ,OS_TEXT("No space left on device")},
{ESPIPE ,OS_TEXT("Illegal seek")},
{EROFS ,OS_TEXT("Read-only file system")},
{EMLINK ,OS_TEXT("Too many links")},
{EPIPE ,OS_TEXT("Broken pipe")},
{EDOM ,OS_TEXT("Math argument out of domain of func")},
{ERANGE ,OS_TEXT("Math result not representable")},
// //errno.h
//
{EDEADLK ,OS_TEXT("Resource deadlock would occur")},
{ENAMETOOLONG ,OS_TEXT("File name too long")},
{ENOLCK ,OS_TEXT("No record locks available")},
{ENOSYS ,OS_TEXT("Function not implemented")},
{ENOTEMPTY ,OS_TEXT("Directory not empty")},
{ELOOP ,OS_TEXT("Too many symbolic links encountered")},
{ENOMSG ,OS_TEXT("No message of desired type")},
{EIDRM ,OS_TEXT("Identifier removed")},
{ENOSTR ,OS_TEXT("Device not a stream")},
{ENODATA ,OS_TEXT("No data available")},
{ETIME ,OS_TEXT("Timer expired")},
{ENOSR ,OS_TEXT("Out of streams resources")},
{EREMOTE ,OS_TEXT("Object is remote")},
{ENOLINK ,OS_TEXT("Link has been severed")},
{EPROTO ,OS_TEXT("Protocol error")},
{EMULTIHOP ,OS_TEXT("Multihop attempted")},
{EBADMSG ,OS_TEXT("Not a data message")},
{EOVERFLOW ,OS_TEXT("Value too large for defined data type")},
{EILSEQ ,OS_TEXT("Illegal byte sequence")},
{EUSERS ,OS_TEXT("Too many users")},
{ENOTSOCK ,OS_TEXT("Socket operation on non-socket")},
{EDESTADDRREQ ,OS_TEXT("Destination address required")},
{EMSGSIZE ,OS_TEXT("Message too long")},
{EPROTOTYPE ,OS_TEXT("Protocol wrong type for socket")},
{ENOPROTOOPT ,OS_TEXT("Protocol not available")},
{EPROTONOSUPPORT,OS_TEXT("Protocol not supported")},
{ESOCKTNOSUPPORT,OS_TEXT("Socket type not supported")},
{EOPNOTSUPP ,OS_TEXT("Operation not supported on transport endpoint")},
{EPFNOSUPPORT ,OS_TEXT("Protocol family not supported")},
{EAFNOSUPPORT ,OS_TEXT("Address family not supported by protocol")},
{EADDRINUSE ,OS_TEXT("Address already in use")},
{EADDRNOTAVAIL ,OS_TEXT("Cannot assign requested address")},
{ENETDOWN ,OS_TEXT("Network is down")},
{ENETUNREACH ,OS_TEXT("Network is unreachable")},
{ENETRESET ,OS_TEXT("Network dropped connection because of reset")},
{ECONNABORTED ,OS_TEXT("Software caused connection abort")},
{ECONNRESET ,OS_TEXT("Connection reset by peer")},
{ENOBUFS ,OS_TEXT("No buffer space available")},
{EISCONN ,OS_TEXT("Transport endpoint is already connected")},
{ENOTCONN ,OS_TEXT("Transport endpoint is not connected")},
{ESHUTDOWN ,OS_TEXT("Cannot send after transport endpoint shutdown")},
{ETOOMANYREFS ,OS_TEXT("Too many references: cannot splice")},
{ETIMEDOUT ,OS_TEXT("Connection timed out")},
{ECONNREFUSED ,OS_TEXT("Connection refused")},
{EHOSTDOWN ,OS_TEXT("Host is down")},
{EHOSTUNREACH ,OS_TEXT("No route to host")},
{EALREADY ,OS_TEXT("Operation already in progress")},
{EINPROGRESS ,OS_TEXT("Operation now in progress")},
{ESTALE ,OS_TEXT("Stale NFS file handle")},
{EDQUOT ,OS_TEXT("Quota exceeded")},
{ECANCELED ,OS_TEXT("Operation Canceled")},
{EOWNERDEAD ,OS_TEXT("Owner died")},
{ENOTRECOVERABLE,OS_TEXT("State not recoverable")},
#ifndef HGL_OS_BSD
{ECHRNG ,OS_TEXT("Channel number out of range")},
{EL2NSYNC ,OS_TEXT("Level 2 not synchronized")},
{EL3HLT ,OS_TEXT("Level 3 halted")},
{EL3RST ,OS_TEXT("Level 3 reset")},
{ELNRNG ,OS_TEXT("Link number out of range")},
{EUNATCH ,OS_TEXT("Protocol driver not attached")},
{ENOCSI ,OS_TEXT("No CSI structure available")},
{EL2HLT ,OS_TEXT("Level 2 halted")},
{EBADE ,OS_TEXT("Invalid exchange")},
{EBADR ,OS_TEXT("Invalid request descriptor")},
{EXFULL ,OS_TEXT("Exchange full")},
{ENOANO ,OS_TEXT("No anode")},
{EBADRQC ,OS_TEXT("Invalid request code")},
{EBADSLT ,OS_TEXT("Invalid slot")},
{EBFONT ,OS_TEXT("Bad font file format")},
{ENONET ,OS_TEXT("Machine is not on the network")},
{ENOPKG ,OS_TEXT("Package not installed")},
{EADV ,OS_TEXT("Advertise error")},
{ESRMNT ,OS_TEXT("Srmount error")},
{ECOMM ,OS_TEXT("Communication error on send")},
{EDOTDOT ,OS_TEXT("RFS specific error")},
{ENOTUNIQ ,OS_TEXT("Name not unique on network")},
{EBADFD ,OS_TEXT("File descriptor in bad state")},
{EREMCHG ,OS_TEXT("Remote address changed")},
{ELIBACC ,OS_TEXT("Can not access a needed shared library")},
{ELIBBAD ,OS_TEXT("Accessing a corrupted shared library")},
{ELIBSCN ,OS_TEXT(".lib section in a.out corrupted")},
{ELIBMAX ,OS_TEXT("Attempting to link in too many shared libraries")},
{ELIBEXEC ,OS_TEXT("Cannot exec a shared library directly")},
{ERESTART ,OS_TEXT("Interrupted system call should be restarted")},
{ESTRPIPE ,OS_TEXT("Streams pipe error")},
{EUCLEAN ,OS_TEXT("Structure needs cleaning")},
{ENOTNAM ,OS_TEXT("Not a XENIX named type file")},
{ENAVAIL ,OS_TEXT("No XENIX semaphores available")},
{EISNAM ,OS_TEXT("Is a named type file")},
{EREMOTEIO ,OS_TEXT("Remote I/O error")},
{ENOMEDIUM ,OS_TEXT("No medium found")},
{EMEDIUMTYPE ,OS_TEXT("Wrong medium type")},
{ENOKEY ,OS_TEXT("Required key not available")},
{EKEYEXPIRED ,OS_TEXT("Key has expired")},
{EKEYREVOKED ,OS_TEXT("Key has been revoked")},
{EKEYREJECTED ,OS_TEXT("Key was rejected by service")},
{ERFKILL ,OS_TEXT("Operation not possible due to RF-kill")},
{EHWPOISON ,OS_TEXT("Memory page has hardware error")},
#endif//
#else
{10004, OS_TEXT("阻塞操作被函数WSACancelBlockingCall ()调用所中断")},
{10013, OS_TEXT("试图使用被禁止的访问权限去访问套接字")},
{10014, OS_TEXT("系统检测到调用试图使用的一个指针参数指向的是一个非法指针地址")},
{10022, OS_TEXT("提供了非法参数")},
{10024, OS_TEXT("打开了太多的套接字")},
{10035, OS_TEXT("当前操作在非阻塞套接字上不能立即完成")},
{10036, OS_TEXT("一个阻塞操作正在执行")},
{10037, OS_TEXT("被调用的套接字当前有操作正在进行")},
{10038, OS_TEXT("操作试图不是在套接字上进行")},
{10039, OS_TEXT("在套接字上一个操作所必须的地址被遗漏")},
{10040, OS_TEXT("在数据报套接字上发送的一个消息大于内部消息缓冲区或一些其它网络限制,或者是用来接受数据报的缓冲区小于数据报本身")},
{10041, OS_TEXT("在socket()函数调用中指定的协议不支持请求的套接字类型的语义")},
{10042, OS_TEXT("在getsockopt()或setsockopt()调用中,指定了一个未知的、非法的或不支持的选项或层(level)")},
{10043, OS_TEXT("请求的协议没有在系统中配置或没有支持它的实现存在")},
{10044, OS_TEXT("不支持在此地址族中指定的套接字类型")},
{10045, OS_TEXT("对于引用的对象的类型来说,试图进行的操作不支持")},
{10046, OS_TEXT("协议簇没有在系统中配置或没有支持它的实现存在")},
{10047, OS_TEXT("使用的地址与被请求的协议不兼容")},
{10048, OS_TEXT("重复使用一个套接字地址(协议/IP地址/端口号)")},
{10049, OS_TEXT("被请求的地址在它的环境中是不合法的")},
{10050, OS_TEXT("套接字操作遇到一个不活动的网络")},
{10051, OS_TEXT("试图和一个无法到达的网络进行套接字操作")},
{10052, OS_TEXT("在操作正在进行时连接因“keep-alive”检测到失败而中断")},
{10053, OS_TEXT("一个已建立的连接被你的主机上的软件终止")},
{10054, OS_TEXT("存在的连接被远程主机强制关闭")},
{10055, OS_TEXT("由于系统缺乏足够的缓冲区空间,或因为队列已满")},
{10056, OS_TEXT("连接请求发生在已经连接的套接字上")},
{10057, OS_TEXT("因为套接字没有连接发送或接收数据的请求不被允许或者是使用sendto()函数在数据报套接字上发送时没有提供地址")},
{10058, OS_TEXT("因为套接字在相应方向上已经被先前的shutdown()调用关闭,因此该方向上的发送或接收请求不被允许")},
{10060, OS_TEXT("连接请求因被连接方在一个时间周期内不能正确响应而失败,或已经建立的连接因被连接的主机不能响应而失败")},
{10061, OS_TEXT("因为目标主机主动拒绝,连接不能建立")},
{10064, OS_TEXT("套接字操作因为目的主机关闭而失败返回")},
{10065, OS_TEXT("试图和一个不可达主机进行套接字操作")},
{10067, OS_TEXT("太多的socket应用程序")},
{10091, OS_TEXT("此时Windows Sockets实现因底层用来提供网络服务的系统不可用")},
{10093, OS_TEXT("应用程序没有调用WSAStartup()函数或函数WSAStartup()调用失败了")},
{10101, OS_TEXT("远端已经初始化了一个“雅致”的关闭序列")},
{10109, OS_TEXT("指定的类没有找到")},
{11001, OS_TEXT("主机未知")},
{11002, OS_TEXT("在主机名解析时的临时错误,它意味着本地服务器没有从授权服务器接收到一个响应")},
{11003, OS_TEXT("在数据库查找时发生了某种不可恢复错误")},
{11004, OS_TEXT("请求的名字合法并且在数据库中找到了,但它没有正确的关联数据用于解析")},
{11092, OS_TEXT("当前的Windows Sockets实现不支持应用程序指定的Windows Sockets规范版本")},
#endif//HGL_OS != HGL_OS_Windows
{-1, OS_TEXT("未知错误")},
};
/**
* SOCKET错误详细信息字符串
* @param n
* @return
*/
const os_char *GetSocketString(int n)
{
int i=0;
while(tab[i].number!=-1)
{
if(tab[i].number==n)
return tab[i].recountal;
i++;
}
return(tab[i].recountal); //此时tab[i].number==-1
}
/**
* @param ThisSocket socket
*/
void CloseSocket(int ThisSocket)
{
if(ThisSocket<=-1)return;
#ifdef _WIN32
closesocket(ThisSocket);
LOG_INFO(OS_TEXT("CloseSocket: ") + OSString(ThisSocket));
#else
int result;
do
{
shutdown(ThisSocket,SHUT_RDWR); //终止读写操作
result=close(ThisSocket);
LOG_INFO(OS_TEXT("CloseSocket: ")+OSString(ThisSocket)+OS_TEXT(",result:")+OSString(result)+OS_TEXT(",errno: ")+OSString(errno));
if(errno==EBADF)break;
if(errno==EINPROGRESS)continue;
}while(result);
LOG_INFO(OS_TEXT("CloseSocket: ") + OSString(ThisSocket) + OS_TEXT(",result:") + OSString(result));
#endif//_WIN32
}
/**
* 使
* @param ThisSocket socket
* @param block 使(true/false)
* @param send_time_out (: )
* @param recv_time_out (: )
*/
void SetSocketBlock(int ThisSocket,bool block,double send_time_out,double recv_time_out)
{
#if HGL_OS == HGL_OS_Windows
u_long par = (block ? 0 : 1);
DWORD stv=send_time_out*1000;
DWORD rtv=recv_time_out*1000;
ioctlsocket(ThisSocket, FIONBIO, &par);
setsockopt(ThisSocket,SOL_SOCKET,SO_RCVTIMEO,(char *)&rtv,sizeof(DWORD));
setsockopt(ThisSocket,SOL_SOCKET,SO_SNDTIMEO,(char *)&stv,sizeof(DWORD));
#else
int par=(block?0:1);
timeval stv,rtv;
SetTimeVal(stv,send_time_out);
SetTimeVal(rtv,recv_time_out);
ioctl(ThisSocket,FIONBIO,&par);
setsockopt(ThisSocket,SOL_SOCKET,SO_RCVTIMEO,(char *)&rtv,sizeof(timeval));
setsockopt(ThisSocket,SOL_SOCKET,SO_SNDTIMEO,(char *)&stv,sizeof(timeval));
#endif//HGL_OS == HGL_OS_Windows
}
void SetSocketLinger(int ThisSocket,int time_out)
{
struct linger so_linger;
if(time_out>0)
{
so_linger.l_onoff=1;
so_linger.l_linger=time_out;
}
else
{
so_linger.l_onoff=0;
}
setsockopt(ThisSocket,SOL_SOCKET,SO_LINGER,(const char *)&so_linger,sizeof(linger));
}
}//namespace network
}//namespace hgl

249
src/SocketInputStream.cpp Normal file
View File

@ -0,0 +1,249 @@
#include<hgl/network/SocketInputStream.h>
#include<hgl/io/DataInputStream.h>
#include<hgl/network/TCPSocket.h>
#include<hgl/type/MemBlock.h>
#include<hgl/LogInfo.h>
namespace hgl
{
namespace network
{
bool Read(io::DataInputStream *dis,sockaddr_in &addr)
{
if(dis->ReadUint8((uint8 *)&(addr.sin_addr.s_addr),4)!=4)
return(false);
return dis->ReadUint16(addr.sin_port);
}
}//namespace network
namespace network
{
SocketInputStream::SocketInputStream(int s)
{
// LOG_INFO(OS_TEXT("SocketInputStream::SocketInputStream(")+OSString(s)+OS_TEXT(")"));
SetSocket(s);
mb=new MemBlock<char>();
}
SocketInputStream::~SocketInputStream()
{
// LOG_INFO(OS_TEXT("SocketInputStream::~SocketInputStream(")+OSString(sock)+OS_TEXT(")"));
SAFE_CLEAR(mb);
}
/**
* socket中读取指定的字节数
* @param buf
* @param size
* @return
* @return -1
*/
int64 SocketInputStream::Read(void *buf,int64 size)
{
if(sock==-1)
{
LOG_ERROR(OS_TEXT("SocketInputStream::Read() fatal error,sock=-1"));
return(-1);
}
if(size==0)return(0);
if(size<0)
{
LOG_ERROR(OS_TEXT("SocketInputStream::Read() fatal error,size<0,sock=")+OSString(sock));
return(-3);
}
if(!buf)
{
LOG_ERROR(OS_TEXT("SocketInputStream::Read() fatal error,buf=nullptr,sock=")+OSString(sock));
return(-2);
}
const int64 result=recv(sock,(char *)buf,size,0);
if(result>0)
{
total+=result;
// LOG_INFO(OS_TEXT("Socket ")+OSString(sock)+OS_TEXT(" recv ")+OSString(size)+OS_TEXT(" bytes ok,result ")+OSString(result)+OS_TEXT(" total recv ")+OSString(total)+OS_TEXT(" bytes."));
}
else if(result<0)
{
int err=GetLastSocketError();
if(err==nseWouldBlock)
return 0;
LOG_INFO(OS_TEXT("Socket ")+OSString(sock)+OS_TEXT(" recv ")+OSString(size)+OS_TEXT(" bytes failed,error: ")+OSString(err)+OS_TEXT(",")+GetSocketString(err));
}
return(result);
}
/**
* socket中读取指定的字节数
* @param buf
* @param size
* @return
* @return -1
*/
int64 SocketInputStream::Peek(void *buf,int64 size)
{
if(sock==-1)
{
LOG_ERROR(OS_TEXT("SocketInputStream::Peek() fatal error,sock=-1"));
return(-1);
}
if(!buf)
{
LOG_ERROR(OS_TEXT("SocketInputStream::Peek() fatal error,buf=nullptr,sock=")+OSString(sock));
return(-2);
}
if(size<=0)
{
LOG_ERROR(OS_TEXT("SocketInputStream::Peek() fatal error,size<=0,sock=")+OSString(sock));
return(-3);
}
return recv(sock,(char *)buf,size,MSG_PEEK);
}
/**
* socket中充分读取指定的字节数
* @param buf
* @param size
* @return
* @return -1
*/
int64 SocketInputStream::ReadFully(void *buf,int64 size)
{
if(sock==-1)
{
LOG_ERROR(OS_TEXT("SocketInputStream::ReadFully() fatal error,sock=-1"));
return(-1);
}
if(size==0)return(0);
if(size<0)
{
LOG_ERROR(OS_TEXT("SocketInputStream::ReadFully() fatal error,size<0,sock=")+OSString(sock));
return(-3);
}
if(!buf)
{
LOG_ERROR(OS_TEXT("SocketInputStream::ReadFully() fatal error,buf=nullptr,sock=")+OSString(sock));
return(-2);
}
bool to_first=true;
int err;
const os_char *err_str;
char *p=(char *)buf;
#if HGL_OS == HGL_OS_Windows
int result = 0;
int left_bytes = size;
#else
ssize_t result = 0;
size_t left_bytes = size;
#endif//HGL_OS == HGL_OS_Windows
// const double start_time=GetDoubleTime();
while(left_bytes>0)
{
//如果最后一个参数使用MSG_WAITALL则无论是否阻塞模式都会永远阻塞
//使用0则会得出一个11号nseTryAgain错误
result=recv(sock,p,left_bytes,0); //似乎windows 2003才开始支持MSG_WAITALL
if(result==0) //linux下返回0即为对方断开连接,win/bsd下未验证
{
sock=-1;
break;
}
if(result<0)
{
err=GetLastSocketError();
// std::cerr<<"SocketInputStream::ReadFully error,Socket:"<<sock<<",error code="<<err<<std::endl;
if(err==0 //没有错误
||err==nseInt) //Interrupted system call(比如ctrl+c,一般DEBUG下才有)
continue;
if(err==nseWouldBlock) //资源临时不可用,仅代表没数据,并不是出错的意思
break;
if(err==nseTimeOut) //超时
{
// if(to_first)
// {
// to_first=false;
// continue;
// }
LOG_ERROR(OS_TEXT("SocketInputStream::ReadFully TimeOut,Socket:")+OSString(sock));
}
err_str=GetSocketString(err);
if(err_str)
{
LOG_ERROR(OS_TEXT("SocketInputStream::ReadFully error,Socket:")+OSString(sock)+OS_TEXT(",error code=")+OSString(err)+OS_TEXT(":")+OSString(err_str));
}
else
{
LOG_ERROR(OS_TEXT("SocketInputStream::ReadFully error,Socket:")+OSString(sock)+OS_TEXT(",error code=")+OSString(err));
}
sock=-1;
break;
}
else
{
p+=result;
left_bytes-=result;
}
}
// const double end_time=GetDoubleTime();
// LOG_INFO(OS_TEXT("SocketInputStream::ReadFully() time: ")+OSString(end_time-start_time));
// #ifdef _DEBUG
// result=(p-(char *)buf);
// total+=result;
//
// LOG_INFO(OS_TEXT("Socket ")+OSString(sock)+OS_TEXT(" recv ")+OSString(result)+OS_TEXT(" bytes,total recv ")+OSString(total)+OS_TEXT(" bytes."));
// #else
total+=(p-(char *)buf);
// #endif//_DEBUG
return(p-(char *)buf);
}
int64 SocketInputStream::Skip(int64 n)
{
if(n<=0)return(n);
mb->SetLength(n);
return ReadFully(mb->data(),n);
}
int64 SocketInputStream::Available()const
{
int recv_buf_size=0;
socklen_t len=sizeof(int);
getsockopt(sock,SOL_SOCKET,SO_RCVBUF,(char *)&recv_buf_size,&len); //这个函数会出错,但我们不理会
return recv_buf_size;
}
}//namespace network
}//namespace hgl

223
src/SocketManage.cpp Normal file
View File

@ -0,0 +1,223 @@
#include<hgl/network/SocketManage.h>
#include<hgl/LogInfo.h>
#include"SocketManageBase.h"
namespace hgl
{
namespace network
{
SocketManage::SocketManage(int max_user)
{
manage=CreateSocketManageBase(max_user);
}
SocketManage::~SocketManage()
{
delete manage;
}
void SocketManage::ProcSocketRecvList()
{
const int count=sock_recv_list.GetCount();
if(count<=0)return;
SocketEvent *se=sock_recv_list.GetData();
TCPAccept *sock;
for(int i=0;i<count;i++)
{
if(socket_list.Get(se->sock,sock))
{
if(sock->OnSocketRecv(se->error)<0)
{
LOG_INFO(OS_TEXT("OnSocketRecv return Error,sock:")+OSString(se->sock));
error_set.Add(sock);
}
}
else
{
LOG_ERROR(OS_TEXT("Fatal error,can't find socket in SocketList,sock is ")+OSString(se->sock));
}
++se;
}
sock_recv_list.ClearData();
}
void SocketManage::ProcSocketSendList()
{
const int count=sock_send_list.GetCount();
if(count<=0)return;
SocketEvent *se=sock_send_list.GetData();
TCPAccept *sock;
for(int i=0;i<count;i++)
{
if(socket_list.Get(se->sock,sock))
{
if(sock->OnSocketSend(se->size)<0)
{
LOG_INFO(OS_TEXT("OnSocketSend return Error,sock:")+OSString(se->sock));
error_set.Add(sock);
}
}
else
{
LOG_ERROR(OS_TEXT("Fatal error,can't find socket in SocketList,sock is ")+OSString(se->sock));
}
++se;
}
sock_send_list.ClearData();
}
void SocketManage::ProcSocketErrorList()
{
const int count=sock_error_list.GetCount();
if(count<=0)return;
SocketEvent *se=sock_error_list.GetData();
TCPAccept *sock;
for(int i=0;i<count;i++)
{
if(socket_list.Get(se->sock,sock))
{
LOG_INFO(OS_TEXT("SocketError,sock:")+OSString(se->sock)+OS_TEXT(",errno:")+OSString(se->error));
sock->OnSocketError(se->error);
error_set.Add(sock);
}
else
{
LOG_ERROR(OS_TEXT("Fatal error,can't find socket in SocketList,sock is ")+OSString(se->sock));
}
++se;
}
sock_error_list.ClearData();
}
void SocketManage::ProcErrorList()
{
const int count=error_set.GetCount();
if(count<=0)return;
TCPAccept **sp=error_set.GetData();
for(int i=0;i<count;i++)
{
Unjoin(*sp);
++sp;
}
//error_set不在这里ClearData在主循环的一开始参见那里的注释
}
bool SocketManage::Join(TCPAccept *s)
{
if(!s)return(false);
if(!socket_list.Add(s->ThisSocket,s))
{
LOG_ERROR(OS_TEXT("repeat append socket to manage,sock:")+OSString(s->ThisSocket));
return(false);
}
if(!manage->Join(s->ThisSocket))
{
socket_list.DeleteByKey(s->ThisSocket);
return(false);
}
return(true);
}
int SocketManage::Join(TCPAccept **s_list,int count)
{
if(!s_list||count<=0)
return(-1);
int total=0;
for(int i=0;i<count;i++)
{
if(this->Join(s_list[i]))
++total;
}
return total;
}
bool SocketManage::Unjoin(TCPAccept *s)
{
if(!s)return(false);
if(!socket_list.DeleteByKey(s->ThisSocket))
{
LOG_ERROR(OS_TEXT("socket don't in SocketManage,sock:")+OSString(s->ThisSocket));
return(false);
}
manage->Unjoin(s->ThisSocket); //unjoin理论上不存在失败
return(true);
}
int SocketManage::Unjoin(TCPAccept **s_list,int count)
{
if(!s_list||count<=0)
return(-1);
int total=0;
for(int i=0;i<count;i++)
{
if(this->Unjoin(s_list[i]))
++total;
}
return total;
}
int SocketManage::Update(const double &time_out)
{
//将error_set放在这里是为了保留它给外面的调用者使用
error_set.ClearData();
const int count=manage->Update(time_out,sock_recv_list,sock_send_list,sock_error_list);
if(count<=0)
return(count);
ProcSocketSendList(); //这是上一帧的,所以先发。未来可能考虑改成另建一批线程发送
ProcSocketRecvList();
ProcSocketErrorList();
ProcErrorList(); //这里仅仅是将Socket从列表中移除并没有删掉。
return count;
}
void SocketManage::Clear()
{
const int count=socket_list.GetCount();
auto **us=socket_list.GetDataList();
for(int i=0;i<count;i++)
{
Unjoin((*us)->right);
++us;
}
socket_list.ClearData();
}
}//namespace network
}//namespace hgl

35
src/SocketManageBase.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef HGL_NETWORK_SOCKET_MANAGE_BASE_INCLUDE
#define HGL_NETWORK_SOCKET_MANAGE_BASE_INCLUDE
#include<hgl/network/SocketEvent.h>
namespace hgl
{
namespace network
{
/**
* Socket基础管理
*/
class SocketManageBase
{
public:
virtual ~SocketManageBase()=default;
virtual bool Join(int)=0; ///<加入一个Socket
// virtual bool Join(const int *,int)=0; ///<加入一批Socket
virtual bool Unjoin(int)=0; ///<分离一个Socket
// virtual bool Unjoin(const int *,int)=0; ///<分离一批Socket
virtual int GetCount()const=0; ///<取得Socket数量
virtual void Clear()=0; ///<清除所有Socket
virtual int Update(const double &,
SocketEventList &,
SocketEventList &,
SocketEventList &)=0; ///<轮循刷新所有socket
};//class SocketManageBase
SocketManageBase *CreateSocketManageBase(int max_user); ///<创建一个Socket基础管理器
}//namespace network
}//namespace hgl
#endif//HGL_NETWORK_SERVER_ACCEPT_MANAGE_BASE_INCLUDE

255
src/SocketManageEpoll.cpp Normal file
View File

@ -0,0 +1,255 @@
#include"SocketManageBase.h"
#include<hgl/network/Socket.h>
#include<hgl/LogInfo.h>
#include<unistd.h>
#include<sys/epoll.h>
namespace hgl
{
namespace network
{
class SocketManageEpoll:public SocketManageBase
{
protected:
int epoll_fd;
uint user_event;
int max_connect;
int cur_count;
protected:
epoll_event *event_list;
private:
bool epoll_add(int sock)
{
epoll_event ev;
hgl_zero(ev);
ev.data.fd= sock;
ev.events= user_event //要处理的事件
|EPOLLET //边缘模式(即读/写时,需要一直读/写直到出错为止相对LT模式是只要有数据就会一直通知)
|EPOLLERR //出错
|EPOLLRDHUP //对方挂断
|EPOLLHUP; //挂断
return(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,sock,&ev)==0);
}
bool epoll_del(int sock)
{
//在内核版本 2.6.9 之前EPOLL_CTL_DEL 要求一个 event 是非空的指针,尽管这个参数会被忽略。
//从 Linux 2.6.9 开始,在执行 EPOLL_CTL_DEL 时 event 可以指定为 NULL。
//我们不支持Linux 2.6.9之前的版本所以直接传NULL
return(epoll_ctl(epoll_fd,EPOLL_CTL_DEL,sock,nullptr)==0);
}
public:
SocketManageEpoll(int epfd,uint ue,int mc)
{
epoll_fd=epfd;
user_event=ue;
max_connect=mc;
cur_count=0;
event_list=new epoll_event[max_connect];
}
~SocketManageEpoll()
{
delete[] event_list;
close(epoll_fd);
}
bool Join(int sock) override
{
epoll_add(sock);
SetSocketBlock(sock,false);
++cur_count;
LOG_INFO(OS_TEXT("SocketManageEpoll::Join() Socket:")+OSString(sock));
return(true);
}
// bool Join(const int *sock_list,int count) override
// {
// if(count<=0)return(false);
//
// for(int i=0;i<count;i++)
// {
// epoll_add(*sock_list);
//
// SetSocketBlock(*sock_list,false);
//
// ++sock_list;
// }
//
// cur_count+=count;
//
// return(true);
// }
bool Unjoin(int sock) override
{
if(epoll_fd==-1)
{
LOG_ERROR(OS_TEXT("SocketManageEpoll::Unjoin() epoll_fd==-1)"));
return(false);
}
--cur_count;
epoll_del(sock);
LOG_INFO(OS_TEXT("SocketManageEpoll::Unjoin() Socket:")+OSString(sock));
return(true);
}
// bool Unjoin(const int *sock_list,int count) override
// {
// if(epoll_fd==-1)
// {
// LOG_ERROR(OS_TEXT("SocketManageEpoll::Unjoin() epoll_fd==-1)"));
// return(false);
// }
//
// if(!sock_list||count<=0)return(false);
//
// for(int i=0;i<count;i++)
// {
// epoll_del(*sock_list);
// ++sock_list;
// }
//
// cur_count-=count;
// LOG_INFO(OS_TEXT("SocketManageEpoll::Unjoin() Socket count:")+OSString(count));
//
// return(true);
// }
int GetCount()const override
{
return cur_count;
}
void Clear() override
{
if(epoll_fd!=-1)
{
close(epoll_fd);
epoll_fd=-1;
}
cur_count=0;
}
int Update(const double &time_out,SocketEventList &recv_list,SocketEventList &send_list,SocketEventList &error_list) override
{
int event_count=0;
if(epoll_fd==-1)
return(-1);
if(cur_count<=0)
return(0);
event_count=epoll_wait(epoll_fd,event_list,cur_count,time_out<0?-1:time_out*HGL_MILLI_SEC_PRE_SEC);
if(event_count==0)
return(0);
if(event_count<0)
{
LOG_INFO(OS_TEXT("epoll return -1,errno: ")+OSString(errno));
if(errno==EBADF
||errno==EFAULT
||errno==EINVAL)
return(-1);
return(0);
}
recv_list.PreMalloc(event_count);
send_list.PreMalloc(event_count);
error_list.PreMalloc(event_count);
epoll_event *ee=this->event_list;
SocketEvent *rp=recv_list.GetData();
SocketEvent *sp=send_list.GetData();
SocketEvent *ep=error_list.GetData();
int recv_num=0;
int send_num=0;
int error_num=0;
for(int i=0;i<event_count;i++)
{
if(ee->events&( EPOLLERR| //出错了
EPOLLRDHUP| //对方关了
EPOLLHUP)) //我方强制关了
{
LOG_ERROR("SocketManageEpoll Error,socket:"+OSString(ee->data.fd)+",epoll event:"+OSString(ee->events));
ep->sock=ee->data.fd;
ep->error=ee->events;
++ep;
++error_num;
}
else
if(ee->events&EPOLLIN) //可以读数据
{
rp->sock=ee->data.fd;
rp->size=0;
++rp;
++recv_num;
}
else
if(ee->events&EPOLLOUT) //可以发数据
{
sp->sock=ee->data.fd;
sp->size=0;
++sp;
++send_num;
}
++ee;
}
recv_list.SetCount(recv_num);
send_list.SetCount(send_num);
error_list.SetCount(error_num);
return(event_count);
}
};//class SocketManageEpoll:public SocketManageBase
SocketManageBase *CreateSocketManageBase(int max_user)
{
if(max_user<=0)return(nullptr);
int epoll_fd=epoll_create(max_user);
if(epoll_fd<0)
{
LOG_ERROR(OS_TEXT("epoll_create return error,errno is")+OSString(errno));
return(nullptr);
}
return(new SocketManageEpoll(epoll_fd,EPOLLIN,max_user)); //暂时只处理recv。。。至于send则直接强制发完不走epoll
//return(new SocketManageEpoll(epoll_fd,EPOLLIN|EPOLLOUT,max_user));
}
}//namespace network
}//namespace hgl

150
src/SocketManageSelect.cpp Normal file
View File

@ -0,0 +1,150 @@
#include"SocketManageBase.h"
#include<hgl/network/Socket.h>
#include<hgl/Time.h>
#include<hgl/type/Set.h>
#include<hgl/LogInfo.h>
namespace hgl
{
void SetTimeVal(timeval &tv,const double t_sec);
namespace network
{
class SocketManageSelect:public SocketManageBase
{
int max_connect;
int cur_count;
int max_fd;
Set<int> sock_id_list;
fd_set fd_sock_list; //完整的sock列表
fd_set fd_recv_list;
fd_set fd_send_list;
fd_set fd_error_list;
timeval time_out,*time_par;
public:
SocketManageSelect(int mc)
{
cur_count=0;
max_connect=mc;
max_fd=0;
Clear();
}
bool Join(int sock) override
{
FD_SET(sock,&fd_sock_list);
sock_id_list.Add(sock);
if(sock>max_fd)
max_fd=sock;
SetSocketBlock(sock,false);
cur_count++;
LOG_INFO(OS_TEXT("Join ")+OSString(sock)+OS_TEXT(" to SocketManageSelect"));
return(true);
}
bool Unjoin(int sock) override
{
cur_count--;
FD_CLR(sock,&fd_sock_list);
sock_id_list.Delete(sock);
LOG_INFO(OS_TEXT("Unjoin ")+OSString(sock)+OS_TEXT(" from SocketManageSelect"));
return(true);
}
int GetCount()const override
{
return cur_count;
}
void Clear() override
{
cur_count=0;
max_fd=0;
FD_ZERO(&fd_sock_list);
FD_ZERO(&fd_recv_list);
FD_ZERO(&fd_send_list);
FD_ZERO(&fd_error_list);
}
int ConvertList(SocketEventList &sel,const fd_set &fs)
{
sel.SetCount(fs.fd_count);
SocketEvent *p=sel.GetData();
for(uint i=0;i<fs.fd_count;i++)
{
p->sock=fs.fd_array[i];
p->size=-1;
++p;
}
return fs.fd_count;
}
int Update(const double &to,SocketEventList &recv_list,SocketEventList &send_list,SocketEventList &error_list) override
{
if(cur_count<=0)
return(0);
if(to<=0)
time_par=nullptr; //传入nullptr表示阻塞模式
else
{ //时间为0表示非阻塞
SetTimeVal(time_out,to);
time_par=&time_out;
}
memcpy(&fd_recv_list, &fd_sock_list,sizeof(fd_sock_list));
memcpy(&fd_send_list, &fd_sock_list,sizeof(fd_sock_list));
memcpy(&fd_error_list, &fd_sock_list,sizeof(fd_sock_list));
if(select(max_fd+1,&fd_recv_list,&fd_send_list,&fd_error_list,time_par)<0)
{
LOG_INFO(OS_TEXT("select return -1,errno: ")+OSString(errno));
if(errno==EBADF
||errno==EFAULT
||errno==EINVAL)
return(-1);
return(0);
}
ConvertList(recv_list,fd_recv_list);
ConvertList(send_list,fd_send_list);
ConvertList(error_list,fd_error_list);
return(fd_recv_list.fd_count
+fd_send_list.fd_count
+fd_error_list.fd_count);
}
};//class SocketManageSelect:public SocketManageBase
SocketManageBase *CreateSocketManageBase(int max_user)
{
return(new SocketManageSelect(max_user));
}
}//namespace network
}//namespace hgl

178
src/SocketOutputStream.cpp Normal file
View File

@ -0,0 +1,178 @@
#include<hgl/network/SocketOutputStream.h>
#include<hgl/io/DataOutputStream.h>
#include<hgl/network/TCPSocket.h>
#include<hgl/LogInfo.h>
namespace hgl
{
namespace network
{
// bool Write(io::DataOutputStream *dos,const sockaddr_in &addr)
// {
// #if (HGL_COMPILER == HGL_COMPILER_GNU)||(HGL_COMPILER == HGL_COMPILER_LLVM)
// if(dos->WriteUint8((uint8 *)&(addr.sin_addr.s_addr),4)!=4)return(false);
// #else
// #if (HGL_OS == HGL_OS_Windows)
// if(dos->WriteUint8((uint8 *)&(addr.sin_addr.S_addr),4)!=4)return(false);
// #endif//
// #endif//
//
// return dos->WriteUint16(addr.sin_port);
// }
}//namespace network
namespace network
{
/**
* socket中写入指定的字节数
* @param buf
* @param size
* @return
* @return -1
*/
int64 SocketOutputStream::Write(const void *buf,int64 size)
{
if(sock==-1)
{
LOG_ERROR(OS_TEXT("SocketOutputStream::Write() fatal error,sock=-1"));
return(-1);
}
if(size==0)return(0);
if(size<0)
{
LOG_ERROR(OS_TEXT("SocketOutputStream::Write() fatal error,size<0,sock=")+OSString(sock));
return(-3);
}
if(!buf)
{
LOG_ERROR(OS_TEXT("SocketOutputStream::Write() fatal error,buf=nullptr,sock=")+OSString(sock));
return(-2);
}
const int64 result=send(sock,(char *)buf,size,0);
if(result>0)
{
total+=result;
// LOG_INFO(OS_TEXT("Socket ")+OSString(sock)+OS_TEXT(" send ")+OSString(size)+OS_TEXT(" bytes ok,result ")+OSString(result)+OS_TEXT(" total send ")+OSString(total)+OS_TEXT(" bytes."));
}
else
{
int err=GetLastSocketError();
LOG_INFO(OS_TEXT("Socket ")+OSString(sock)+OS_TEXT(" send ")+OSString(size)+OS_TEXT(" bytes failed,,error: ")+OSString(err)+OS_TEXT(",")+GetSocketString(err));
}
return(result);
}
/**
* socket中充分写入指定的字节数
* @param buf
* @param size
* @return
* @return -1
*/
int64 SocketOutputStream::WriteFully(const void *buf,int64 size)
{
if(sock==-1)
{
LOG_ERROR(OS_TEXT("SocketOutputStream::WriteFully() fatal error,sock=-1"));
return(-1);
}
if(size==0)return(0);
if(size<0)
{
LOG_ERROR(OS_TEXT("SocketOutputStream::WriteFully() fatal error,size<0,sock=")+OSString(sock));
return(-3);
}
if(!buf)
{
LOG_ERROR(OS_TEXT("SocketOutputStream::WriteFully() fatal error,buf=nullptr,sock=")+OSString(sock));
return(-2);
}
int err;
const os_char *err_str;
char *p=(char *)buf;
// const double start_time=GetDoubleTime();
#if HGL_OS == HGL_OS_Windows
int result = 0;
int left_bytes = size;
#else
ssize_t result = 0;
size_t left_bytes = size;
#endif//HGL_OS == HGL_OS_Windows
while(left_bytes>0)
{
result=send(sock,p,left_bytes,0);
// LOG_ERROR(OS_TEXT("socket send result, left_bytes: ")+OSString(sock)+OSString(" , ")+OSString((int)result)+OSString(" , ")+OSString((int)left_bytes));
if(result==0)
{
sock=-1;
break;
}
if(result<0)
{
err=GetLastSocketError();
if(err==0
||err==nseTimeOut
||err==nseWouldBlock
||err==nseInt
)
continue;
if(err==nseBrokenPipe)
{
sock=-1;
break;
}
err_str=GetSocketString(err);
if(err_str)
{
LOG_ERROR(OS_TEXT("SocketOutputStream::WriteFully error,Socket:")+OSString(sock)+OS_TEXT(",error code=")+OSString(err)+OS_TEXT(":")+OSString(err_str));
}
else
{
LOG_ERROR(OS_TEXT("SocketOutputStream::WriteFully error,Socket:")+OSString(sock)+OS_TEXT(",error code=")+OSString(err));
}
sock=-1;
break;
}
p+=result;
left_bytes-=result;
}
// const double end_time=GetDoubleTime();
// LOG_INFO(OS_TEXT("SocketOutputStream::WriteFully() time: ")+OSString(end_time-start_time));
total+=(p-(char *)buf);
return(p-(char *)buf);
}
int64 SocketOutputStream::Available()const
{
int send_buf_size=0;
socklen_t len=sizeof(int);
getsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char *)&send_buf_size,&len); //这个函数会出错,但我们不理会
return send_buf_size;
}
}//namespace network
}//namespace hgl

34
src/TCPAccept.cpp Normal file
View File

@ -0,0 +1,34 @@
#include<hgl/network/TCPAccept.h>
#include<hgl/network/SocketInputStream.h>
#include<hgl/network/SocketOutputStream.h>
#include<hgl/io/DataInputStream.h>
#include<hgl/io/DataOutputStream.h>
#include<hgl/Str.h>
namespace hgl
{
namespace network
{
TCPAccept::~TCPAccept()
{
SAFE_CLEAR(sos);
SAFE_CLEAR(sis);
}
bool TCPAccept::Send(void *data,const uint size)
{
if(!data)return(false);
if(size<=0)return(false);
if(!sos)
sos=new SocketOutputStream(ThisSocket);
int result=sos->WriteFully(data,size);
if(result!=size)
return(false);
return(true);
}
}//namespace network
}//namespace hgl

104
src/TCPAcceptPacket.cpp Normal file
View File

@ -0,0 +1,104 @@
#include<hgl/network/TCPAccept.h>
#include<hgl/network/SocketInputStream.h>
#include<hgl/network/SocketOutputStream.h>
#include<hgl/io/DataInputStream.h>
#include<hgl/io/DataOutputStream.h>
#include<hgl/Str.h>
namespace hgl
{
namespace network
{
TCPAcceptPacket::TCPAcceptPacket():TCPAccept(),recv_buffer(HGL_TCP_BUFFER_SIZE)
{
}
TCPAcceptPacket::TCPAcceptPacket(int s,IPAddress *ip):TCPAccept(s,ip),recv_buffer(HGL_TCP_BUFFER_SIZE)
{
}
/**
* socket接收数据回调函数<br>
*/
int TCPAcceptPacket::OnSocketRecv(int /*size*/)
{
if(!sis)
{
sis=new SocketInputStream(ThisSocket);
recv_total=0;
recv_length=0;
}
int total=0;
while(true)
{
if(recv_length<PACKET_SIZE_TYPE_BYTES) //头都没收完
{
int result=sis->Read(recv_buffer.data()+recv_length,PACKET_SIZE_TYPE_BYTES-recv_length);
if(result<0)
return(result);
if(result==0)
return total;
recv_length+=result;
recv_total+=result;
total+=result;
}
if(recv_length<PACKET_SIZE_TYPE_BYTES) //已经有头了
continue;
PACKET_SIZE_TYPE pack_size=*(PACKET_SIZE_TYPE *)(recv_buffer.data());
recv_buffer.SetLength(PACKET_SIZE_TYPE_BYTES+pack_size);
int result=sis->Read(recv_buffer.data()+recv_length,pack_size-(recv_length-PACKET_SIZE_TYPE_BYTES));
if(result<0)
return(result);
if(result==0)
return total;
recv_length+=result;
recv_total+=result;
total+=result;
if(recv_length<pack_size+PACKET_SIZE_TYPE_BYTES) //这个包还没收完整
return(total); //证明socket缓冲区里没有数据了直接返回
OnRecvPacket(recv_buffer.data()+PACKET_SIZE_TYPE_BYTES,pack_size); //调用回调
recv_buffer.ClearData();
recv_length=0;
}
}
bool TCPAcceptPacket::SendPacket(void *data,const PACKET_SIZE_TYPE &size)
{
if(!data)return(false);
if(size<=0)return(false);
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$4
//直接发,,,,正式版 本当然不能这样写,,,但现在先这样了
if(!sos)
sos=new SocketOutputStream(ThisSocket);
int result=sos->WriteFully(&size,sizeof(PACKET_SIZE_TYPE));
if(result!=sizeof(PACKET_SIZE_TYPE))
return(false);
result=sos->WriteFully(data,size);
if(result!=size)
return(false);
return(true);
}
}//namespace network
}//namespace hgl

167
src/TCPClient.cpp Normal file
View File

@ -0,0 +1,167 @@
#include<hgl/network/TCPClient.h>
#include<hgl/LogInfo.h>
#include<hgl/network/SocketInputStream.h>
#include<hgl/network/SocketOutputStream.h>
/*
线 线
线
线线线
*/
/*
线
线socket接收到暂存缓冲区
线
线
访
线socket接收缓冲区暴满
*/
namespace hgl
{
namespace network
{
void TCPClient::InitPrivate(int sock)
{
TimeOut=HGL_NETWORK_TIME_OUT;
sis=new SocketInputStream(sock);
sos=new SocketOutputStream(sock);
ipstr = nullptr;
}
/**
* TCP客户端连接类构造函数
*/
TCPClient::TCPClient():TCPSocket()
{
InitPrivate(-1);
}
TCPClient::TCPClient(int sock,const IPAddress *addr):TCPSocket(sock,addr)
{
InitPrivate(sock);
}
TCPClient::~TCPClient()
{
Disconnect();
SAFE_CLEAR(sis);
SAFE_CLEAR(sos);
SAFE_CLEAR_ARRAY(ipstr);
}
/**
*
* @return
*/
bool TCPClient::Connect()
{
if(ThisSocket<0||!ThisAddress)RETURN_FALSE;
if(connect(ThisSocket,ThisAddress->GetSockAddr(),ThisAddress->GetSockAddrInSize()))
{
SAFE_CLEAR(ipstr);
ipstr=ThisAddress->CreateString();
LOG_HINT(U8_TEXT("Don't Connect to TCPServer ")+UTF8String(ipstr));
this->CloseSocket();
return(false);
}
// LOG_INFO(u"connect "+u8_to_u16(host)+u':'+UTF16String(port)+u" ok,socket:"+UTF16String(ThisSocket));
SetBlock(true,TimeOut); //阻塞模式
ResetConnect();
return(true);
}
/**
*
* @param addr
*/
bool TCPClient::CreateConnect(const IPAddress *addr)
{
if(!addr)
RETURN_FALSE;
if(!addr->IsTCP())
RETURN_FALSE;
if(!InitSocket(addr))
RETURN_FALSE;
return this->Connect();
}
/**
*
*/
void TCPClient::Disconnect()
{
SAFE_CLEAR_ARRAY(ipstr);
if(ThisSocket==-1)
return;
this->CloseSocket(); //两个线程会自动因为socket关闭而退出
//注线程退出会调用ThreadExit再次调用Disconnect
}
/**
* 使socket
* @param sock socket编号
* @param addr socket地址
*/
bool TCPClient::UseSocket(int sock,const IPAddress *addr)
{
if(!TCPSocket::UseSocket(sock,addr))
RETURN_FALSE;
((SocketInputStream *)sis)->SetSocket(sock);
((SocketOutputStream *)sos)->SetSocket(sock);
return(true);
}
TCPClient *CreateTCPClient(IPAddress *addr)
{
if(!addr)RETURN_ERROR_NULL;
if(!addr->IsTCP())
RETURN_ERROR_NULL;
int sock=CreateSocket(addr);
if(sock<0)
RETURN_ERROR_NULL;
if(!Connect(sock,addr))
{
CloseSocket(sock);
RETURN_ERROR_NULL;
}
return(new TCPClient(sock,addr));
}
}//namespace network
}//namespace hgl

34
src/TCPServer.cpp Normal file
View File

@ -0,0 +1,34 @@
#include<hgl/network/TCPServer.h>
#if HGL_OS != HGL_OS_Windows
#include<netinet/tcp.h>
#endif//
namespace hgl
{
namespace network
{
int TCPServer::CreateServerSocket()
{
//独立一个函数是因为Windows下创建IOCP Server时这里需要特殊实现
return socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
}
#if (HGL_OS != HGL_OS_Windows)&&(HGL_OS != HGL_OS_macOS)&&(HGL_OS != HGL_OS_iOS)
/**
* AcceptAccept成功
* @param time_out ()
*/
void TCPServer::SetDeferAccept(const int time_out)
{
#ifdef HGL_OS_BSD
constexpr struct accept_filter_arg af={"dataready",""};
setsockopt(this->ThisSocket,SOL_SOCKET,SO_ACCEPTFILTER,&af,sizeof(af));
#else
setsockopt(this->ThisSocket,SOL_TCP,TCP_DEFER_ACCEPT,&time_out,sizeof(time_out));
#endif//bsd&mac
}
#endif//no windows&mac
}//namespace network
}//namespace hgl

123
src/TCPSocket.cpp Normal file
View File

@ -0,0 +1,123 @@
#include<hgl/network/TCPSocket.h>
#include<hgl/LogInfo.h>
#if HGL_OS != HGL_OS_Windows
#include<netinet/tcp.h>
#endif//HGL_OS != HGL_OS_Windows
namespace hgl
{
void SetTimeVal(timeval &tv,const double t_sec);
namespace network
{
/**
* 使()
* @param no_delay
*/
bool TCPSocket::SetNodelay(bool no_delay)
{
int flag=(no_delay?1:0);
return(setsockopt(ThisSocket,IPPROTO_TCP,TCP_NODELAY,(char *)&flag,sizeof(flag))!=-1);
}
/**
* 使KEEPALIVE自动保持连接机制
* @param keep_alive
* @param idle (7200)
* @param interval (75)
* @param count (9)
*/
void TCPSocket::SetKeepAlive(bool keep_alive,const int idle,const int interval,const int count)
{
int flag=(keep_alive?1:0);
#if HGL_OS != HGL_OS_Windows
setsockopt(ThisSocket,SOL_SOCKET,SO_KEEPALIVE,&flag,sizeof(flag));
#else
setsockopt(ThisSocket, SOL_SOCKET, SO_KEEPALIVE, (const char *)&flag, sizeof(flag));
#endif//windows
if(!flag)
return;
#if HGL_OS != HGL_OS_Windows //windows不支持
#if HGL_OS != HGL_OS_macOS
setsockopt(ThisSocket,IPPROTO_TCP,TCP_KEEPIDLE, &idle, sizeof(int));
#endif//HGL_OS_macOS
setsockopt(ThisSocket,IPPROTO_TCP,TCP_KEEPINTVL, &interval, sizeof(int));
setsockopt(ThisSocket,IPPROTO_TCP,TCP_KEEPCNT, &count, sizeof(int));
#endif//HGL_OS_Windows
}
void TCPSocket::ResetConnect()
{
FD_ZERO(&local_set);
FD_SET(ThisSocket,&local_set);
}
/**
* 使socket
* @param sock socket编号
* @param addr socket地址
*/
bool TCPSocket::UseSocket(int sock,const IPAddress *addr)
{
if(sock<0)
RETURN_FALSE;
if(!addr->IsTCP())
RETURN_FALSE;
if(!Socket::UseSocket(sock,addr))
RETURN_FALSE;
ResetConnect();
return(true);
}
/**
* socket是否还在联接状态
*/
bool TCPSocket::IsConnect()
{
return(ThisSocket!=-1);
}
/**
*
* @param wait_time
* @return >0
* @return 0
* @return <0
*/
int TCPSocket::WaitRecv(double wait_time)
{
if(ThisSocket==-1)
RETURN_ERROR(-1);
SetTimeVal(time_out,wait_time);
memcpy(&recv_set,&local_set,sizeof(fd_set));
memcpy(&err_set,&local_set,sizeof(fd_set));
const int result=select(ThisSocket+1,&recv_set,nullptr,&err_set,&time_out);
if(result<0)
{
int err=GetLastSocketError();
RETURN_ERROR(-err);
}
if(FD_ISSET(ThisSocket,&recv_set))
return(1);
if(FD_ISSET(ThisSocket,&err_set))
RETURN_ERROR(-1);
return(0);
}
}//namespace network
}//namespace hgl

89
src/UdpLiteSocket.cpp Normal file
View File

@ -0,0 +1,89 @@
#include<hgl/LogInfo.h>
#include<hgl/network/UdpSocket.h>
#include <string.h>
#if HGL_OS != HGL_OS_Windows
#if (HGL_OS == HGL_OS_FreeBSD)||(HGL_OS == HGL_OS_NetBSD)||(HGL_OS == HGL_OS_OpenBSD)||(HGL_OS==HGL_OS_MacOSX)
#include<netinet/udplite.h>
#else
#include<sys/socket.h>
#endif//BSD or macOS
#endif//HGL_OS != HGL_OS_Windows
#ifndef SOL_UDPLITE
#define SOL_UDPLITE 136
#endif//SOL_UDPLITE
#ifndef UDPLITE_SEND_CSCOV
#define UDPLITE_SEND_CSCOV 10
#endif
#ifndef UDPLITE_RECV_CSCOV
#define UDPLITE_RECV_CSCOV 11
#endif
//--------------------------------------------------------------------------------------------------
namespace hgl
{
namespace network
{
/**
* UDPLite连接使IP地址和端口
* @param addr
* @return true
* @return false
*/
bool UDPLiteSocket::Create(const IPAddress *addr)
{
if(!addr)RETURN_FALSE;
if(addr->GetSocketType()!=SOCK_DGRAM)RETURN_FALSE;
if(addr->GetProtocol()!=IPPROTO_UDPLITE)RETURN_FALSE;
if(!CreateSocket(addr->GetFamily(),SOCK_DGRAM,IPPROTO_UDPLITE))
RETURN_FALSE;
socket_protocols=IPPROTO_UDPLITE;
if(!addr->Bind(ThisSocket))
{
hgl::CloseSocket(ThisSocket);
return(false);
}
SetBlock(false);
return(true);
}
/**
* UDPLite连接
*/
bool UDPLiteSocket::Create(int family)
{
if(family!=AF_INET&&family!=AF_INET6)RETURN_FALSE;
if((ThisSocket=socket(family,SOCK_DGRAM,IPPROTO_UDPLITE))<0)
{
LOG_ERROR(U16_TEXT("创建UDPLiteSocket失败errno:")+UTF16String(GetLastSocketError()));
return(false);
}
socket_protocols=IPPROTO_UDPLITE;
SetBlock(false);
return(true);
}
void UDPLiteSocket::SetChecksumCoverage(int send_val,int recv_val)
{
if(ThisSocket==-1)return;
#if HGL_OS == HGL_OS_Windows
setsockopt(ThisSocket, SOL_UDPLITE, UDPLITE_SEND_CSCOV, (const char *)&send_val, sizeof(int));
setsockopt(ThisSocket, SOL_UDPLITE, UDPLITE_RECV_CSCOV, (const char *)&recv_val, sizeof(int));
#else
setsockopt(ThisSocket, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &send_val, sizeof(int));
setsockopt(ThisSocket, SOL_UDPLITE, UDPLITE_RECV_CSCOV, &recv_val, sizeof(int));
#endif//
}
}//namespace network
}//namespace hgl

167
src/UdpSocket.cpp Normal file
View File

@ -0,0 +1,167 @@
#include<hgl/LogInfo.h>
#include<hgl/network/UdpSocket.h>
#include<string.h>
#if HGL_OS != HGL_OS_Windows
#include<netinet/udp.h>
#endif//HGL_OS != HGL_OS_Windows
//--------------------------------------------------------------------------------------------------
namespace hgl
{
namespace network
{
/**
*
*/
UDPSocket::UDPSocket()
{
ThisSocket=-1;
bind_addr=nullptr;
tar_addr=nullptr;
}
/**
*
*/
UDPSocket::~UDPSocket()
{
CloseSocket();
SAFE_CLEAR(tar_addr);
SAFE_CLEAR(bind_addr);
}
/**
* UDP连接使IP地址和端口
* @param addr
* @return true
* @return false
*/
bool UDPSocket::Create(const IPAddress *addr)
{
if(!addr)RETURN_FALSE;
if(!addr->IsUDP())RETURN_FALSE;
if(!Socket::InitSocket(addr))
RETURN_FALSE;
bind_addr=addr->CreateCopy();
if(!bind_addr->Bind(ThisSocket))
{
hgl::CloseSocket(ThisSocket);
RETURN_FALSE;
}
SetBlock(false);
return(true);
}
// /**
// * 创建一个UDP连接
// */
// bool UDPSocket::Create(int family)
// {
// if(family!=AF_INET&&family!=AF_INET6)RETURN_FALSE;
//
// if((ThisSocket=socket(family,SOCK_DGRAM,IPPROTO_UDP))<0)
// {
// LOG_ERROR(U16_TEXT("创建Socket失败errno:")+UTF16String(GetLastSocketError()));
// RETURN_FALSE;
// }
//
// SetBlock(false);
// return(true);
// }
/**
*
* @param addr
* @return
*/
bool UDPSocket::SetSendAddr(const IPAddress *addr)
{
if(ThisSocket==-1)RETURN_FALSE;
SAFE_CLEAR(tar_addr);
tar_addr=addr->CreateCopy();
{
const int opt = tar_addr->IsBoradcast()?1:0;
if(setsockopt(ThisSocket, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt))==-1)
RETURN_FALSE;
}
return(true);
}
/**
*
* @param data
* @param size
* @return
*/
int UDPSocket::SendPacket(const void *data,int size)
{
#ifdef _DEBUG
if(ThisSocket==-1)
{
LOG_HINT(U16_TEXT("UDPSocket没有调用Create"));
return(-1);
}
#endif//
return(sendto(ThisSocket,(char *)data,size,0,tar_addr->GetSockAddr(),tar_addr->GetSockAddrInSize()));
}
/**
*
* @param addr
* @param data
* @param size
* @return
*/
int UDPSocket::SendPacket(IPAddress *addr,const void *data,int size)
{
#ifdef _DEBUG
if(ThisSocket==-1)
{
LOG_HINT(U16_TEXT("UDPSocket没有调用Create"));
return(-1);
}
#endif//
return(sendto(ThisSocket,(char *)data,size,0,addr->GetSockAddr(),addr->GetSockAddrInSize()));
}
/**
*
* @param buf
* @param size
* @param remote_addr
* @return
*/
int UDPSocket::RecvPacket(void *buf,int size,IPAddress *remote_addr)
{
#ifdef _DEBUG
if(ThisSocket==-1)
{
LOG_HINT(U16_TEXT("UDPSocket没有调用Create"));
return(-1);
}
#endif//
static
#if HGL_OS == HGL_OS_Windows
int
#else
socklen_t
#endif//
sas=remote_addr->GetSockAddrInSize();
return(recvfrom(ThisSocket,(char *)buf,size,0,remote_addr->GetSockAddr(),&sas));
}
}//namespace network
}//namespace hgl

32
src/WebApi_Currency.cpp Normal file
View File

@ -0,0 +1,32 @@
#include<hgl/finance/Currency.h>
#include<hgl/Str.h>
#include<hgl/io/MemoryOutputStream.h>
#include<hgl/network/HTTPTools.h>
namespace hgl
{
namespace finance
{
float GetCurrencyExchangeRate(const char target[4],const char source[4])
{
if(strlen(target)!=3
||strlen(source)!=3)return(0);
char url[]="http://download.finance.yahoo.com/d/quotes.csv?s=******=X&f=l1&e=.csv";
memcpy(url+49,source,3);
memcpy(url+52,target,3);
hgl::io::MemoryOutputStream mos;
if(hgl::network::http::get(&mos,url)<=0)
return 0;
float result;
if(stof((char *)(mos.GetData()),result))
return result;
return 0;
}
}//namespace finance
}//namespace hgl

105
src/WebSocket.cpp Normal file
View File

@ -0,0 +1,105 @@
#include<hgl/Str.h>
#include<hgl/type/BaseString.h>
#include<hgl/io/MemoryOutputStream.h>
#include<hgl/algorithm/Hash.h>
#include<hgl/algorithm/Crypt.h>
namespace hgl
{
namespace network
{
using namespace hgl::algorithm;
/**
* WebSocket信息
* @param data
* @param size
* @return
*/
bool GetWebSocketInfo(UTF8String &sec_websocket_key,UTF8String &sec_websocket_protocol,uint &sec_websocket_version,const char *data,const uint size)
{
constexpr char SEC_WEBSOCKET_KEY[]="Sec-WebSocket-Key: ";
constexpr uint SEC_WEBSOCKET_KEY_SIZE=sizeof(SEC_WEBSOCKET_KEY)-1; //sizeof的带\0所以要-1
constexpr char SEC_WEBSOCKET_PROTOCOL[]="Sec-WebSocket-Protocol: ";
constexpr uint SEC_WEBSOCKET_PROTOCOL_SIZE=sizeof(SEC_WEBSOCKET_PROTOCOL)-1;
constexpr char SEC_WEBSOCKET_VERSION[]="Sec-WebSocket-Version: ";
constexpr uint SEC_WEBSOCKET_VERSION_SIZE=sizeof(SEC_WEBSOCKET_VERSION)-1;
if(!data||size<40)return(false);
const char *end;
{
const char *key=hgl::strstr(data,size,SEC_WEBSOCKET_KEY,SEC_WEBSOCKET_KEY_SIZE);
if(!key)return(false);
key+=SEC_WEBSOCKET_KEY_SIZE;
end=key;
while(*end!='\r')++end;
sec_websocket_key.Set(key,end-key);
}
{
const char *protocol=hgl::strstr(data,size,SEC_WEBSOCKET_PROTOCOL,SEC_WEBSOCKET_PROTOCOL_SIZE);
if(protocol) //也有可能是不存在的
{
protocol+=SEC_WEBSOCKET_PROTOCOL_SIZE;
end=protocol;
while(*end!='\r')++end;
sec_websocket_protocol.Set(protocol,end-protocol);
}
}
{
const char *version=hgl::strstr(data,size,SEC_WEBSOCKET_VERSION,SEC_WEBSOCKET_VERSION_SIZE);
if(version)
{
version+=SEC_WEBSOCKET_VERSION_SIZE;
end=version;
while(*end!='\r')++end;
hgl::stou(version,sec_websocket_version);
}
}
return(true);
}
/**
* WebSocket回复头
* @param result
*/
void MakeWebSocketAccept(UTF8String &result,const UTF8String &sec_websocket_key,const UTF8String &sec_websocket_protocol)
{
const UTF8String key_mask=sec_websocket_key+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
HashCodeSHA1 hc;
CountSHA1(key_mask.c_str(),key_mask.Length(),hc);
io::MemoryOutputStream mos;
base64_encode(&mos,hc.code,hc.size());
const UTF8String sec_websocket_accept((char *)mos.GetData(),mos.GetSize());
result="HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: "+sec_websocket_accept;
if(!sec_websocket_protocol.IsEmpty())
result+="\r\nSec-WebSocket-Protocol: "+sec_websocket_protocol;
result+="\r\n\r\n";
}
}//namespace network
}//namespace hgl

352
src/WebSocketAccept.cpp Normal file
View File

@ -0,0 +1,352 @@
#include<hgl/network/WebSocketAccept.h>
#include<hgl/network/WebSocket.h>
#include<hgl/network/SocketInputStream.h>
#include<hgl/network/SocketOutputStream.h>
#include<hgl/LogInfo.h>
namespace hgl
{
namespace network
{
//参考工程: https://github.com/katzarsky/WebSocket
WebSocketAccept::WebSocketAccept():TCPAccept(),recv_buffer(HGL_TCP_BUFFER_SIZE)
{
}
WebSocketAccept::WebSocketAccept(int s,IPAddress *ip):TCPAccept(s,ip),recv_buffer(HGL_TCP_BUFFER_SIZE)
{
}
void WebSocketAccept::WebSocketHandshake()
{
constexpr char HTTP_HEADER_END_STR[4]={'\r','\n','\r','\n'}; //别用"\r\n\r\n"不然sizeof会得出来5
constexpr int HTTP_HEADER_END_SIZE=sizeof(HTTP_HEADER_END_STR);
MemBlock<char> ws_header(1024);
int pos=0;
int total=0;
int size=0;
const char *end;
while(true)
{
size=sis->Read(ws_header.data()+pos,1024);
if(size==0)continue;
if(size<0)
{
LOG_ERROR(OS_TEXT("WebSocketAccept::WebSocketHandshake() read data error"));
break;
}
recv_total+=size;
pos+=size;
end=hgl::strrstr<const char>(ws_header.data(),pos,HTTP_HEADER_END_STR,HTTP_HEADER_END_SIZE);
if(!end)
continue;
end+=HTTP_HEADER_END_SIZE;
total=end-ws_header.data();
UTF8String key;
UTF8String ws_protocol;
uint ws_version;
UTF8String ws_accept_protocol;
if(GetWebSocketInfo(key,ws_protocol,ws_version,ws_header.data(),total))
if(OnHandshake(ws_accept_protocol,ws_protocol,ws_version))
{
UTF8String ws_return;
MakeWebSocketAccept(ws_return,key,ws_accept_protocol);
if(Send(ws_return.c_str(),ws_return.Length()))
{
size=pos-total;
if(size>0)
memcpy(recv_buffer.data(),end,size);
recv_length=size;
return;
}
}
break;
}
CloseSocket();
}
/**
* socket接收数据回调函数<br>
*/
int WebSocketAccept::OnSocketRecv(int /*size*/)
{
int total=0;
if(!sis)
{
sis=new SocketInputStream(ThisSocket);
recv_total=0;
recv_length=0;
WebSocketHandshake();
total+=recv_total;
}
while(true)
{
if(recv_length==0)
{
msg_header_size=2; //最小头2字节
msg_full_length=0;
msg_length=0;
msg_opcode=0;
msg_fin=0;
msg_masked=0;
}
if(recv_length<msg_header_size) //头都没收完
{
int result=sis->Read(recv_buffer.data()+recv_length,msg_header_size-recv_length);
if(result<0)
RETURN_ERROR(result);
if(result==0)
return(total);
recv_length+=result;
recv_total+=result;
total+=result;
}
if(recv_length<msg_header_size) //已经有头了
continue;
uint8 *p=recv_buffer.data();
msg_opcode =p[0]&0x7;
if(msg_opcode==8) //close
{
this->CloseSocket();
return(-1);
}
msg_fin =(p[0]>>7)&0x1;
msg_masked =(p[1]>>7)&0x1;
uint length_field=p[1]&0x7F;
msg_header_size=2;
if(length_field<=125)
{
msg_length=length_field;
}
else
if(length_field==126) //16 bit msg_length
{
msg_header_size+=2;
if(recv_length<msg_header_size)
return(total);
msg_length=ntohs(*(uint16 *)(p+2));
}
else
if(length_field==127) //64 bit msg_length
{
msg_header_size+=8;
if(recv_length<msg_header_size)
return(total);
msg_length=ntohl(*(uint32 *)(p+2));
}
msg_full_length=msg_length;
if(msg_masked)
msg_full_length+=4;
recv_buffer.SetLength(msg_full_length);
int result=sis->Read(recv_buffer.data()+recv_length,msg_full_length-(recv_length-msg_header_size));
if(result<0)
RETURN_ERROR(result);
if(result==0)
return total;
recv_length+=result;
recv_total+=result;
total+=result;
if(recv_length<msg_full_length+msg_header_size) //这个包还没收完整
return(total); //证明socket缓冲区里没有数据了直接返回
//收完了
char *pack;
p+=msg_header_size;
if(msg_masked)
{
uint32 mask=*(uint32 *)p;
p+=4;
pack=(char *)p;
for(uint i=0;i<msg_length;i++)
{
*p=(*p)^((uchar *)(&mask))[i%4];
++p;
}
}
else
{
pack=(char *)p;
}
if(msg_opcode==0xA)OnPong();else
if(msg_opcode==0x9)OnPing();else
if(msg_opcode>=3
&&msg_opcode<=7)
{
}
else
if(msg_opcode==2)
{
if(msg_length>0)
{
#ifdef _DEBUG
data_out_str.SetLength(msg_length*3);
DataToLowerHexStr(data_out_str.data(),(uint8 *)pack,msg_length,',');
LOG_INFO(U8_TEXT("WebSocket[")+UTF8String(ThisSocket)+U8_TEXT("] Recv binary [")+UTF8String(msg_length)+U8_TEXT("]: ")+UTF8String(data_out_str.data()));
#endif//_DEBUG
OnBinary(pack,msg_length,msg_fin);
}
if(!msg_fin)
last_opcode=2;
else
last_opcode=0;
}
else
if(msg_opcode==1){if(msg_length>0)OnText(pack,msg_length,msg_fin);if(!msg_fin)last_opcode=2;else last_opcode=0;}else
if(msg_opcode==0)
{
if(msg_length>0)
{
if(last_opcode==1)
OnText(pack,msg_length,msg_fin);
else
if(last_opcode==2)
OnBinary(pack,msg_length,msg_fin);
}
}
else
{
LOG_PROBLEM(OS_TEXT("WebSocketAccept,opcode error,opcode:")+OSString(msg_opcode)+OS_TEXT(",length:")+OSString(msg_length));
OnError();
}
recv_buffer.ClearData();
recv_length=0;
}//while
}
int WebSocketAccept::SendFrame(uint8 opcode,void *msg,uint32 size,bool fin)
{
uint8 header[14];
uint header_size;
header[0]=opcode&0xF;
if(fin)
header[0]|=1<<7;
if(size<=125)
{
header[1]=size;
header_size=2;
}
else
if(size<=65535)
{
header[1]=126;
header[2]=(size&0xFF00)>>8;
header[3]= size&0xFF;
header_size=4;
}
else
{
header[1]=127;
header[2]=0;
header[3]=0;
header[4]=0;
header[5]=0;
header[6]=(size&0xFF000000)>>24;
header[7]=(size&0xFF0000)>>16;
header[8]=(size&0xFF00)>>8;
header[9]= size&0xFF;
header_size=10;
}
if(!sos)
sos=new SocketOutputStream(ThisSocket);
if(sos->WriteFully(header,header_size)!=header_size)
return(-1);
if(size>0)
if(sos->WriteFully(msg,size)!=size)
return(-1);
return header_size+size;
}
bool WebSocketAccept::SendPing()
{
return SendFrame(0x9,nullptr,0,true)>0;
}
bool WebSocketAccept::SendPong()
{
return SendFrame(0xA,nullptr,0,true)>0;
}
bool WebSocketAccept::SendBinary(void *data,uint32 size,bool fin)
{
#ifdef _DEBUG
data_out_str.SetLength(size*3);
DataToLowerHexStr(data_out_str.data(),(uint8 *)data,size,',');
LOG_INFO(U8_TEXT("WebSocket[")+UTF8String(ThisSocket)+U8_TEXT("] Send binary [")+UTF8String(size)+U8_TEXT("]: ")+UTF8String(data_out_str.data()));
#endif//_DEBUG
return SendFrame(0x2,data,size,fin)>0;
}
bool WebSocketAccept::SendText(void *text,uint32 size,bool fin)
{
return SendFrame(0x1,text,size,fin)>0;
}
}//namespace network
}//namespace hgl

68
src/WebapiUserAgent.cpp Normal file
View File

@ -0,0 +1,68 @@
#include<hgl/webapi/UserAgentString.h>
namespace hgl
{
namespace webapi
{
UTF8String FirefoxUserAgent(FirefoxUserAgentConfig &cfg)
{
UTF8String agent="Mozilla/5.0 ";
if(cfg.os>=OS_WindowsX86
&&cfg.os<=OS_LinuxX86_64)
{
if(cfg.os>=OS_WindowsX86
&&cfg.os<=OS_WindowsWOW64)
{
agent+="(Windows NT "+UTF8String(cfg.os_ver.major)+"."+UTF8String(cfg.os_ver.minor)+"; ";
if(cfg.os==OS_WindowsAMD64)agent+="Win64; x64; ";else
if(cfg.os==OS_WindowsWOW64)agent+="WOW64; ";
}
else
if(cfg.os==OS_macOS)
agent+="(Macintosh; Intel Mac OS X "+UTF8String(cfg.os_ver.major)+"."+UTF8String(cfg.os_ver.minor)+"; ";
else
if(cfg.os==OS_Linuxi686)
agent+="(X11; Linux i686; ";
else
if(cfg.os==OS_LinuxX86_64)
agent+="(X11; Linux x86_64; ";
agent+="rv:"+UTF8String(cfg.ff_ver.major)+"."+UTF8String(cfg.ff_ver.minor)+") Gecko/"+UTF8String(cfg.gecko_version)+" Firefox/"
+UTF8String(cfg.ff_ver.major)+"."+UTF8String(cfg.ff_ver.minor);
}
else
if(cfg.os>=OS_iPod
&&cfg.os<=OS_iPad)
{
if(cfg.os==OS_iPod) agent+="(iPod touch; ";else
if(cfg.os==OS_iPad) agent+="(iPad; ";else
agent+="(iPhone; ";
agent+= "CPU iPhone OS "+UTF8String(cfg.os_ver.major)+"_"+UTF8String(cfg.os_ver.minor)+" like Mac OS X) "+
"AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4";
}
else
if(cfg.os>=OS_AndroidPhone
&&cfg.os<=OS_AndroidTV)
{
agent+="(Android "+UTF8String(cfg.os_ver.major)+"."+UTF8String(cfg.os_ver.minor)+"; ";
if(cfg.os==OS_AndroidPhone )agent+="Mobile; ";
if(cfg.os==OS_AndroidTablet )agent+="Tablet; ";
if(cfg.os==OS_AndroidTV )agent+="TV; ";
agent+="rv:"+UTF8String(cfg.ff_ver.major)+"."+UTF8String(cfg.ff_ver.minor)+") Gecko/"
+UTF8String(cfg.ff_ver.major)+"."+UTF8String(cfg.ff_ver.minor)+" Firefox/"
+UTF8String(cfg.ff_ver.major)+"."+UTF8String(cfg.ff_ver.minor);
}
else
{
agent+="Firefox/"+UTF8String(cfg.ff_ver.major)+"."+UTF8String(cfg.ff_ver.minor);
}
return agent;
}
}//namespace webapi
}//namespace hgl

721
src/WinFireWall.cpp Normal file
View File

@ -0,0 +1,721 @@
#include<hgl/network/WinFireWall.h>
#include<hgl/type/BaseString.h>
#include<netfw.h>
namespace hgl
{
namespace network
{
WinFireWall::WinFireWall(void)
{
CoInitialize( NULL );
m_pFireWallProfile = NULL;
}
WinFireWall::~WinFireWall(void)
{
Close();
CoUninitialize();
}
/**
* Windows防火墙访问
* @return FW_NOERROR
*/
FW_ERROR_CODE WinFireWall::Init()
{
HRESULT hr = S_FALSE;
INetFwMgr* fwMgr = NULL;
INetFwPolicy* fwPolicy = NULL;
FW_ERROR_CODE ret = FW_NOERROR;
try
{
if( m_pFireWallProfile )
throw FW_ERR_INITIALIZED;
// Create an instance of the firewall settings manager.
hr = CoCreateInstance( __uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof( INetFwMgr), (void**)&fwMgr );
if( FAILED( hr ))
throw FW_ERR_CREATE_SETTING_MANAGER;
// Retrieve the local firewall policy.
hr = fwMgr->get_LocalPolicy( &fwPolicy );
if( FAILED( hr ))
throw FW_ERR_LOCAL_POLICY;
// Retrieve the firewall profile currently in effect
hr = fwPolicy->get_CurrentProfile( &m_pFireWallProfile );
if( FAILED( hr ))
throw FW_ERR_PROFILE;
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
if( fwPolicy )
fwPolicy->Release();
if( fwMgr )
fwMgr->Release();
return ret;
}
/**
* Windows防火墙访问
*/
FW_ERROR_CODE WinFireWall::Close()
{
// Release the firewall profile
if( m_pFireWallProfile )
{
m_pFireWallProfile->Release();
m_pFireWallProfile = NULL;
}
return FW_NOERROR;
}
/**
*
* @param bOn
* @return FW_NOERROR
*/
FW_ERROR_CODE WinFireWall::CheckFirewall( bool& bOn )
{
HRESULT hr;
VARIANT_BOOL bFWEnabled;
bOn = FALSE;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
hr = m_pFireWallProfile->get_FirewallEnabled( &bFWEnabled );
if( FAILED(hr))
throw FW_ERR_FIREWALL_IS_ENABLED;
if( bFWEnabled != VARIANT_FALSE )
bOn = TRUE;
}
catch( FW_ERROR_CODE nError )
{
return nError;
}
return FW_NOERROR;
}
/**
* Windows防火墙
* @return FW_NOERROR
*/
FW_ERROR_CODE WinFireWall::OpenFirewall()
{
HRESULT hr;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
// Check whether the firewall is off
bool bFWOn;
FW_ERROR_CODE ret = CheckFirewall( bFWOn );
if( ret != FW_NOERROR )
throw ret;
// If it is off now, turn it on
if( !bFWOn )
{
hr = m_pFireWallProfile->put_FirewallEnabled( VARIANT_TRUE );
if( FAILED( hr ))
throw FW_ERR_FIREWALL_ENABLED;
}
}
catch( FW_ERROR_CODE nError )
{
return nError;
}
return FW_NOERROR;
}
/**
* Windows防火墙
* @return FW_NOERROR
*/
FW_ERROR_CODE WinFireWall::CloseFirewall()
{
HRESULT hr;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
// Check whether the firewall is off
bool bFWOn;
FW_ERROR_CODE ret = CheckFirewall( bFWOn );
if( ret != FW_NOERROR )
throw ret;
// If it is on now, turn it off
if( bFWOn )
{
hr = m_pFireWallProfile->put_FirewallEnabled( VARIANT_FALSE );
if( FAILED( hr ))
throw FW_ERR_FIREWALL_ENABLED;
}
}
catch( FW_ERROR_CODE nError )
{
return nError;
}
return FW_NOERROR;
}
/**
* Windows防火墙中的设置
* @param lpszProcessImageFileName ()
* @param bEnable
* @return FW_NOERROR
*/
FW_ERROR_CODE WinFireWall::CheckApplication( const wchar_t* lpszProcessImageFileName, bool& bEnable )
{
FW_ERROR_CODE ret = FW_NOERROR;
HRESULT hr;
// BSTR bstrFWProcessImageFileName = NULL;
UTF16String bstrFWProcessImageFileName;
VARIANT_BOOL bFWEnabled;
INetFwAuthorizedApplication* pFWApp = NULL;
INetFwAuthorizedApplications* pFWApps = NULL;
bEnable = FALSE;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
if( lpszProcessImageFileName == NULL )
throw FW_ERR_INVALID_ARG;
hr = m_pFireWallProfile->get_AuthorizedApplications( &pFWApps );
if( FAILED( hr ))
throw FW_ERR_AUTH_APPLICATIONS;
// Allocate a BSTR for the process image file name
//bstrFWProcessImageFileName = SysAllocString( lpszProcessImageFileName );
bstrFWProcessImageFileName = lpszProcessImageFileName;
//if( SysStringLen( bstrFWProcessImageFileName ) == 0)
if(bstrFWProcessImageFileName.Length()==0)
throw FW_ERR_SYS_ALLOC_STRING;
hr = pFWApps->Item( bstrFWProcessImageFileName.c_str(), &pFWApp);
// If FAILED, the appliacation is not in the collection list
if( SUCCEEDED( hr ))
{
// Find out if the authorized application is enabled
hr = pFWApp->get_Enabled( &bFWEnabled );
if( FAILED( hr ))
throw FW_ERR_APP_ENABLED;
if( bFWEnabled == VARIANT_TRUE )
bEnable = TRUE;
}
}
catch( FW_ERROR_CODE nError )
{
ret = nError;
}
// Free the BSTR
//SysFreeString( bstrFWProcessImageFileName );
// Release memories to retrieve the information of the application
if( pFWApp )
pFWApp->Release();
if( pFWApps )
pFWApps->Release();
return ret;
}
/**
* Windows防火墙可通信名单
* @param lpszProcessImageFileName ()
* @param lpszRegisterName Windows防火墙名单中的程序名称
* @return FW_NOERROR
*/
FW_ERROR_CODE WinFireWall::AddApplication( const wchar_t* lpszProcessImageFileName, const wchar_t* lpszRegisterName )
{
FW_ERROR_CODE ret = FW_NOERROR;
HRESULT hr;
bool bAppEnable;
//BSTR bstrProcessImageFileName = NULL;
UTF16String bstrProcessImageFileName;
//BSTR bstrRegisterName = NULL;
UTF16String bstrRegisterName;
INetFwAuthorizedApplication* pFWApp = NULL;
INetFwAuthorizedApplications* pFWApps = NULL;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
if( lpszProcessImageFileName == NULL || lpszRegisterName == NULL )
throw FW_ERR_INVALID_ARG;
// First of all, check the application is already authorized;
FW_ERROR_CODE nError = this->CheckApplication( lpszProcessImageFileName, bAppEnable );
if( nError != FW_NOERROR )
throw nError;
// Only add the application if it isn't authorized
if( bAppEnable == FALSE )
{
// Retrieve the authorized application collection
hr = m_pFireWallProfile->get_AuthorizedApplications( &pFWApps );
if( FAILED( hr ))
throw FW_ERR_AUTH_APPLICATIONS;
// Create an instance of an authorized application
hr = CoCreateInstance( __uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), (void**)&pFWApp);
if( FAILED( hr ))
throw FW_ERR_CREATE_APP_INSTANCE;
// Allocate a BSTR for the Process Image FileName
//bstrProcessImageFileName = SysAllocString( lpszProcessImageFileName );
bstrProcessImageFileName = lpszProcessImageFileName;
//if( SysStringLen( bstrProcessImageFileName ) == 0)
if (bstrProcessImageFileName.Length() == 0)
throw FW_ERR_SYS_ALLOC_STRING;
// Set the process image file name
hr = pFWApp->put_ProcessImageFileName( bstrProcessImageFileName.c_str() );
if( FAILED( hr ) )
throw FW_ERR_PUT_PROCESS_IMAGE_NAME;
// Allocate a BSTR for register name
//bstrRegisterName = SysAllocString( lpszRegisterName );
bstrRegisterName = lpszRegisterName;
//if( SysStringLen( bstrRegisterName ) == 0)
if (bstrRegisterName.Length() == 0)
throw FW_ERR_SYS_ALLOC_STRING;
// Set a registered name of the process
hr = pFWApp->put_Name( bstrRegisterName.c_str() );
if( FAILED( hr ))
throw FW_ERR_PUT_REGISTER_NAME;
// Add the application to the collection
hr = pFWApps->Add( pFWApp );
if( FAILED( hr ))
throw FW_ERR_ADD_TO_COLLECTION;
}
}
catch( FW_ERROR_CODE nError )
{
ret = nError;
}
//SysFreeString( bstrProcessImageFileName );
//SysFreeString( bstrRegisterName );
if( pFWApp )
pFWApp->Release();
if( pFWApps )
pFWApps->Release();
return ret;
}
/**
* Windows防火墙可通信名单中移除
* @param lpszProcessImageFileName ()
* @return FW_NOERROR
*/
FW_ERROR_CODE WinFireWall::RemoveApplication( const wchar_t* lpszProcessImageFileName )
{
FW_ERROR_CODE ret = FW_NOERROR;
HRESULT hr;
bool bAppEnable;
//BSTR bstrProcessImageFileName = NULL;
UTF16String bstrProcessImageFileName;
INetFwAuthorizedApplications* pFWApps = NULL;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
if( lpszProcessImageFileName == NULL )
throw FW_ERR_INVALID_ARG;
FW_ERROR_CODE nError = this->CheckApplication( lpszProcessImageFileName, bAppEnable );
if( nError != FW_NOERROR )
throw nError;
// Only remove the application if it is authorized
if( bAppEnable == TRUE )
{
// Retrieve the authorized application collection
hr = m_pFireWallProfile->get_AuthorizedApplications( &pFWApps );
if( FAILED( hr ))
throw FW_ERR_AUTH_APPLICATIONS;
// Allocate a BSTR for the Process Image FileName
//bstrProcessImageFileName = SysAllocString( lpszProcessImageFileName );
bstrProcessImageFileName = lpszProcessImageFileName;
//if( SysStringLen( bstrProcessImageFileName ) == 0)
if (bstrProcessImageFileName.Length() == 0)
throw FW_ERR_SYS_ALLOC_STRING;
hr = pFWApps->Remove( bstrProcessImageFileName.c_str() );
if( FAILED( hr ))
throw FW_ERR_REMOVE_FROM_COLLECTION;
}
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
//SysFreeString( bstrProcessImageFileName);
if( pFWApps )
pFWApps->Release();
return ret;
}
/**
*
* @param lPortNumber
* @param ipProtocol (ANY:TCPUDP )
* @param bEnable
* @return FW_NOERROR
*/
FW_ERROR_CODE WinFireWall::CheckPort( unsigned int lPortNumber, PROTOCOL ipProtocol, bool& bEnable )
{
FW_ERROR_CODE ret = FW_NOERROR;
VARIANT_BOOL bFWEnabled;
INetFwOpenPort* pFWOpenPort = NULL;
INetFwOpenPorts* pFWOpenPorts = NULL;
HRESULT hr;
bEnable = FALSE;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
// Retrieve the open ports collection
hr = m_pFireWallProfile->get_GloballyOpenPorts( &pFWOpenPorts );
if( FAILED( hr ))
throw FW_ERR_GLOBAL_OPEN_PORTS;
// Get the open port
hr = pFWOpenPorts->Item( lPortNumber, (NET_FW_IP_PROTOCOL)ipProtocol, &pFWOpenPort );
if( SUCCEEDED( hr ))
{
hr = pFWOpenPort->get_Enabled( &bFWEnabled );
if( FAILED( hr ))
throw FW_ERR_PORT_IS_ENABLED;
if( bFWEnabled == VARIANT_TRUE )
bEnable = TRUE;
}
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
if( pFWOpenPort )
pFWOpenPort->Release();
if( pFWOpenPorts )
pFWOpenPorts->Release();
return ret;
}
/**
* Windows防火墙允许通信名单中
* @param lPortNumber
* @param ipProtocol (ANY:TCPUDP )
* @param lpszRegisterName Windows防火墙名单中所显示的名称
* @return FW_NOERROR
*/
FW_ERROR_CODE WinFireWall::OpenPort( unsigned int lPortNumber, PROTOCOL ipProtocol, const wchar_t* lpszRegisterName )
{
FW_ERROR_CODE ret = FW_NOERROR;
INetFwOpenPort* pFWOpenPort = NULL;
INetFwOpenPorts* pFWOpenPorts = NULL;
//BSTR bstrRegisterName = NULL;
UTF16String bstrRegisterName;
HRESULT hr;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
bool bEnablePort;
FW_ERROR_CODE nError = CheckPort( lPortNumber, ipProtocol, bEnablePort);
if( nError != FW_NOERROR)
throw nError;
// Only add the port, if it isn't added to the collection
if( bEnablePort == FALSE )
{
// Retrieve the collection of globally open ports
hr = m_pFireWallProfile->get_GloballyOpenPorts( &pFWOpenPorts );
if( FAILED( hr ))
throw FW_ERR_GLOBAL_OPEN_PORTS;
// Create an instance of an open port
hr = CoCreateInstance( __uuidof(NetFwOpenPort), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwOpenPort), (void**)&pFWOpenPort);
if( FAILED( hr ))
throw FW_ERR_CREATE_PORT_INSTANCE;
// Set the port number
hr = pFWOpenPort->put_Port( lPortNumber );
if( FAILED( hr ))
throw FW_ERR_SET_PORT_NUMBER;
// Set the IP Protocol
hr = pFWOpenPort->put_Protocol( (NET_FW_IP_PROTOCOL)ipProtocol );
if( FAILED( hr ))
throw FW_ERR_SET_IP_PROTOCOL;
//bstrRegisterName = SysAllocString( lpszRegisterName );
bstrRegisterName = lpszRegisterName;
//if( SysStringLen( bstrRegisterName ) == 0)
if (bstrRegisterName.Length() == 0)
throw FW_ERR_SYS_ALLOC_STRING;
// Set the registered name
hr = pFWOpenPort->put_Name( bstrRegisterName.c_str() );
if( FAILED( hr ))
throw FW_ERR_PUT_REGISTER_NAME;
hr = pFWOpenPorts->Add( pFWOpenPort );
if( FAILED( hr ))
throw FW_ERR_ADD_TO_COLLECTION;
}
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
//SysFreeString( bstrRegisterName );
if( pFWOpenPort )
pFWOpenPort->Release();
if( pFWOpenPorts )
pFWOpenPorts->Release();
return ret;
}
/**
* Windows防火墙允许通信名单中移除
* @param lPortNumber
* @param ipProtocol (ANY:TCPUDP )
* @return FW_NOERROR
*/
FW_ERROR_CODE WinFireWall::ClosePort( unsigned int lPortNumber, PROTOCOL ipProtocol )
{
FW_ERROR_CODE ret = FW_NOERROR;
INetFwOpenPorts* pFWOpenPorts = NULL;
HRESULT hr;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
bool bEnablePort;
FW_ERROR_CODE nError = CheckPort( lPortNumber, ipProtocol, bEnablePort);
if( nError != FW_NOERROR)
throw nError;
// Only remove the port, if it is on the collection
if( bEnablePort == TRUE )
{
// Retrieve the collection of globally open ports
hr = m_pFireWallProfile->get_GloballyOpenPorts( &pFWOpenPorts );
if( FAILED( hr ))
throw FW_ERR_GLOBAL_OPEN_PORTS;
hr = pFWOpenPorts->Remove( lPortNumber, (NET_FW_IP_PROTOCOL)ipProtocol );
if (FAILED( hr ))
throw FW_ERR_REMOVE_FROM_COLLECTION;
}
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
if( pFWOpenPorts )
pFWOpenPorts->Release();
return ret;
}
FW_ERROR_CODE WinFireWall::IsExceptionNotAllowed( bool& bNotAllowed )
{
FW_ERROR_CODE ret = FW_NOERROR;
bNotAllowed = TRUE;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
VARIANT_BOOL bExNotAllowed;
HRESULT hr = m_pFireWallProfile->get_ExceptionsNotAllowed( &bExNotAllowed );
if( FAILED( hr ))
throw FW_ERR_EXCEPTION_NOT_ALLOWED;
if( bExNotAllowed == VARIANT_TRUE )
bNotAllowed = TRUE;
else
bNotAllowed = FALSE;
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
return ret;
}
FW_ERROR_CODE WinFireWall::SetExceptionNotAllowed( bool bNotAllowed )
{
FW_ERROR_CODE ret = FW_NOERROR;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
HRESULT hr = m_pFireWallProfile->put_ExceptionsNotAllowed( bNotAllowed ? VARIANT_TRUE : VARIANT_FALSE );
if( FAILED( hr ))
throw FW_ERR_EXCEPTION_NOT_ALLOWED;
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
return ret;
}
FW_ERROR_CODE WinFireWall::IsNotificationDiabled( bool& bDisabled )
{
FW_ERROR_CODE ret = FW_NOERROR;
bDisabled = FALSE;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
VARIANT_BOOL bNotifyDisable;
HRESULT hr = m_pFireWallProfile->get_NotificationsDisabled( &bNotifyDisable );
if( FAILED( hr ))
throw FW_ERR_NOTIFICATION_DISABLED;
if( bNotifyDisable == VARIANT_TRUE )
bDisabled = TRUE;
else
bDisabled = FALSE;
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
return ret;
}
FW_ERROR_CODE WinFireWall::SetNotificationDiabled( bool bDisabled )
{
FW_ERROR_CODE ret = FW_NOERROR;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
HRESULT hr = m_pFireWallProfile->put_NotificationsDisabled( bDisabled ? VARIANT_TRUE : VARIANT_FALSE );
if( FAILED( hr ))
throw FW_ERR_NOTIFICATION_DISABLED;
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
return ret;
}
FW_ERROR_CODE WinFireWall::IsUnicastResponsesToMulticastBroadcastDisabled( bool& bDisabled )
{
FW_ERROR_CODE ret = FW_NOERROR;
bDisabled = FALSE;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
VARIANT_BOOL bUniMultiDisabled;
HRESULT hr = m_pFireWallProfile->get_UnicastResponsesToMulticastBroadcastDisabled( &bUniMultiDisabled );
if( FAILED( hr ))
throw FW_ERR_UNICAST_MULTICAST;
if( bUniMultiDisabled == VARIANT_TRUE )
bDisabled = TRUE;
else
bDisabled = FALSE;
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
return ret;
}
FW_ERROR_CODE WinFireWall::SetUnicastResponsesToMulticastBroadcastDisabled( bool bDisabled )
{
FW_ERROR_CODE ret = FW_NOERROR;
try
{
if( m_pFireWallProfile == NULL )
throw FW_ERR_INITIALIZED;
HRESULT hr = m_pFireWallProfile->put_UnicastResponsesToMulticastBroadcastDisabled( bDisabled ? VARIANT_TRUE : VARIANT_FALSE );
if( FAILED( hr ))
throw FW_ERR_UNICAST_MULTICAST;
}
catch( FW_ERROR_CODE nError)
{
ret = nError;
}
return ret;
}
}//namespace network
}//namespace hgl