Socket模块概述
主要对socket
的方法进行封装,提供接口方便的创建TCP
、UDP
、Unix
的socket
对象。
当创建一个socket
对象时,并没有真正的创建一个socket
句柄,此时它的句柄为-1
,只有在bind
、connect
的时候才会通过newSock()
创建一个socket
句柄与对象关联起来,在accept
时创建新的socket
对象,并初始化。新的socket
句柄都初始化为地址复用模式,如果为TCP
连接,禁用Nagle
算法,提高传输效率,降低延迟。
详解
class Socket
socket类型
enum Type {
TCP = SOCK_STREAM,
UDP = SOCK_DGRAM
};
协议簇
enum Family {
IPv4 = AF_INET,
IPv6 = AF_INET6,
UNIX = AF_UNIX
};
mumber(成员变量)
// socketfd
int m_sock;
// 协议簇
int m_family;
// 类型
int m_type;
// 协议
int m_protocol;
// 是否连接
bool m_isConnected;
// 本地地址
Address::ptr m_localAddress;
// 远端地址
Address::ptr m_remotrAddress;
CreateTCP(根据地址创建TCP套接字)
静态方法
Socket::ptr Socket::CreateTCP(sylar::Address::ptr address) {
Socket::ptr sock(new Socket(address->getFamily(), TCP, 0));
return sock;
}
CreateUDP(根据地址创建UDP套接字)
静态方法
Socket::ptr Socket::CreateUDP(sylar::Address::ptr address) {
Socket::ptr sock(new Socket(address->getFamily(), UDP, 0));
return sock;
}
CreateTCPSocket(创建IPv4TCP套接字)
静态方法
Socket::ptr Socket::CreateTCPSocket() {
Socket::ptr sock(new Socket(IPv4, TCP, 0));
return sock;
}
CreateUDPSocket(创建IPv4UDP套接字)
静态方法
Socket::ptr Socket::CreateUDPSocket() {
Socket::ptr sock(new Socket(IPv4, UDP, 0));
return sock;
}
CreateTCPSocket6(创建IPv6TCP套接字)
静态方法
Socket::ptr Socket::CreateTCPSocket6() {
Socket::ptr sock(new Socket(IPv6, TCP, 0));
return sock;
}
CreateUDPSocket6(创建IPv6UDP套接字)
静态方法
Socket::ptr Socket::CreateUDPSocket6() {
Socket::ptr sock(new Socket(IPv6, UDP, 0));
return sock;
}
CreateTCPSocket6(创建UnixTCP套接字)
静态方法
Socket::ptr Socket::CreateUnixTCPSocket() {
Socket::ptr sock(new Socket(UNIX, TCP, 0));
return sock;
}
CreateUDPSocket6(创建UnixUDP套接字)
静态方法
Socket::ptr Socket::CreateUnixUDPSocket() {
Socket::ptr sock(new Socket(UNIX, UDP, 0));
return sock;
}
Socket(构造函数)
只是创建对象,并没有真正的创建socketfd
Socket::Socket(int family, int type, int protocol)
:m_sock(-1)
,m_family(family)
,m_type(type)
,m_protocol(protocol)
,m_isConnected(false) {
}
~Socket(析构函数)
Socket::~Socket() {
close();
}
getSendTimeout(返回发送超时时间)
int64_t Socket::getSendTimeout() {
sylar::FdCtx::ptr ctx = sylar::FdMgr::GetInstance()->get(m_sock);
if (ctx) {
return ctx->getTimeout(SO_SNDTIMEO);
}
return -1;
}
setSendTimeout(设置发送超时时间)
void Socket::setSendTimeout(int64_t v) {
struct timeval tv { int(v / 1000), int(v % 1000 * 1000) };
setOption(SOL_SOCKET, SO_SNDTIMEO, tv);
}
getRecvTimeout(返回接收超时时间)
int64_t Socket::getRecvTimeout() {
sylar::FdCtx::ptr ctx = sylar::FdMgr::GetInstance()->get(m_sock);
if (ctx) {
return ctx->getTimeout(SO_RCVTIMEO);
}
return -1;
}
setRecvTimeout(设置接收超时时间)
void Socket::setRecvTimeout(int64_t v) {
struct timeval tv { int(v / 1000), int(v % 1000) * 1000 };
setOption(SOL_SOCKET, SO_RCVTIMEO, tv);
}
getOption(获取socketfd信息)
模板函数
template<class T>
bool getOption(int level, int option, T& result) {
size_t length = sizeof(T);
return getOption(level, option, &result, &length);
}
bool Socket::getOption(int level, int option, void* result, size_t* len) {
int rt = getsockopt(m_sock, level, option, result, (socklen_t*)len);
if (rt) {
SYLAR_LOG_DEBUG(g_logger) << "getOption sock = " << m_sock
<< ", level = " << level << ", option = " << option
<< ", errno = " << errno << ", strerr = " << strerror(errno);
return false;
}
return true;
}
getOption(设置socketfd信息)
模板函数
template<class T>
bool setOption(int level, int option, const T& result) {
return setOption(level, option, &result, sizeof(T));
}
bool Socket::setOption(int level, int option, const void* result, size_t len) {
int rt = setsockopt(m_sock, level, option, result, (socklen_t)len);
if (rt) {
SYLAR_LOG_DEBUG(g_logger) << "setOption sock = " << m_sock
<< ", level = " << level << ", option = " << option
<< ", errno = " << errno << ", strerr = " << strerror(errno);
return false;
}
return true;
}
init(初始化socket对象)
private
初始化accept
后用于通信的socket
bool Socket::init(int sock) {
FdCtx::ptr ctx = sylar::FdMgr::GetInstance()->get(sock);
if (ctx && ctx->isSocket() && !ctx->isClosed()) {
m_sock = sock;
m_isConnected = true;
initSock();
getLocalAddress();
getRemoteAddress();
return true;
}
return false;
}
initSock(初始化socketfd)
private
void Socket::initSock() {
int val = 1;
// SO_REUSEADDR 打开或关闭地址复用功能 option_value不等于0时,打开
setOption(SOL_SOCKET, SO_REUSEADDR, val);
if (m_type == SOCK_STREAM) {
// Nagle算法通过将小数据块合并成更大的数据块来减少网络传输的次数,提高网络传输的效率。
// 禁用Nagle算法,减小延迟
setOption(IPPROTO_TCP, TCP_NODELAY, val);
}
}
newSock(创建socketfd)
private
void Socket::newSock() {
m_sock = socket(m_family, m_type, m_protocol);
if (SYLAR_LIKELY(m_sock != -1)) {
initSock();
} else {
SYLAR_LOG_ERROR(g_logger) << "socket(" << m_family
<< ", " << m_type << ", " << m_protocol << ") errno = "
<< errno << ", strerr = " << strerror(errno);
}
}
bind(绑定地址)
bool Socket::bind(const Address::ptr addr) {
// 如果没有socketfd
if (!isValid()) {
// 创建socketfd
newSock();
if (SYLAR_UNLIKELY(!isValid())) {
return false;
}
}
if (SYLAR_UNLIKELY(addr->getFamily() != m_family)) {
SYLAR_LOG_ERROR(g_logger) << "bind sock.family("
<< m_family << ") add.family(" << addr->getFamily()
<< ") not qual, addr = " << addr->toString();
return false;
}
if (::bind(m_sock, addr->getAddr(), addr->getAddrLen())) {
SYLAR_LOG_ERROR(g_logger) << "bind errno = " << errno
<< ", strerr = " << strerror(errno);
return false;
}
getLocalAddress();
return true;
}
listen(监听)
bool Socket::listen(int backlog) {
if (!isValid()) {
SYLAR_LOG_ERROR(g_logger) << "listen error sock = -1";
return false;
}
if (::listen(m_sock, backlog)) {
SYLAR_LOG_ERROR(g_logger) << "listen error errno = " << errno
<< ", strerr = " << strerror(errno);
return false;
}
return true;
}
accept(接收connect连接)
创建新的socket
对象,用于与客户端通信。
Socket::ptr Socket::accept() {
Socket::ptr sock(new Socket(m_family, m_type, m_protocol));
int newsock = ::accept(m_sock, nullptr, nullptr);
if (newsock == -1) {
SYLAR_LOG_ERROR(g_logger) << "accept(" << m_sock << ") errno = "
<< errno << ", strerr = " << strerror(errno);
return nullptr;
}
if (sock->init(newsock)) {
return sock;
}
return nullptr;
}
connect(连接地址)
bool Socket::connect(const Address::ptr addr, uint64_t timeout_ms) {
if (!isValid()) {
newSock();
if (SYLAR_UNLIKELY(!isValid())) {
return false;
}
}
if (SYLAR_UNLIKELY(addr->getFamily() != m_family)) {
SYLAR_LOG_ERROR(g_logger) << "bind sock.family("
<< m_family << ") add.family(" << addr->getFamily()
<< ") not qual, addr = " << addr->toString();
return false;
}
if (timeout_ms == (uint64_t)-1) {
if (::connect(m_sock, addr->getAddr(), addr->getAddrLen())) {
SYLAR_LOG_ERROR(g_logger) << "sock = " << m_sock << "connect ("
<< addr->toString() << ") error errno = " << errno
<< ", strerr = " << strerror(errno);
close();
return false;
}
} else {
if (::connect_with_timeout(m_sock, addr->getAddr(), addr->getAddrLen(), timeout_ms)) {
SYLAR_LOG_ERROR(g_logger) << "sock = " << m_sock << "connect ("
<< addr->toString() << ") error errno = " << errno
<< ", strerr = " << strerror(errno);
close();
return false;
}
}
m_isConnected = true;
getRemoteAddress();
getLocalAddress();
return true;
}
close(关闭socket)
bool Socket::close() {
if (!m_isConnected && m_sock == -1) {
return true;
}
m_isConnected = false;
if (m_sock != -1) {
::close(m_sock);
m_sock = -1;
}
return true;
}
send(发送数据:单数据块)
int Socket::send(const void* buffer, size_t length, int flags) {
if (isConnected()) {
return ::send(m_sock, buffer, length, flags);
}
return -1;
}
send(发送数据:多数据块)
int Socket::send(const iovec* buffers, size_t length, int flags) {
if (isConnected()) {
msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = (iovec*)buffers;
msg.msg_iovlen = length;
return ::sendmsg(m_sock, &msg, flags);
}
return -1;
}
sendTo(指定地址发送数据:单数据块)
int Socket::sendTo(const void* buffer, size_t length, const Address::ptr to, int flags) {
if (isConnected()) {
return ::sendto(m_sock, buffer, length, flags, to->getAddr(), to->getAddrLen());
}
return -1;
}
sendTo(指定地址发送数据:多数据块)
int Socket::sendTo(const iovec* buffers, size_t length, const Address::ptr to, int flags) {
if (isConnected()) {
msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = (iovec*)buffers;
msg.msg_iovlen = length;
msg.msg_name = const_cast<sockaddr*>(to->getAddr());
msg.msg_namelen = to->getAddrLen();
return ::sendmsg(m_sock, &msg, flags);
}
return -1;
}
recv(接收数据:单数据块)
int Socket::recv(void* buffer, size_t length, int flags) {
if (isConnected()) {
return ::recv(m_sock, buffer, length, flags);
}
return -1;
}
recv(接收数据:多数据块)
int Socket::recv(iovec* buffers, size_t length, int flags) {
if (isConnected()) {
msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = (iovec*)buffers;
msg.msg_iovlen = length;
return ::recvmsg(m_sock, &msg, flags);
}
return -1;
}
recvFrom(指定地址接收数据:单数据块)
int Socket::recvFrom(void* buffer, size_t length, Address::ptr from, int flags) {
if (isConnected()) {
socklen_t len = from->getAddrLen();
return ::recvfrom(m_sock, buffer, length, flags, const_cast<sockaddr*>(from->getAddr()), &len);
}
return -1;
}
recvFrom(指定地址接收数据:多数据块)
int Socket::recvFrom(iovec* buffers, size_t length, Address::ptr from, int flags) {
if (isConnected()) {
msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = (iovec*)buffers;
msg.msg_iovlen = length;
msg.msg_name = const_cast<sockaddr*>(from->getAddr());
msg.msg_namelen = from->getAddrLen();
return recvmsg(m_sock, &msg, flags);
}
return -1;
}
getRemoteAddress(返回远端地址)
Address::ptr Socket::getRemoteAddress() {
if (m_remotrAddress) {
return m_remotrAddress;
}
Address::ptr result;
switch (m_family) {
case AF_INET:
result.reset(new IPv4Address());
break;
case AF_INET6:
result.reset(new IPv6Address());
break;
case AF_UNIX:
result.reset(new UinxAddress());
break;
default:
result.reset(new UnknowAddress(m_family));
break;
}
socklen_t addrlen = result->getAddrLen();
// 获取一个已连接套接字的远程地址信息
if (getpeername(m_sock, const_cast<sockaddr*>(result->getAddr()), &addrlen)) {
SYLAR_LOG_ERROR(g_logger) << "getpeername error sock = " << m_sock
<< ", errno = " << errno << ", strerr = " << strerror(errno);
return Address::ptr(new UnknowAddress(m_family));
}
if (m_family == AF_UNIX) {
UinxAddress::ptr addr = std::dynamic_pointer_cast<UinxAddress>(result);
addr->setAddrlen(addrlen);
}
m_remotrAddress = result;
return m_remotrAddress;
}
getRemoteAddress(返回本地地址)
Address::ptr Socket::getLocalAddress() {
if (m_localAddress) {
return m_localAddress;
}
Address::ptr result;
switch (m_family) {
case AF_INET:
result.reset(new IPv4Address());
break;
case AF_INET6:
result.reset(new IPv6Address());
break;
case AF_UNIX:
result.reset(new UinxAddress());
break;
default:
result.reset(new UnknowAddress(m_family));
break;
}
socklen_t addrlen = result->getAddrLen();
// 获取一个套接字的本地地址信息
if (getsockname(m_sock, const_cast<sockaddr*>(result->getAddr()), &addrlen)) {
SYLAR_LOG_ERROR(g_logger) << "getsockname error sock = " << m_sock
<< ", errno = " << errno << ", strerr = " << strerror(errno);
return Address::ptr(new UnknowAddress(m_family));
}
if (m_family == AF_UNIX) {
UinxAddress::ptr addr = std::dynamic_pointer_cast<UinxAddress>(result);
addr->setAddrlen(addrlen);
}
m_localAddress = result;
return m_localAddress;
}
cancelRead(取消读事件)
bool Socket::cancelRead() {
return IOManager::GetThis()->cancelEvent(m_sock, sylar::IOManager::READ);
}
cancelWrite(取消写事件)
bool Socket::cancelWrite() {
return IOManager::GetThis()->cancelEvent(m_sock, sylar::IOManager::WRITE);
}
cancelAccept(取消accept)
bool Socket::cancelAccept() {
return IOManager::GetThis()->cancelEvent(m_sock, sylar::IOManager::READ);
}
cancelAll(取消所有事件)
bool Socket::cancelAll() {
return IOManager::GetThis()->cancelAll(m_sock);
}