TC_Socket是一个socket的封装类,封装了socket的处理,该封装类的主要操作功能包括
- 生成socket,根据指定的socket类型,调用socket系统调用,并进行异常处理,如果sock存在,则先关闭,打开新的描述符。
void
TC_Socket::createSocket(
int
iSocketType,
int
iDomain)
{
assert (iSocketType == SOCK_STREAM || iSocketType == SOCK_DGRAM);
close();
_iDomain
= iDomain;
_sock
= socket(iDomain, iSocketType , 0);
if
(
_sock
< 0)
{
_sock
=
INVALID_SOCKET
;
throw
TC_Socket_Exception
(
"[TC_Socket::createSocket] create socket error! :"
+ string(strerror( errno)));
}
}
- 关闭sock;
void
TC_Socket::close()
{
if
(
_sock
!=
INVALID_SOCKET
)
{
:: close(
_sock
);
_sock
=
INVALID_SOCKET
;
}
}
- 获取对点的ip和端口,对AF_INET的socket有效,构建sockaddr,利用getPeerName从sock描述符获取IP以及端口地址,通过inet_ntop把数值型地址转换为字符串,通过ntohs把端口的网络顺序转换成为主机顺序,sPeerAddress= sAddr是一个复制拷贝。
void
TC_Socket:: getPeerName(string &sPeerAddress,
uint16_t
&iPeerPort)
{
assert (
_iDomain
== AF_INET);
struct
sockaddr
stPeer;
bzero (&stPeer,
sizeof
(
struct
sockaddr
));
socklen_t iPeerLen =
sizeof
(
sockaddr
);
getPeerName (&stPeer, iPeerLen);
char
sAddr[ INET_ADDRSTRLEN] =
"\0"
;
struct
sockaddr_in
*p = (
struct
sockaddr_in
*)&stPeer;
inet_ntop (
_iDomain
, &p->sin_addr, sAddr,
sizeof
(sAddr));
sPeerAddress= sAddr;
iPeerPort = ntohs(p->sin_port);
}
- 获取自己的ip和端口,对AF_INET的socket有效.
void
TC_Socket:: getSockName(string &sSockAddress,
uint16_t
&iSockPort)
{
assert (
_iDomain
== AF_INET);
struct
sockaddr
stSock;
bzero (&stSock,
sizeof
(
struct
sockaddr
));
socklen_t iSockLen =
sizeof
(
sockaddr
);
getSockName (&stSock, iSockLen);
char
sAddr[ INET_ADDRSTRLEN] =
"\0"
;
struct
sockaddr_in
*p = (
struct
sockaddr_in
*)&stSock;
inet_ntop (
_iDomain
, &p->sin_addr, sAddr,
sizeof
(sAddr));
sSockAddress = sAddr;
iSockPort = ntohs(p->sin_port);
}
- 修改,获取socket选项值.
int
TC_Socket:: setSockOpt(
int
opt,
const
void
*pvOptVal, socklen_t optLen,
int
level)
{
return
setsockopt(
_sock
, level, opt, pvOptVal, optLen);
}
int
TC_Socket::getSockOpt(
int
opt,
void
*pvOptVal, socklen_t &optLen,
int
level)
{
return
getsockopt(
_sock
, level, opt, pvOptVal, &optLen);
}
- accept服务端sock,accept是阻塞的操作,并是一个不可重入函数,会被信号处理等中断,此处需要重复操作,返回一个客户端TC_SOCK
int
TC_Socket:: accept(
TC_Socket
&tcSock,
struct
sockaddr
*pstSockAddr, socklen_t &iSockLen)
{
assert (tcSock.
_sock
==
INVALID_SOCKET
);
int
ifd;
while
((ifd = :: accept(
_sock
, pstSockAddr, &iSockLen)) < 0 && errno == EINTR);
tcSock.
_sock
= ifd;
tcSock.
_iDomain
=
_iDomain
;
return
tcSock.
_sock
;
}
- bind操作,将sock绑定到指定的地址与端口
void
TC_Socket:: bind(
const
char
*sPathName)
{
assert (
_iDomain
== AF_LOCAL);
unlink (sPathName);
struct
sockaddr_un
stBindAddr;
bzero (&stBindAddr,
sizeof
(
struct
sockaddr_un
));
stBindAddr. sun_family =
_iDomain
;
strncpy (stBindAddr.sun_path, sPathName,
sizeof
(stBindAddr.sun_path));
try
{
bind((
struct
sockaddr
*)&stBindAddr,
sizeof
(stBindAddr));
}
catch
(...)
{
throw
TC_Socket_Exception
(
"[TC_Socket::bind] bind '"
+ string(sPathName) +
"' error"
, errno);
}
}
void
TC_Socket::bind(
struct
sockaddr
* pstBindAddr, socklen_t iAddrLen)
{
//如果服务器终止后,服务器可以第二次快速启动而不用等待一段时间
int
iReuseAddr = 1;
//设置
setSockOpt (SO_REUSEADDR, (
const
void
*)&iReuseAddr,
sizeof
(
int
), SOL_SOCKET);
if
(:: bind(
_sock
, pstBindAddr, iAddrLen) < 0)
{
throw
TC_Socket_Exception
(
"[TC_Socket::bind] bind error"
, errno );
}
}
- 连接其他服务,对AF_INET的socket有效(同步连接)
int
TC_Socket::connect(
struct
sockaddr
*pstServerAddr, socklen_t serverLen)
{
return
:: connect(
_sock
, pstServerAddr, serverLen);
}
- 监听其他端口(同步连接),能收指定连接队列
void
TC_Socket::listen(
int
iConnBackLog)
{
if
(:: listen(
_sock
, iConnBackLog) < 0)
{
throw
TC_Socket_Exception
(
"[TC_Socket::listen] listen error"
, errno );
}
}
- 发送,接收数据(一般用于tcp).
int
TC_Socket::recv(
void
*pvBuf, size_t iLen,
int
iFlag)
{
return
:: recv(
_sock
, pvBuf, iLen, iFlag);
}
int
TC_Socket::send(
const
void
*pvBuf, size_t iLen,
int
iFlag)
{
return
:: send(
_sock
, pvBuf, iLen, iFlag);
}
- 单向关闭连接
void
TC_Socket:: shutdown(
int
iHow)
{
if
(:: shutdown(
_sock
, iHow) < 0)
{
throw
TC_Socket_Exception
(
"[TC_Socket::shutdown] shutdown error"
, errno );
}
}
- 设置是否阻塞,利用fcntl,先F_GETFL操作,加上或者消除bBlock后F_SETFL
void
TC_Socket:: setblock(
int
fd,
bool
bBlock)
{
int
val = 0;
if
((val = fcntl(fd, F_GETFL, 0)) == -1)
{
throw
TC_Socket_Exception
(
"[TC_Socket::setblock] fcntl [F_GETFL] error"
, errno );
}
if
(!bBlock)
{
val |= O_NONBLOCK;
}
else
{
val &= ~ O_NONBLOCK;
}
if
( fcntl(fd, F_SETFL, val) == -1)
{
throw
TC_Socket_Exception
(
"[TC_Socket::setblock] fcntl [F_SETFL] error"
, errno );
}
}
- 静态工具方法,生成管道,并且将管道设置的读写设置为指定的阻塞设置。
void
TC_Socket:: createPipe(
int
fds[2],
bool
bBlock)
{
if
(:: pipe(fds) != 0)
{
throw
TC_Socket_Exception
(
"[TC_Socket::createPipe] error"
, errno );
}
try
{
setblock(fds[0], bBlock);
setblock(fds[1], bBlock);
}
catch
(...)
{
:: close(fds[0]);
:: close(fds[1]);
throw
;
}
}
- 静态工具方法,获取所有本地地址,主要借助于ioctl函数,不断的递增分配存储空间,直到空间能够容纳所有的地址为止,表示取到了所有的地址;
vector< string> TC_Socket:: getLocalHosts()
{
vector <string> result;
TC_Socket
ts;
ts.createSocket (SOCK_STREAM, AF_INET);
int
cmd = SIOCGIFCONF;
struct
ifconf
ifc;
int
numaddrs = 10;
int
old_ifc_len = 0;
while
(
true
)
{
int
bufsize = numaddrs *
static_cast
<
int
>(
sizeof
(
struct
ifreq
));
ifc. ifc_len = bufsize;
ifc. ifc_buf = (
char
*)malloc (bufsize);
int
rs = ioctl(ts.getfd(), cmd, &ifc);
if
(rs == -1)
{
free(ifc.ifc_buf );
throw
TC_Socket_Exception
(
"[TC_Socket::getLocalHosts] ioctl error"
, errno);
}
else
if
(ifc. ifc_len == old_ifc_len)
{
break
;
}
else
{
old_ifc_len = ifc. ifc_len;
}
numaddrs += 10;
free(ifc.ifc_buf);
}
numaddrs = ifc. ifc_len /
static_cast
<
int
>(
sizeof
(
struct
ifreq
));
struct
ifreq
* ifr = ifc. ifc_req;
for
(
int
i = 0; i < numaddrs; ++i)
{
if
(ifr[i]. ifr_addr.sa_family == AF_INET)
{
struct
sockaddr_in
* addr =
reinterpret_cast
<
struct
sockaddr_in
*>(&ifr[i]. ifr_addr);
if
(addr-> sin_addr.s_addr != 0)
{
char
sAddr[ INET_ADDRSTRLEN] =
"\0"
;
inet_ntop(AF_INET , &(*addr).sin_addr, sAddr,
sizeof
(sAddr));
result.push_back (sAddr);
}
}
}
free (ifc.ifc_buf);
return
result;
}
- 静态工具方法,解析地址, 从字符串(ip或域名), 解析到in_addr结构.
void
TC_Socket:: parseAddr(
const
string &sAddr,
struct
in_addr
&stSinAddr)
{
int
iRet = inet_pton(AF_INET, sAddr. c_str(), &stSinAddr);
if
(iRet < 0)
{
throw
TC_Socket_Exception
(
"[TC_Socket::parseAddr] inet_pton error"
, errno );
}
else
if
(iRet == 0)
{
struct
hostent
stHostent;
struct
hostent
*pstHostent;
char
buf[2048] =
"\0"
;
int
iError;
gethostbyname_r(sAddr.c_str(), &stHostent, buf,
sizeof
(buf), &pstHostent, &iError);
if
(pstHostent == NULL)
{
throw
TC_Socket_Exception
(
"[TC_Socket::parseAddr] gethostbyname_r error! :"
+ string(hstrerror(iError)));
}
else
{
stSinAddr = *(
struct
in_addr
*) pstHostent-> h_addr;
}
}
}