文章目录
P54-P56:Socket 06-08
后面三节内容和前面Address
模块一样,主要对socket
的方法进行封装,提供接口方便的创建TCP
、UDP
、Unix
的socket
对象。
当创建一个socket
对象时,并没有真正的创建一个socket
句柄,此时它的句柄为-1
,只有在bind
、connect
的时候才会通过newSock()
创建一个socket
句柄与对象关联起来,在accept
时创建新的socket
对象,并初始化。新的socket
句柄都初始化为地址复用模式,如果为TCP
连接,禁用Nagle
算法,提高传输效率,降低延迟。
class Socket
成员变量
// socketfd
int m_sock;
// 协议簇
int m_family;
// 类型
int m_type;
// 协议
int m_protocol;
// 是否连接
bool m_isConnected;
// 本地地址
Address::ptr m_localAddress;
// 远端地址
Address::ptr m_remoteAddress;
创建套接字
Socket::ptr Socket::CreateTCP(sylar::Address::ptr address) {
Socket::ptr sock(new Socket(address->getFamily(), TCP, 0));
return sock;
}
Socket::ptr Socket::CreateUDP(sylar::Address::ptr address) {
Socket::ptr sock(new Socket(address->getFamily(), UDP, 0));
return sock;
}
///
Socket::ptr Socket::CreateTCPSocket() {
Socket::ptr sock(new Socket(IPv4, TCP, 0));
return sock;
}
Socket::ptr Socket::CreateUDPSocket() {
Socket::ptr sock(new Socket(IPv4, UDP, 0));
return sock;
}
///
Socket::ptr Socket::CreateTCPSocket6() {
Socket::ptr sock(new Socket(IPv6, TCP, 0));
return sock;
}
Socket::ptr Socket::CreateUDPSocket6() {
Socket::ptr sock(new Socket(IPv6, UDP, 0));
return sock;
}
///
Socket::ptr Socket::CreateUnixTCPSocket() {
Socket::ptr sock(new Socket(UNIX, TCP, 0));
return sock;
}
Socket::ptr Socket::CreateUnixUDPSocket() {
Socket::ptr sock(new Socket(UNIX, UDP, 0));
return sock;
}
构造/析构函数
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() {
close();
}
超时时间
int64_t Socket::getSendTimeout() {
// 通过句柄管理器获得一个句柄
FdCtx::ptr ctx = FdMgr::GetInstance()->get(m_sock);
if(ctx) {
// 成功获取则调用Fdctx中的获取超时时间函数,根据传入的参数获取接收超时时间或者发送超时时间
return ctx->getTimeout(SO_SNDTIMEO);
}
return -1;
}
void Socket::setSendTimeout(int64_t v) {
struct timeval tv{int(v / 1000), int(v % 1000 * 1000)};
setOption(SOL_SOCKET, SO_SNDTIMEO, tv);
}
///
void Socket::setSendTimeout(int64_t v) {
struct timeval tv{int(v / 1000), int(v % 1000 * 1000)};
setOption(SOL_SOCKET, SO_SNDTIMEO, tv);
}
int64_t Socket::getRecvTimeout() {
FdCtx::ptr ctx = FdMgr::GetInstance()->get(m_sock);
if(ctx) {
return ctx->getTimeout(SO_RCVTIMEO);
}
return -1;
}
getOption
bool Socket::getOption(int level, int option, void* result, size_t* len) {
// 调用之前写的hook函数getsockopt,通过socketfd获取详细信息
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 << " errstr = " << strerror(errno);
return false;
}
return true;
}
setOption
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 << " errstr = " << strerror(errno);
return false;
}
return true;
}
init
bool Socket::init(int sock) {
FdCtx::ptr ctx = FdMgr::GetInstance()->get(sock);
if(ctx && ctx->isSocket() && !ctx->isClose()) {
m_sock = sock;
m_isConnected = true;
initSock();
getLocalAddress();
getRemoteAddress();
return true;
}
return false;
}
initSock
void Socket::initSock() {
int val = 1;
setOption(SOL_SOCKET, SO_REUSEADDR, val);
if(m_type == SOCK_STREAM) {
setOption(IPPROTO_TCP, TCP_NODELAY, val);
}
}
newSock
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 << " errstr = " << 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 << ") addr.family(" << addr->getFamily()
<< ") not equal, addr = " << addr->toString();
return false;
}
if(::bind(m_sock, addr->getAddr(), addr->getAddrLen())) {
SYLAR_LOG_ERROR(g_logger) << "bind error 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
<< " errstr = " << strerror(errno);
return false;
}
return true;
}
accept
Socket::ptr Socket::accept() {
// 创建新的socket对象,用于与客户端通信。
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 << " errstr = " << 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) << "connect sock.family("
<< m_family << ") addr.family(" << addr->getFamily()
<< ") not equal, 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 << " errstr = " << 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()
<< ") tomeout" << timeout_ms << " error errno = " << errno << " errstr = " << strerror(errno);
close();
return false;
}
}
m_isConnected = true;
getRemoteAddress();
getLocalAddress();
return true;
}
close
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 false;
}
发送数据
int Socket::send(const void* buffer, size_t length, int flag) {
if(isConnected()) {
return ::send(m_sock, buffer, length, flag);
}
return -1;
}
int Socket::send(const iovec* buffers, size_t length, int flag) {
if(isConnected()) {
msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = (iovec*)buffers;
msg.msg_iovlen = length;
return ::sendmsg(m_sock, &msg, flag);
}
return -1;
}
int Socket::sendTo(const void* buffer, size_t length, const Address::ptr to,int flag) {
if(isConnected()) {
return ::sendto(m_sock, buffer, length, flag, to->getAddr(), to->getAddrLen());
}
return -1;
}
int Socket::sendTo(const iovec* buffers, size_t length, const Address::ptr to,int flag) {
if(isConnected()) {
msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = (iovec*)buffers;
msg.msg_iovlen = length;
msg.msg_name = to->getAddr();
msg.msg_namelen = to->getAddrLen();
return ::sendmsg(m_sock, &msg, flag);
}
return -1;
}
接收数据
int Socket::recv(void* buffer, size_t length, int flag) {
if(isConnected()) {
return ::recv(m_sock, buffer, length,flag);
}
return -1;
}
int Socket::recv(iovec* buffers, size_t length, int flag) {
if(isConnected()) {
msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = (iovec*)buffers;
msg.msg_iovlen = length;
return ::recvmsg(m_sock, &msg, flag);
}
return -1;
}
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, from->getAddr(), &len);
}
return -1;
}
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 = from->getAddr();
msg.msg_namelen = from->getAddrLen();
return ::recvmsg(m_sock, &msg, flags);
}
return -1;
}
getRemoteAddress
Address::ptr Socket::getRemoteAddress() {
// 已经有了直接返回
if(m_remoteAddress) {
return m_remoteAddress;
}
// 结果地址
Address::ptr result;
// 根据协议簇创建指定地址
switch(m_family) {
case AF_INET:
result.reset(new IPv4Address());
break;
case AF_INET6:
result.reset(new IPv6Address());
case AF_UNIX:
result.reset(new UnixAddress());
break;
default:
result.reset(new UnknownAddress(m_family));
break;
}
// 获取地址长度
socklen_t addrlen = result->getAddrLen();
if(getpeername(m_sock, result->getAddr(), &addrlen)) {
SYLAR_LOG_ERROR(g_logger) << "getpeername error sock = " << m_sock
<< " errno = " << errno << " errstr = " << strerror(errno);
return Address::ptr(new UnknownAddress(m_family));
}
if(m_family == AF_UNIX) {
UnixAddress::ptr addr = std::dynamic_pointer_cast<UnixAddress>(result);
addr->setAddrLen(addrlen);
}
m_remoteAddress = result;
return m_remoteAddress;
}
getLocalAddress
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());
case AF_UNIX:
result.reset(new UnixAddress());
break;
default:
result.reset(new UnknownAddress(m_family));
break;
}
socklen_t addrlen = result->getAddrLen();
if(getsockname(m_sock, result->getAddr(), &addrlen)) {
SYLAR_LOG_ERROR(g_logger) << "getsockname error sock = " << m_sock
<< " errno = " << errno << " errstr = " << strerror(errno);
return Address::ptr(new UnknownAddress(m_family));
}
if(m_family == AF_UNIX) {
UnixAddress::ptr addr = std::dynamic_pointer_cast<UnixAddress>(result);
addr->setAddrLen(addrlen);
}
m_localAddress = result;
return m_localAddress;
}
测试
代码
#include "../sylar/socket.h"
#include "../sylar/sylar.h"
#include "../sylar/iomanager.h"
#include "../sylar/address.h"
static sylar::Logger::ptr g_looger = SYLAR_LOG_ROOT();
void test_socket() {
sylar::IPAddress::ptr addr = sylar::Address::LookupAnyIPAdress("www.baidu.com");
if(addr) {
SYLAR_LOG_INFO(g_looger) << "get address: " << addr->toString();
} else {
SYLAR_LOG_ERROR(g_looger) << "get address fail";
return;
}
sylar::Socket::ptr sock = sylar::Socket::CreateTCP(addr);
addr->setPort(80);
if(!sock->connect(addr)) {
SYLAR_LOG_ERROR(g_looger) << "connect " << addr->toString() << " fail";
return;
} else {
SYLAR_LOG_INFO(g_looger) << "connect " << addr->toString() << " connected";
}
const char buff[] = "GET / HTTP/1.0\r\n\r\n";
int rt = sock->send(buff, sizeof(buff));
if(rt <= 0) {
SYLAR_LOG_ERROR(g_looger) << "send fail rt = " << rt;
return;
}
std::string buffs;
buffs.resize(4096);
rt = sock->recv(&buffs[0], buffs.size());
if(rt <= 0) {
SYLAR_LOG_ERROR(g_looger) << "recv fail rt = " << rt;
return;
}
buffs.resize(rt);
SYLAR_LOG_INFO(g_looger) << buffs;
}
int main(int argc, char** argv) {
sylar::IOManager iom;
iom.schedule(&test_socket);
return 0;
}
结果