代码拉取完成,页面将自动刷新
/*-------------------------------------------------------------------------
FileName : socket.h
Description : 异步socket相关操作实现
remark :
Modification :
--------------------------------------------------------------------------
1、Date 2015-11-05 create hejl
-------------------------------------------------------------------------*/
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include "Socket.h"
#include "HoComm.h" // deps ERRLOG_IF1BRK macro
// 默认返回noblock sockfd
int Socket::create_fd(const char* ip, int port, bool udp, bool v6)
{
const char* ipaddr = ip;
int s = -1;
int ret = 0;
do
{
int reuseaddr = 1;
if (v6)
{
struct sockaddr_in6 ip6addr;
bzero(&ip6addr, sizeof(ip6addr));
ip6addr.sin6_family = AF_INET6;
ip6addr.sin6_port = htons(port);
if (NULL==ip || 0==*ip) // 任意本地接口
{
ip6addr.sin6_addr = in6addr_any;
}
else
{
ret = inet_pton(AF_INET6, ipaddr, &ip6addr.sin6_addr);
ERRLOG_IF1BRK(ret<=0, ret, "INET_PTON| ret=%d| err=%s| ipaddr=%s",
ret, strerror(errno), ip);
}
s = socket(AF_INET6, (udp? SOCK_DGRAM: SOCK_STREAM), 0);
ERRLOG_IF1BRK(s<0, s, "SOCKET| s=%d| err=%s| ipaddr=%s",
s, strerror(errno), ip);
if ( -1 == setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(const void *) &reuseaddr, sizeof(int)) )
{
ret = errno;
perror("LISTEN| msg=reuse addr fail");
//LOGERROR("LISTEN| msg=reuse addr fail| err(%d)=%s", ret, strerror(ret));
break;
}
ret = bind(s, (struct sockaddr*)&ip6addr, sizeof(ip6addr));
ERRLOG_IF1BRK(ret, s, "SOCKBIND| err(%d)=%s", errno, strerror(errno));
}
else
{
struct sockaddr_in ip4addr;
bzero(&ip4addr, sizeof(ip4addr));
ip4addr.sin_family = AF_INET;
ip4addr.sin_port = htons(port);
if (NULL==ip || 0==*ip) // 任意本地接口
{
ip4addr.sin_addr.s_addr = INADDR_ANY;
}
else
{
ret = inet_pton(PF_INET, ipaddr, (void*)&ip4addr.sin_addr.s_addr);
ERRLOG_IF1BRK(ret<=0, ret, "INET_PTON| ret=%d| err=%s| ipaddr=%s",
ret, strerror(errno), ip);
}
s = socket(AF_INET, (udp? SOCK_DGRAM: SOCK_STREAM), 0);
ERRLOG_IF1BRK(s<0, s, "SOCKET| s=%d| err=%s| ipaddr=%s",
s, strerror(errno), ip);
if ( -1 == setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(const void *) &reuseaddr, sizeof(int)) )
{
ret = errno;
perror("LISTEN| msg=reuse addr fail");
//LOGERROR("LISTEN| msg=reuse addr fail| err(%d)=%s", ret, strerror(ret));
break;
}
ret = bind(s, (struct sockaddr*)&ip4addr, sizeof(struct sockaddr));
ERRLOG_IF1BRK(ret, s, "SOCKBIND| err(%d)=%s", errno, strerror(errno));
}
if (!udp)
{
ret = listen(s, LISTEN_BACKLOG);
ERRLOG_IF1BRK(ret, s, "LISTEN| s=%d| err=%s| ipaddr=%s",
s, strerror(errno), ip);
sock_nonblock(s);
}
}
while (false);
if (ret && -1 != s)
{
close(s);
s = -1;
}
return s;
}
template<bool TPeer>
string Socket::_getName_(int fd, bool hasport /*= false*/, bool v6 /*= false*/)
{
int result, ret = 0;
socklen_t addr_len;
string name;
do
{
if (v6)
{
struct sockaddr_in6 addr6;
addr_len = sizeof(addr6);
ret = TPeer? getpeername(fd, (sockaddr*)&addr6, &addr_len) : getsockname(fd, (sockaddr*)&addr6, &addr_len);
ERRLOG_IF1BRK(ret, ret, "SOCKNAME| err(%d)=%s", errno, strerror(errno));
sock6_ntop(straddr, addr6);
name = straddr;
if (hasport)
{
char strport[16] = {0};
snprintf(strport, sizeof(strport), ":%d", (int)sock6_port(addr6));
name += strport;
}
}
else
{
struct sockaddr_in addr4;
addr_len = sizeof(addr4);
result = TPeer? getpeername(fd, (sockaddr*)&addr4, &addr_len) : getsockname(fd, (sockaddr*)&addr4, &addr_len);
ERRLOG_IF1BRK(result, result, "SOCKNAME| err(%d)=%s", errno, strerror(errno));
sock4_ntop(straddr, addr4);
name = straddr;
if (hasport)
{
char strport[16] = {0};
snprintf(strport, sizeof(strport), ":%d", (int)sock4_port(addr4));
name += strport;
}
}
ret = 0;
}
while(false);
return name;
}
// summery: 判别传入地址的类型
// return: -1 无效; 0 ipv4地址;1 ipv6地址; 2 域名
int Socket::addr_type(const char* addr)
{
if (NULL == addr) return -1;
int num_cnt = 0;
int dot_cnt = 0;
int char_cnt1 = 0;
int char_cnt2 = 0;
int colon_cnt = 0;
for (int i = 0; addr[i]; ++i)
{
char ch = addr[i];
if (ch >= '0' && ch <= '9')num_cnt++;
else if ('.' == ch)dot_cnt++;
else if ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))char_cnt1++;
else if ((ch > 'f' && ch <= 'z') || (ch > 'F' && ch <= 'Z'))char_cnt2++;
else if (':' == ch)colon_cnt++;
else return -1;
}
if (3 == dot_cnt && num_cnt > 3 && 0 == (char_cnt1+char_cnt2+colon_cnt)) return 0;
if (colon_cnt > 0 && (num_cnt + char_cnt1) > 0 && 0 == (char_cnt2 + dot_cnt)) return 1;
if (0 == colon_cnt && char_cnt1 + char_cnt2 + num_cnt > 0) return 2;
return -1;
}
// param: addrHost [in/out] 输入主机地址,输出对应IP
// remark: 如果输入IP,则原样返回
// return: -1 无效;-2 dns解析失败; 0 ipv4地址;1 ipv6地址;
int Socket::host2Ip(string& addrHost)
{
int ret = addr_type(addrHost.c_str());
if (2 == ret) // 域名解析
{
struct hostent* hst = gethostbyname(addrHost.c_str());
if (NULL == hst || NULL == hst->h_addr_list[0]) return -2;
ret = (AF_INET6 == hst->h_addrtype)? 1: 0;
char buff[64] = {0};
const char* rntop = inet_ntop(AF_INET, hst->h_addr_list[0], buff, sizeof(buff));
if (rntop)
{
addrHost = rntop;
}
else
{
ret = -2;
}
}
return ret;
}
string Socket::sock_name(int fd, bool hasport /*= false*/, bool v6 /*= false*/)
{
return _getName_<false>(fd, hasport, v6);
}
string Socket::peer_name(int fd, bool hasport/* = false*/, bool v6/* = false*/)
{
return _getName_<true>(fd, hasport, v6);
}
int Socket::read(int fd, char* buff, unsigned& begpos, unsigned endpos)
{
int ret = 0;
//int nread, nleft;
unsigned length_byte;
char* pdata;
do
{
ERRLOG_IF1BRK(fd<0 || 0==buff || begpos >= endpos, ERRSOCK_PARAM,
"SOCKRECV| fd=%d| buff=%p| beg=%u| end=%u", fd, buff, begpos, endpos);
length_byte = endpos - begpos;
pdata = buff + begpos;
ret = ::read(fd, pdata, length_byte);
if (ret > 0)
{
begpos += ret;
}
else if (0 == ret)
{
break;
}
else
{
int eno = errno;
if (eno == EINTR || eno == EAGAIN)
{
ret = ERRSOCK_AGAIN;
break;
}
}
}
while(0);
return ret;
}
int Socket::recv(int fd, char* buff, unsigned& begpos, unsigned endpos)
{
int ret = 0;
int nread, nleft;
unsigned length_byte;
char* pdata;
do
{
ERRLOG_IF1BRK(fd<0 || 0==buff || begpos >= endpos, ERRSOCK_PARAM,
"SOCKRECV| fd=%d| buff=%p| beg=%u| end=%u", fd, buff, begpos, endpos);
length_byte = endpos - begpos;
pdata = buff + begpos;
nread = ::recv(fd, pdata, length_byte, MSG_PEEK);
if (nread < 0)
{
int eno = errno;
IFBREAK_N(eno==EAGAIN || eno==EINTR, ERRSOCK_AGAIN);
LOGERROR("SOCKRECV| fd=%d| err(%d)=%s", fd, eno, strerror(eno));
eno = 0;
ret = ERRSOCK_FAIL;
break;
}
IFBREAK_N(0==nread, ERRSOCK_CLOSE); // normal close
ERRLOG_IF1BRK((unsigned)nread>length_byte, ERRSOCK_UNKNOW, // overwrite ?
"SOCKRECV| fd=%d| nread=%d| lengthbyte=%u", fd, nread, length_byte);
nleft = nread;
while (nleft > 0)
{
if ((nread = ::read(fd, pdata, nleft)) < 0)
{
int eno = errno;
if (eno == EINTR || eno == EAGAIN)
{
nread = 0;
}
else
{
LOGERROR("SOCKRECV| fd=%d| err(%d)=%s", fd, eno, strerror(eno));
ret = ERRSOCK_FAIL;
break;
}
}
else if (nread == 0)
{
break;
}
nleft -= nread;
pdata += nread;
begpos += nread;
ret += nread;
}
} while (false);
return ret;
}
int Socket::send(int fd, char* buff, unsigned& begpos, unsigned endpos)
{
int ret = 0;
int nwrite;
int trytime = 2;
unsigned length_byte;
char* pdata;
while (--trytime > 0)
{
ERRLOG_IF1BRK(fd<0 || 0==buff || begpos >= endpos, ERRSOCK_PARAM,
"SOCKSEND| fd=%d| buff=%p| beg=%u| end=%u", fd, buff, begpos, endpos);
length_byte = endpos - begpos;
pdata = buff + begpos;
nwrite = ::send(fd, pdata, length_byte, MSG_DONTWAIT);
if (nwrite < 0)
{
int eno = errno;
IFBREAK_N(EAGAIN==eno||EWOULDBLOCK==eno, ERRSOCK_AGAIN);
if (EINTR==eno)
{
++trytime;
continue;
}
else
{
LOGERROR("SOCKSEND| fd=%d| err(%d)=%s", fd, eno, strerror(eno));
ret = ERRSOCK_FAIL;
break;
}
}
begpos += nwrite;
ret += nwrite;
}
return ret;
}
int Socket::connect_noblock(int& fd, const char* host, int port) // ipv4
{
return connect(fd, host, port, 0, true);
}
int Socket::connect(int& fd, const char* host, int port, int timout_sec, bool noblock)
{
int ret;
int svrfd = -1;
do
{
IFBREAK_N(NULL == host, ERRSOCK_PARAM);
string strHost(host);
ret = host2Ip(strHost);
ERRLOG_IF1BRK(ret<0, ERRSOCK_PARAM,
"SOCKCONNECT| ret=%d(%s)| ip=%s:%d",
ret, -2==ret?"dns parse fail": "invalid host", host, port);
bool v6 = (ret == 1);
const char* ip = strHost.c_str();
if (v6)
{
struct sockaddr_in6 addr6;
bzero(&addr6, sizeof(addr6));
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(port);
ret = inet_pton(AF_INET6, ip, &addr6.sin6_addr);
ERRLOG_IF1BRK(ret<=0, ERRSOCK_PARAM, "SOCKCONNECT| err(%d)=%s| ip=%s:%d",
errno, strerror(errno), ip, port);
svrfd = socket(AF_INET6, SOCK_STREAM, 0);
if (noblock) sock_nonblock(svrfd);
if (timout_sec > 0) setSndTimeOut(svrfd, timout_sec);
ret = ::connect(svrfd, (struct sockaddr*)&addr6, sizeof(addr6));
}
else
{
struct sockaddr_in addr4;
bzero(&addr4, sizeof(addr4));
addr4.sin_family = AF_INET;
addr4.sin_port = htons(port);
ret = inet_pton(AF_INET, ip, &addr4.sin_addr);
ERRLOG_IF1BRK(ret<=0, ERRSOCK_PARAM, "SOCKCONNECT| ret=%d| err(%d)=%s| ip=%s:%d",
ret, errno, strerror(errno), ip, port);
svrfd = socket(AF_INET, SOCK_STREAM, 0);
if (noblock) sock_nonblock(svrfd);
if (timout_sec > 0) setSndTimeOut(svrfd, timout_sec);
ret = ::connect(svrfd, (struct sockaddr*)&addr4, sizeof(addr4));
}
if (ret)
{
int eno = errno;
if (EINPROGRESS == eno)
{
// non-block socket connecting
ret = ERRSOCK_AGAIN;
fd = svrfd;
break;
}
if (svrfd > 0)
{
close(svrfd);
}
LOGERROR("SOCKCONNECT| err(%d)=%s| ip=%s:%d",
eno, strerror(eno), ip, port);
ret = ERRSOCK_CONNECT;
break;
}
ret = 0;
fd = svrfd;
}
while(0);
return ret;
}
int Socket::geterrno(int fd)
{
int err;
socklen_t len;
int status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
return status;
}
int Socket::setRcvTimeOut(int fd, int sec)
{
struct timeval timeout={sec, 0};
int ret=setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout));
return ret;
}
int Socket::setSndTimeOut(int fd, int sec)
{
struct timeval timeout={sec, 0};
int ret=setsockopt(fd,SOL_SOCKET,SO_SNDTIMEO,&timeout,sizeof(timeout));
return ret;
}
int Socket::setSndBuffSize(int fd, int bytes)
{
socklen_t len = sizeof(int);
int ret;
if ((ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bytes, sizeof(int))) == 0)
{
if ((ret = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bytes, (socklen_t*)&len)) == 0)
{
return bytes;
}
}
return ret;
}
int Socket::setRcvBuffSize(int fd, int bytes)
{
socklen_t len = sizeof(int);
int ret;
if ((ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bytes, sizeof(int))) == 0)
{
if ((ret = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bytes, (socklen_t*)&len)) == 0)
{
return bytes;
}
}
return ret;
}
int Socket::setKeepAlive(int fd, int keepAliveSec, int testIntvalSec, int probeCount)
{
int flag = keepAliveSec > 0 ? 1 : 0;
int ret1 = 0, ret2 = 0, ret3 = 0, ret4 = 0;
ret1 = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flag, sizeof(flag));
if (flag > 0)
{
if (testIntvalSec > 0)
{
ret2 = setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepAliveSec, sizeof(keepAliveSec));
}
if (testIntvalSec > 0)
{
ret3 = setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, (void *)&testIntvalSec, sizeof(testIntvalSec));
}
if (probeCount > 0)
{
ret4 = setsockopt(fd, SOL_TCP, TCP_KEEPCNT, (void *)&probeCount, sizeof(probeCount));
}
}
return (0 == ret1 && 0 == ret2 && 0 == ret3 && 0 == ret4) ? 0 : -1;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。