31muduo_net库源码分析(七)
来源:互联网 发布:713中美南海对峙知乎 编辑:程序博客网 时间:2024/06/06 14:25
1.Socket封装
(1)Endian.h
封装了字节序转换函数(全局函数,位于muduo::net::sockets名称空间中)。
(2)SocketsOps.h/ SocketsOps.cc
封装了socket相关系统调用(全局函数,位于muduo::net::sockets名称空间中)。
(3)Socket.h/Socket.cc(Socket类)
用RAII方法封装socket file descriptor
(4)InetAddress.h/InetAddress.cc(InetAddress类)
网际地址sockaddr_in封装
2.代码
1.SocketsOps.h
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is an internal header file, you should not include this.#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();int connect(int sockfd, const struct sockaddr_in& addr);void bindOrDie(int sockfd, const struct sockaddr_in& addr);void listenOrDie(int sockfd);int accept(int sockfd, struct sockaddr_in* 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_in& addr);void toIp(char* buf, size_t size, const struct sockaddr_in& addr);void fromIpPort(const char* ip, uint16_t port, struct sockaddr_in* addr);int getSocketError(int sockfd);struct sockaddr_in getLocalAddr(int sockfd);struct sockaddr_in getPeerAddr(int sockfd);bool isSelfConnect(int sockfd);}}}#endif // MUDUO_NET_SOCKETSOPS_H
2.SocketsOps.cc
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#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 <unistd.h>using namespace muduo;using namespace muduo::net;namespace{typedef struct sockaddr SA;const SA* sockaddr_cast(const struct sockaddr_in* addr){ return static_cast<const SA*>(implicit_cast<const void*>(addr));}SA* sockaddr_cast(struct sockaddr_in* addr){ return static_cast<SA*>(implicit_cast<void*>(addr));}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;}}int sockets::createNonblockingOrDie(){ // socket#if VALGRIND int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockfd < 0) { LOG_SYSFATAL << "sockets::createNonblockingOrDie"; } setNonBlockAndCloseOnExec(sockfd);#else // Linux 2.6.27以上的内核支持SOCK_NONBLOCK与SOCK_CLOEXEC int sockfd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); if (sockfd < 0) { LOG_SYSFATAL << "sockets::createNonblockingOrDie"; }#endif return sockfd;}void sockets::bindOrDie(int sockfd, const struct sockaddr_in& addr){ int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr); if (ret < 0) { LOG_SYSFATAL << "sockets::bindOrDie"; }}void sockets::listenOrDie(int sockfd){ int ret = ::listen(sockfd, SOMAXCONN); if (ret < 0) { LOG_SYSFATAL << "sockets::listenOrDie"; }}int sockets::accept(int sockfd, struct sockaddr_in* addr){ socklen_t addrlen = sizeof *addr;#if VALGRIND 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) { 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 LOG_FATAL << "unexpected error of ::accept " << savedErrno; break; default: LOG_FATAL << "unknown error of ::accept " << savedErrno; break; } } return connfd;}int sockets::connect(int sockfd, const struct sockaddr_in& addr){ return ::connect(sockfd, sockaddr_cast(&addr), sizeof addr);}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);}ssize_t sockets::write(int sockfd, const void *buf, size_t count){ return ::write(sockfd, buf, count);}void sockets::close(int sockfd){ if (::close(sockfd) < 0) { LOG_SYSERR << "sockets::close"; }}// 只关闭写的这一半void sockets::shutdownWrite(int sockfd){ if (::shutdown(sockfd, SHUT_WR) < 0) { LOG_SYSERR << "sockets::shutdownWrite"; }}void sockets::toIpPort(char* buf, size_t size, const struct sockaddr_in& addr){ char host[INET_ADDRSTRLEN] = "INVALID"; toIp(host, sizeof host, addr); uint16_t port = sockets::networkToHost16(addr.sin_port); snprintf(buf, size, "%s:%u", host, port);}void sockets::toIp(char* buf, size_t size, const struct sockaddr_in& addr){ assert(size >= INET_ADDRSTRLEN); ::inet_ntop(AF_INET, &addr.sin_addr, buf, static_cast<socklen_t>(size));}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"; }}int sockets::getSocketError(int sockfd){ int optval; socklen_t optlen = sizeof optval; if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) { return errno; } else { return optval; }}struct sockaddr_in sockets::getLocalAddr(int sockfd){ struct sockaddr_in localaddr; bzero(&localaddr, sizeof localaddr); socklen_t addrlen = sizeof(localaddr); if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) { LOG_SYSERR << "sockets::getLocalAddr"; } return localaddr;}struct sockaddr_in sockets::getPeerAddr(int sockfd){ struct sockaddr_in peeraddr; bzero(&peeraddr, sizeof peeraddr); socklen_t addrlen = sizeof(peeraddr); if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) { LOG_SYSERR << "sockets::getPeerAddr"; } return peeraddr;}// 自连接是指(sourceIP, sourcePort) = (destIP, destPort)// 自连接发生的原因:// 客户端在发起connect的时候,没有bind(2)// 客户端与服务器端在同一台机器,即sourceIP = destIP,// 服务器尚未开启,即服务器还没有在destPort端口上处于监听// 就有可能出现自连接,这样,服务器也无法启动了bool sockets::isSelfConnect(int sockfd){ struct sockaddr_in localaddr = getLocalAddr(sockfd); struct sockaddr_in peeraddr = getPeerAddr(sockfd); return localaddr.sin_port == peeraddr.sin_port && localaddr.sin_addr.s_addr == peeraddr.sin_addr.s_addr;}
3.Socket.h
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is an internal header file, you should not include this.#ifndef MUDUO_NET_SOCKET_H#define MUDUO_NET_SOCKET_H#include <boost/noncopyable.hpp>namespace muduo{////// TCP networking.///namespace net{class InetAddress;////// Wrapper of socket file descriptor.////// It closes the sockfd when desctructs./// It's thread safe, all operations are delagated to OS.class Socket : boost::noncopyable{ public: explicit Socket(int sockfd) : sockfd_(sockfd) { } // Socket(Socket&&) // move constructor in C++11 ~Socket(); int fd() const { return sockfd_; } /// abort if address in use void bindAddress(const InetAddress& localaddr); /// abort if address in use 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. int accept(InetAddress* peeraddr); void shutdownWrite(); /// /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). /// // Nagle算法可以一定程度上避免网络拥塞 // TCP_NODELAY选项可以禁用Nagle算法 // 禁用Nagle算法,可以避免连续发包出现延迟,这对于编写低延迟的网络服务很重要 void setTcpNoDelay(bool on); /// /// Enable/disable SO_REUSEADDR /// void setReuseAddr(bool on); /// /// Enable/disable SO_KEEPALIVE /// // TCP keepalive是指定期探测连接是否存在,如果应用层有心跳的话,这个选项不是必需要设置的 void setKeepAlive(bool on); private: const int sockfd_;};}}#endif // MUDUO_NET_SOCKET_H
4.Socket.cc
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/net/Socket.h>#include <muduo/net/InetAddress.h>#include <muduo/net/SocketsOps.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <strings.h> // bzerousing namespace muduo;using namespace muduo::net;Socket::~Socket(){ sockets::close(sockfd_);}void Socket::bindAddress(const InetAddress& addr){ sockets::bindOrDie(sockfd_, addr.getSockAddrInet());}void Socket::listen(){ sockets::listenOrDie(sockfd_);}int Socket::accept(InetAddress* peeraddr){ struct sockaddr_in addr; bzero(&addr, sizeof addr); int connfd = sockets::accept(sockfd_, &addr); if (connfd >= 0) { peeraddr->setSockAddrInet(addr); } return connfd;}void Socket::shutdownWrite(){ sockets::shutdownWrite(sockfd_);}void Socket::setTcpNoDelay(bool on){ int optval = on ? 1 : 0; ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof optval); // FIXME CHECK}void Socket::setReuseAddr(bool on){ int optval = on ? 1 : 0; ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval); // FIXME CHECK}void Socket::setKeepAlive(bool on){ int optval = on ? 1 : 0; ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof optval); // FIXME CHECK}
5.InetAddress.h
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is a public header file, it must only include public header files.#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{////// Wrapper of sockaddr_in.////// This is an POD interface class.class InetAddress : public muduo::copyable{ public: /// Constructs an endpoint with given port number. /// Mostly used in TcpServer listening. // 仅仅指定port,不指定ip,则ip为INADDR_ANY(即0.0.0.0) explicit InetAddress(uint16_t port); /// Constructs an endpoint with given ip and port. /// @c ip should be "1.2.3.4" InetAddress(const StringPiece& ip, uint16_t port); /// Constructs an endpoint with given struct @c sockaddr_in /// Mostly used when accepting new connections InetAddress(const struct sockaddr_in& addr) : addr_(addr) { } string toIp() const; string toIpPort() const; // __attribute__ ((deprecated)) 表示该函数是过时的,被淘汰的 // 这样使用该函数,在编译的时候,会发出警告 string toHostPort() const __attribute__ ((deprecated)) { return toIpPort(); } // default copy/assignment are Okay const struct sockaddr_in& getSockAddrInet() const { return addr_; } void setSockAddrInet(const struct sockaddr_in& addr) { addr_ = addr; } uint32_t ipNetEndian() const { return addr_.sin_addr.s_addr; } uint16_t portNetEndian() const { return addr_.sin_port; } private: struct sockaddr_in addr_;};}}#endif // MUDUO_NET_INETADDRESS_H
6.InetAddress.cc
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/net/InetAddress.h>#include <muduo/net/Endian.h>#include <muduo/net/SocketsOps.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;#pragma GCC diagnostic error "-Wold-style-cast"// /* Structure describing an Internet socket address. */// struct sockaddr_in {// sa_family_t sin_family; /* address family: AF_INET */// uint16_t sin_port; /* port in network byte order */// struct in_addr sin_addr; /* internet address */// };// /* Internet address. */// typedef uint32_t in_addr_t;// struct in_addr {// in_addr_t s_addr; /* address in network byte order */// };using namespace muduo;using namespace muduo::net;BOOST_STATIC_ASSERT(sizeof(InetAddress) == sizeof(struct sockaddr_in));InetAddress::InetAddress(uint16_t port){ bzero(&addr_, sizeof addr_); addr_.sin_family = AF_INET; addr_.sin_addr.s_addr = sockets::hostToNetwork32(kInaddrAny); addr_.sin_port = sockets::hostToNetwork16(port);}InetAddress::InetAddress(const StringPiece& ip, uint16_t port){ bzero(&addr_, sizeof addr_); sockets::fromIpPort(ip.data(), port, &addr_);}string InetAddress::toIpPort() const{ char buf[32]; sockets::toIpPort(buf, sizeof buf, addr_); return buf;}string InetAddress::toIp() const{ char buf[32]; sockets::toIp(buf, sizeof buf, addr_); return buf;}
7.InetAddress_unittest.cc
#include <muduo/net/InetAddress.h>//#define BOOST_TEST_MODULE InetAddressTest#define BOOST_TEST_MAIN#define BOOST_TEST_DYN_LINK#include <boost/test/unit_test.hpp>using muduo::string;using muduo::net::InetAddress;BOOST_AUTO_TEST_CASE(testInetAddress){ InetAddress addr1(1234); BOOST_CHECK_EQUAL(addr1.toIp(), string("0.0.0.0")); BOOST_CHECK_EQUAL(addr1.toIpPort(), string("0.0.0.0:1234")); InetAddress addr2("1.2.3.4", 8888); BOOST_CHECK_EQUAL(addr2.toIp(), string("1.2.3.4")); BOOST_CHECK_EQUAL(addr2.toIpPort(), string("1.2.3.4:8888")); InetAddress addr3("255.255.255.255", 65535); BOOST_CHECK_EQUAL(addr3.toIp(), string("255.255.255.255")); BOOST_CHECK_EQUAL(addr3.toIpPort(), string("255.255.255.255:65535"));}
8.Endian.h
// Copyright 2010, Shuo Chen. All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is a public header file, it must only include public header files.#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 __GNUC_MINOR__ >= 6#pragma GCC diagnostic push#endif#pragma GCC diagnostic ignored "-Wconversion"#pragma GCC diagnostic ignored "-Wold-style-cast"inline uint64_t hostToNetwork64(uint64_t host64){ return htobe64(host64);}inline uint32_t hostToNetwork32(uint32_t host32){ return htobe32(host32);}inline uint16_t hostToNetwork16(uint16_t host16){ return htobe16(host16);}inline uint64_t networkToHost64(uint64_t net64){ return be64toh(net64);}inline uint32_t networkToHost32(uint32_t net32){ return be32toh(net32);}inline uint16_t networkToHost16(uint16_t net16){ return be16toh(net16);}#if __GNUC_MINOR__ >= 6#pragma GCC diagnostic pop#else#pragma GCC diagnostic error "-Wconversion"#pragma GCC diagnostic error "-Wold-style-cast"#endif}}}#endif // MUDUO_NET_ENDIAN_H
阅读全文
1 0
- 31muduo_net库源码分析(七)
- muduo_net库源码分析
- EpollPoller --- muduo_net库源码分析(27)
- 25muduo_net库源码分析(一)
- 26muduo_net库源码分析(二)
- 27muduo_net库源码分析(三)
- 28muduo_net库源码分析(四)
- 29muduo_net库源码分析(五)
- 30muduo_net库源码分析(六)
- 32muduo_net库源码分析(八)
- 33muduo_net库源码分析(九)
- 34muduo_net库源码分析(十)
- muduo_net库源码分析(25)
- muduo_net库源码分析(25)
- muduo_net库源码分析(26-1
- 高并发服务器架构笔记(4)——muduo_net 源码分析
- 16muduo_base库源码分析(七)
- openMPM源码分析(七)
- Hadoop生态系统
- 初学Java
- 服务器等待 socket 连接时的心理活动
- 侧拉横滑相关的小demo
- halcon制作标定板
- 31muduo_net库源码分析(七)
- 欢迎使用CSDN-markdown编辑器
- Python爬虫,爬取百度百科词条
- doxygen使用与C++注释规范
- 05.Spring Cloud学习笔记之服务容错保护组件Hystrix
- 第2课:HLS 的工作机制
- hdu2063(二分图匹配 匈牙利算法模板题)
- 请求网页图片
- HDU