[置顶] Muduo网络库源码分析之对socket及其相关操作的封装
2018-01-09 15:14
981 查看
主要涉及到的类和实现文件有:
Endian.h
提供了字节序转换的函数。
Socket.h/Socket.cc
socketfd 的封装,提供了绑定地址、开始listen、接受连接等操作,并可设置套接字选项。
InetAddress.h/InetAddress.cc
套接字地址的封装,提供了多种方式初始化一个地址,还提供方法从地址中拿到 ip 和 port。
SocketsOps.h/SocketsOps.cc
封装了 socket 相关的一些操作,提供给 Socket 和 InetAddress 用。
这部分就是基本的 TCP 套接字编程和套接字选项的知识,代码逻辑也很简单,推荐看下 UNP卷一 的相关章节。
下面逐一看下这几个相关的文件。
Socket.cc
InetAddress.cc
SocketsOps.cc
Endian.h
提供了字节序转换的函数。
Socket.h/Socket.cc
socketfd 的封装,提供了绑定地址、开始listen、接受连接等操作,并可设置套接字选项。
InetAddress.h/InetAddress.cc
套接字地址的封装,提供了多种方式初始化一个地址,还提供方法从地址中拿到 ip 和 port。
SocketsOps.h/SocketsOps.cc
封装了 socket 相关的一些操作,提供给 Socket 和 InetAddress 用。
这部分就是基本的 TCP 套接字编程和套接字选项的知识,代码逻辑也很简单,推荐看下 UNP卷一 的相关章节。
下面逐一看下这几个相关的文件。
字节序转换部分(Endian.h)
#ifndef MUDUO_NET_ENDIAN_H #define MUDUO_NET_ENDIAN_H #include <stdint.h> #include <endian.h> namespace muduo { namespace net { namespace sockets { // the inline assembler code makes type blur, // so we disable warnings for a while. #if defined(__clang__) || __GNUC_PREREQ (4,6) #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wold-style-cast" /* uint64_t 的整形数字由机器字节序转化为网络字节序 */ inline uint64_t hostToNetwork64(uint64_t host64) { return htobe64(host64); } /* uint32_t 的整形数字由机器字节序转化为网络字节序 */ inline uint32_t hostToNetwork32(uint32_t host32) { return htobe32(host32); } /* uint16_t 的整形数字由机器字节序转化为网络字节序 */ inline uint16_t hostToNetwork16(uint16_t host16) { return htobe16(host16); } /* uint64_t 的整形数字由网络字节序转化为机器字节序 */ inline uint64_t networkToHost64(uint64_t net64) { return be64toh(net64); } /* uint32_t 的整形数字由网络字节序转化为机器字节序 */ inline uint32_t networkToHost32(uint32_t net32) { return be32toh(net32); } /* uint16_t 的整形数字由网络字节序转化为机器字节序 */ inline uint16_t networkToHost16(uint16_t net16) { return be16toh(net16); } #if defined(__clang__) || __GNUC_PREREQ (4,6) #pragma GCC diagnostic pop #else #pragma GCC diagnostic warning "-Wconversion" #pragma GCC diagnostic warning "-Wold-style-cast" #endif } } } #endif // MUDUO_NET_ENDIAN_H
Socket
Socket.h#ifndef MUDUO_NET_SOCKET_H #define MUDUO_NET_SOCKET_H #include <boost/noncopyable.hpp> // struct tcp_info is in <netinet/tcp.h> struct tcp_info; namespace muduo { /// /// TCP networking. /// namespace net { class InetAddress; /// It closes the sockfd when desctructs. /* sock 描述符 fd的封装,实现了 绑定了地址,开始监听 并接受连接 */ class Socket : boost::noncopyable { public: explicit Socket(int sockfd) : sockfd_(sockfd) { } /* close(sockfd_) */ ~Socket(); /* 返回 这个 socket 的 fd*/ int fd() const { return sockfd_; } /* 获取与这个套接字相关联的选项,成功返回 true */ bool getTcpInfo(struct tcp_info*) const; bool getTcpInfoString(char* buf, int len) const; /* 调用bind,绑定sockaddr */ void bindAddress(const InetAddress& localaddr); /* 调用listen ,开始监听*/ void listen(); /// On success, returns a non-negative integer that is /// a descriptor for the accepted socket, which has been /// set to non-blocking and close-on-exec. *peeraddr is assigned. /// On error, -1 is returned, and *peeraddr is untouched. /* 调用accept,成功返回non-blocking和close-on-exec属性的 connfd */ int accept(InetAddress* peeraddr); /* 关闭"写"方向的连接 */ void shutdownWrite(); /* 是否使用 Nagle 算法 */ void setTcpNoDelay(bool on); /* 是否重用本地地址 */ void setReuseAddr(bool on); /* 是否重用本地端口 */ void setReusePort(bool on); /* 是否定期检测连接数否存在 */ void setKeepAlive(bool on); private: const int sockfd_; // sockket fd }; } } #endif // MUDUO_NET_SOCKET_H
Socket.cc
#include <muduo/net/Socket.h> #include <muduo/base/Logging.h> #include <muduo/net/InetAddress.h> #include <muduo/net/SocketsOps.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <strings.h> // bzero #include <stdio.h> // snprintf using namespace muduo; using namespace muduo::net; /* 析构时关闭 fd */ Socket::~Socket() { sockets::close(sockfd_); } bool Socket::getTcpInfo(struct tcp_info* tcpi) const { socklen_t len = sizeof(*tcpi); bzero(tcpi, len); return ::getsockopt(sockfd_, SOL_TCP, TCP_INFO, tcpi, &len) == 0; } /* 将TCP信息转化为字符串 */ bool Socket::getTcpInfoString(char* buf, int len) const { struct tcp_info tcpi; bool ok = getTcpInfo(&tcpi); if (ok) { snprintf(buf, len, "unrecovered=%u " "rto=%u ato=%u snd_mss=%u rcv_mss=%u " "lost=%u retrans=%u rtt=%u rttvar=%u " "sshthresh=%u cwnd=%u total_retrans=%u", tcpi.tcpi_retransmits, // Number of unrecovered [RTO] timeouts tcpi.tcpi_rto, // Retransmit timeout in usec tcpi.tcpi_ato, // Predicted tick of soft clock in usec tcpi.tcpi_snd_mss, tcpi.tcpi_rcv_mss, tcpi.tcpi_lost, // Lost packets tcpi.tcpi_retrans, // Retransmitted packets out tcpi.tcpi_rtt, // Smoothed round trip time in usec tcpi.tcpi_rttvar, // Medium deviation tcpi.tcpi_snd_ssthresh, tcpi.tcpi_snd_cwnd, tcpi.tcpi_total_retrans); // Total retransmits for entire connection } return ok; } /* 以下bind listen accept shutdown 通过调用 sockets 的函数实现 */ void Socket::bindAddress(const InetAddress& addr) { sockets::bindOrDie(sockfd_, addr.getSockAddr()); } void Socket::listen() { sockets::listenOrDie(sockfd_); } int Socket::accept(InetAddress* peeraddr) { struct sockaddr_in6 addr; bzero(&addr, sizeof addr); int connfd = sockets::accept(sockfd_, &addr); if (connfd >= 0) { peeraddr->setSockAddrInet6(addr); } return connfd; } void Socket::shutdownWrite() { sockets::shutdownWrite(sockfd_); } /* 下面设置可选项,由 setsockopt 实现,可参考UNP第七章:套接字选项 */ void Socket::setTcpNoDelay(bool on) { int optval = on ? 1 : 0; ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, &optval, static_cast<socklen_t>(sizeof optval)); // FIXME CHECK } void Socket::setReuseAddr(bool on) { int optval = on ? 1 : 0; ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &optval, static_cast<socklen_t>(sizeof optval)); // FIXME CHECK } void Socket::setReusePort(bool on) { #ifdef SO_REUSEPORT int optval = on ? 1 : 0; int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, &optval, static_cast<socklen_t>(sizeof optval)); if (ret < 0 && on) { LOG_SYSERR << "SO_REUSEPORT failed."; } #else if (on) { LOG_ERROR << "SO_REUSEPORT is not supported."; } #endif } void Socket::setKeepAlive(bool on) { int optval = on ? 1 : 0; ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, &optval, static_cast<socklen_t>(sizeof optval)); // FIXME CHECK }
InetAddress
InetAddress.h#ifndef MUDUO_NET_INETADDRESS_H #define MUDUO_NET_INETADDRESS_H #include <muduo/base/copyable.h> #include <muduo/base/StringPiece.h> #include <netinet/in.h> namespace muduo { namespace net { namespace sockets { const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); } /// This is an POD interface class. /* 套接字地址的封装,包括IPv4和IPv6 */ class InetAddress : public muduo::copyable { public: /* 根据提供的参数,对应几种构造方法 */ /// Constructs an endpoint with given port number. /// Mostly used in TcpServer listening. explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false); /// Constructs an endpoint with given ip and port. /// @c ip should be "1.2.3.4" InetAddress(StringArg ip, uint16_t port, bool ipv6 = false); /// Constructs an endpoint with given struct @c sockaddr_in /// Mostly used when accepting new connections explicit InetAddress(const struct sockaddr_in& addr) : addr_(addr) { } explicit InetAddress(const struct sockaddr_in6& addr) : addr6_(addr) { } /* 返回套接字地址的地址族 */ sa_family_t family() const { return addr_.sin_family; } /* 获取IP 和 Port 信息 */ string toIp() const; string toIpPort() const; uint16_t toPort() const; // default copy/assignment are Okay /* 返回对应的通用套接字地址结构的指针 */ const struct sockaddr* getSockAddr() const { return sockets::sockaddr_cast(&addr6_); } void setSockAddrInet6(const struct sockaddr_in6& addr6) { addr6_ = addr6; } /* 返回套接字地址的ip和端口 */ uint32_t ipNetEndian() const; uint16_t portNetEndian() const { return addr_.sin_port; } // resolve hostname to IP address, not changing port or sin_family // return true on success. // thread safe /* 不改变端口 和地址族的情况下,从主机名得到IP地址 */ static bool resolve(StringArg hostname, InetAddress* result); // static std::vector<InetAddress> resolveAll(const char* hostname, uint16_t port = 0); private: union { struct sockaddr_in addr_; //IPv4 struct sockaddr_in6 addr6_; //IPv6 }; }; } } #endif // MUDUO_NET_INETADDRESS_H
InetAddress.cc
#include <muduo/net/InetAddress.h> #include <muduo/base/Logging.h> #include <muduo/net/Endian.h> #include <muduo/net/SocketsOps.h> #include <netdb.h> #include <strings.h> // bzero #include <netinet/in.h> #include <boost/static_assert.hpp> // INADDR_ANY use (type)value casting. #pragma GCC diagnostic ignored "-Wold-style-cast" static const in_addr_t kInaddrAny = INADDR_ANY; static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK; #pragma GCC diagnostic error "-Wold-style-cast" using namespace muduo; using namespace muduo::net; BOOST_STATIC_ASSERT(sizeof(InetAddress) == sizeof(struct sockaddr_in6)); BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_family) == 0); BOOST_STATIC_ASSERT(offsetof(sockaddr_in6, sin6_family) == 0); BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == 2); BOOST_STATIC_ASSERT(offsetof(sockaddr_in6, sin6_port) == 2); #if !(__GNUC_PREREQ (4,6)) #pragma GCC diagnostic ignored "-Winvalid-offsetof" #endif /* 这是几个构造方法 */ InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6) { BOOST_STATIC_ASSERT(offsetof(InetAddress, addr6_) == 0); BOOST_STATIC_ASSERT(offsetof(InetAddress, addr_) == 0); if (ipv6) { bzero(&addr6_, sizeof addr6_); addr6_.sin6_family = AF_INET6; in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any; addr6_.sin6_addr = ip; addr6_.sin6_port = sockets::hostToNetwork16(port); } else { bzero(&addr_, sizeof addr_); addr_.sin_family = AF_INET; in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; addr_.sin_addr.s_addr = sockets::hostToNetwork32(ip); addr_.sin_port = sockets::hostToNetwork16(port); } } InetAddress::InetAddress(StringArg ip, uint16_t port, bool ipv6) { if (ipv6) { bzero(&addr6_, sizeof addr6_); sockets::fromIpPort(ip.c_str(), port, &addr6_); } else { bzero(&addr_, sizeof addr_); sockets::fromIpPort(ip.c_str(), port, &addr_); } } // 构造结束 /* 返回套接字地址 ip 和 port 点分十进制的 */ string InetAddress::toIpPort() const { char buf[64] = ""; sockets::toIpPort(buf, sizeof buf, getSockAddr()); return buf; } /* 返回套接字地址的 ip 地址,点分十进制的 */ string InetAddress::toIp() const { char buf[64] = ""; sockets::toIp(buf, sizeof buf, getSockAddr()); return buf; } /* 返回套接字地址的ip */ uint32_t InetAddress::ipNetEndian() const { assert(family() == AF_INET); return addr_.sin_addr.s_addr; } /* 返回地址的端口*/ uint16_t InetAddress::toPort() const { return sockets::networkToHost16(portNetEndian()); } static __thread char t_resolveBuffer[64 * 1024]; bool InetAddress::resolve(StringArg hostname, InetAddress* out) { assert(out != NULL); struct hostent hent; struct hostent* he = NULL; int herrno = 0; bzero(&hent, sizeof(hent)); int ret = gethostbyname_r(hostname.c_str(), &hent, t_resolveBuffer, sizeof t_resolveBuffer, &he, &herrno); if (ret == 0 && he != NULL) { assert(he->h_addrtype == AF_INET && he->h_length == sizeof(uint32_t)); out->addr_.sin_addr = *reinterpret_cast<struct in_addr*>(he->h_addr); return true; } else { if (ret) { LOG_SYSERR << "InetAddress::resolve"; } return false; } }
SocketsOps
SocketsOps.h#ifndef MUDUO_NET_SOCKETSOPS_H #define MUDUO_NET_SOCKETSOPS_H #include <arpa/inet.h> namespace muduo { namespace net { namespace sockets { /// /// Creates a non-blocking socket file descriptor, /// abort if any error. int createNonblockingOrDie(sa_family_t family); int connect(int sockfd, const struct sockaddr* addr); void bindOrDie(int sockfd, const struct sockaddr* addr); void listenOrDie(int sockfd); int accept(int sockfd, struct sockaddr_in6* addr); ssize_t read(int sockfd, void *buf, size_t count); ssize_t readv(int sockfd, const struct iovec *iov, int iovcnt); ssize_t write(int sockfd, const void *buf, size_t count); void close(int sockfd); void shutdownWrite(int sockfd); void toIpPort(char* buf, size_t size, const struct sockaddr* addr); void toIp(char* buf, size_t size, const struct sockaddr* addr); void fromIpPort(const char* ip, uint16_t port, struct sockaddr_in* addr); void fromIpPort(const char* ip, uint16_t port, struct sockaddr_in6* addr); int getSocketError(int sockfd); const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr); const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); struct sockaddr* sockaddr_cast(struct sockaddr_in6* addr); const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr); const struct sockaddr_in6* sockaddr_in6_cast(const struct sockaddr* addr); struct sockaddr_in6 getLocalAddr(int sockfd); struct sockaddr_in6 getPeerAddr(int sockfd); bool isSelfConnect(int sockfd); } } } #endif // MUDUO_NET_SOCKETSOPS_H
SocketsOps.cc
#include <muduo/net/SocketsOps.h> #include <muduo/base/Logging.h> #include <muduo/base/Types.h> #include <muduo/net/Endian.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> // snprintf #include <strings.h> // bzero #include <sys/socket.h> #include <sys/uio.h> // readv #include <unistd.h> using namespace muduo; using namespace muduo::net; namespace { typedef struct sockaddr SA; #if VALGRIND || defined (NO_ACCEPT4) /* 设置 non-blocking 和 close-on-exec */ void setNonBlockAndCloseOnExec(int sockfd) { // non-block int flags = ::fcntl(sockfd, F_GETFL, 0); flags |= O_NONBLOCK; int ret = ::fcntl(sockfd, F_SETFL, flags); // FIXME check // close-on-exec flags = ::fcntl(sockfd, F_GETFD, 0); flags |= FD_CLOEXEC; ret = ::fcntl(sockfd, F_SETFD, flags); // FIXME check (void)ret; } #endif } /* * 隐式转换函数 types.h 中定义 * inline To implicit_cast(From const &f) * { * return f; * } */ const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in6* addr) { return static_cast<const struct sockaddr*>(implicit_cast<const void*>(addr)); } struct sockaddr* sockets::sockaddr_cast(struct sockaddr_in6* addr) { return static_cast<struct sockaddr*>(implicit_cast<void*>(addr)); } const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in* addr) { return static_cast<const struct sockaddr*>(implicit_cast<const void*>(addr)); } const struct sockaddr_in* sockets::sockaddr_in_cast(const struct sockaddr* addr) { return static_cast<const struct sockaddr_in*>(implicit_cast<const void*>(addr)); } const struct sockaddr_in6* sockets::sockaddr_in6_cast(const struct sockaddr* addr) { return static_cast<const struct sockaddr_in6*>(implicit_cast<const void*>(addr)); } /* 创建一个 socket 并设置non-blcoking和close-on-exec */ int sockets::createNonblockingOrDie(sa_family_t family) { #if VALGRIND int sockfd = ::socket(family, SOCK_STREAM, IPPROTO_TCP); if (sockfd < 0) { LOG_SYSFATAL << "sockets::createNonblockingOrDie"; } setNonBlockAndCloseOnExec(sockfd); #else int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); if (sockfd < 0) { LOG_SYSFATAL << "sockets::createNonblockingOrDie"; } #endif return sockfd; } /* bind */ void sockets::bindOrDie(int sockfd, const struct sockaddr* addr) { int ret = ::bind(sockfd, addr, static_cast<socklen_t>(sizeof(struct sockaddr_in6))); if (ret < 0) { LOG_SYSFATAL << "sockets::bindOrDie"; } } /* listen */ void sockets::listenOrDie(int sockfd) { int ret = ::listen(sockfd, SOMAXCONN); if (ret < 0) { LOG_SYSFATAL << "sockets::listenOrDie"; } } /* accept */ int sockets::accept(int sockfd, struct sockaddr_in6* addr) { socklen_t addrlen = static_cast<socklen_t>(sizeof *addr); #if VALGRIND || defined (NO_ACCEPT4) int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); setNonBlockAndCloseOnExec(connfd); #else int connfd = ::accept4(sockfd, sockaddr_cast(addr), &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); #endif if (connfd < 0) { /* 如果出错,先把 errno 保存起来 */ int savedErrno = errno; LOG_SYSERR << "Socket::accept"; switch (savedErrno) { case EAGAIN: case ECONNABORTED: case EINTR: case EPROTO: // ??? case EPERM: case EMFILE: // per-process lmit of open file desctiptor ??? // expected errors errno = savedErrno; //上述错误不致命,只保存起来就好 break; case EBADF: case EFAULT: case EINVAL: case ENFILE: case ENOBUFS: case ENOMEM: case ENOTSOCK: case EOPNOTSUPP: // unexpected errors //致命错误,直接 FATAL LOG_FATAL << "unexpected error of ::accept " << savedErrno; break; default: LOG_FATAL << "unknown error of ::accept " << savedErrno; break; } } return connfd; } /* connect */ int sockets::connect(int sockfd, const struct sockaddr* addr) { return ::connect(sockfd, addr, static_cast<socklen_t>(sizeof(struct sockaddr_in6))); } /* read */ ssize_t sockets::read(int sockfd, void *buf, size_t count) { return ::read(sockfd, buf, count); } /* readv 和 read 的区别在于,接受的数据可以填充到多个缓冲区 */ ssize_t sockets::readv(int sockfd, const struct iovec *iov, int iovcnt) { return ::readv(sockfd, iov, iovcnt); } /* write */ ssize_t sockets::write(int sockfd, const void *buf, size_t count) { return ::write(sockfd, buf, count); } /* close */ void sockets::close(int sockfd) { if (::close(sockfd) < 0) { LOG_SYSERR << "sockets::close"; } } /* shutdown 关闭"写"的方向 */ void sockets::shutdownWrite(int sockfd) { if (::shutdown(sockfd, SHUT_WR) < 0) { LOG_SYSERR << "sockets::shutdownWrite"; } } /* 提取出套接字地址的 ip 和 端口,点分十进制 */ void sockets::toIpPort(char* buf, size_t size, const struct sockaddr* addr) { toIp(buf,size, addr); size_t end = ::strlen(buf); const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); /* uint16_t 的整形数字由网络字节序转化为机器字节序 */ uint16_t port = sockets::networkToHost16(addr4->sin_port); assert(size > end); snprintf(buf+end, size-end, ":%u", port); } /* 提取出套接字地址的 ip 点分十进制 */ void sockets::toIp(char* buf, size_t size, const struct sockaddr* addr) { if (addr->sa_family == AF_INET) { assert(size >= INET_ADDRSTRLEN); const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); /* inet_ntop 将二进制整数转化为点分十进制 */ ::inet_ntop(AF_INET, &addr4->sin_addr, buf, static_cast<socklen_t>(size)); } else if (addr->sa_family == AF_INET6) { assert(size >= INET6_ADDRSTRLEN); const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); ::inet_ntop(AF_INET6, &addr6->sin6_addr, buf, static_cast<socklen_t>(size)); } } /* 从 ip 和 port 转化到 sockaddr_in 类型 */ void sockets::fromIpPort(const char* ip, uint16_t port, struct sockaddr_in* addr) { addr->sin_family = AF_INET; addr->sin_port = hostToNetwork16(port); if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) { LOG_SYSERR << "sockets::fromIpPort"; } } void sockets::fromIpPort(const char* ip, uint16_t port, struct sockaddr_in6* addr) { addr->sin6_family = AF_INET6; addr->sin6_port = hostToNetwork16(port); if (::inet_pton(AF_INET6, ip, &addr->sin6_addr) <= 0) { LOG_SYSERR << "sockets::fromIpPort"; } } /* 返回 socket 错误 */ int sockets::getSocketError(int sockfd) { int optval; socklen_t optlen = static_cast<socklen_t>(sizeof optval); if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) { return errno; } else { return optval; } } /* getsockname ,取得本地地址 */ struct sockaddr_in6 sockets::getLocalAddr(int sockfd) { struct sockaddr_in6 localaddr; bzero(&localaddr, sizeof localaddr); socklen_t addrlen = static_cast<socklen_t>(sizeof localaddr); if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) { LOG_SYSERR << "sockets::getLocalAddr"; } return localaddr; } /* getpeername,取得对端地址 */ struct sockaddr_in6 sockets::getPeerAddr(int sockfd) { struct sockaddr_in6 peeraddr; bzero(&peeraddr, sizeof peeraddr); socklen_t addrlen = static_cast<socklen_t>(sizeof peeraddr); if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) { LOG_SYSERR << "sockets::getPeerAddr"; } return peeraddr; } #if !(__GNUC_PREREQ (4,6)) #pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif /* 是否是自连接 判断本地端口地址是否和对端都相同 */ bool sockets::isSelfConnect(int sockfd) { struct sockaddr_in6 localaddr = getLocalAddr(sockfd); struct sockaddr_in6 peeraddr = getPeerAddr(sockfd); if (localaddr.sin6_family == AF_INET) { const struct sockaddr_in* laddr4 = reinterpret_cast<struct sockaddr_in*>(&localaddr); const struct sockaddr_in* raddr4 = reinterpret_cast<struct sockaddr_in*>(&peeraddr); return laddr4->sin_port == raddr4->sin_port && laddr4->sin_addr.s_addr == raddr4->sin_addr.s_addr; } else if (localaddr.sin6_family == AF_INET6) { return localaddr.sin6_port == peeraddr.sin6_port && memcmp(&localaddr.sin6_addr, &peeraddr.sin6_addr, sizeof localaddr.sin6_addr) == 0; } else { return false; } }
相关文章推荐
- [置顶] Muduo网络库源码分析之TcpConnection Class
- Muduo网络库源码分析(四)EventLoopThread和EventLoopThreadPool的封装
- [置顶] Muduo网络库源码分析之Reactor模式的关键结构
- [置顶]【Spring源码分析系列】ApplicationContext 相关接口架构分析
- 【CSAPP读书笔记】过程及其相关操作的分析(经典:包括函数调用过程详解)
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- [置顶] Muduo网络库源码分析之定时器的实现
- [Muduo网络库源码分析] (1) base/Atomic.h_原子操作与原子整数
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- [Muduo网络库源码分析] (2) base/Condition.cc_h_条件变量操作
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- Libevent源码分析-----与event相关的一些函数和操作
- [置顶] java常用集合类及其区别、源码分析(一)
- 结合源码分析HBase相关操作流程
- 结合源码分析HBase相关操作流程
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析
- ARM汇编中的ldr和adr的区别及其在uboot中相关源码的分析