muduo库的Socket封装

307-重写C++muduo库(Socket封装fd) Socket封装fd 这3部分代表Reactor模型的Reactor反应堆和Demultiplex事件分发器; 经典的one loop per thread网络模型 : 一个线程中创建了一个绑定线程的EventLoop,one loop per thread muduo库是一个Multiple Reactors模型: 可以通过setThreadNumber来设置底层的线程数量,一个IO线程(mainReactor)和 多个工作线程(subReactor)。 *** Acceptor: 处理 阅读详情


主要来看一下几个部分:

1.Endian.h

封装了字节序转换函数(全局函数,位于muduo::net::sockets名称空间中)

2.SocketsOps.h/SocketOps.cc

封装了socket相关的系统调用(全局函数,位于muduo::net::sockets名称空间中)

3.Socket.h/Socket.cc(Socket类)

用RAII方法封装socket file descriptor

4.InetAddress.h/InetAddress.cc(InetAddress类)

网际地址sockaddr_in封装


一:Endia.h模块

muduo主要采用htobe()函数,将主机字节序转化为网路字节序,只能在Linux标准中使用。而htonl和htons同时可以在windows中使用。


二:SocketOps模块

封装了socket操作,比较简单,直接给源码注释。

头文件如下:
#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
实现文件如下:
typedef struct sockaddr SA;


//设置nonblock和closeexec
#if VALGRIND || defined (NO_ACCEPT4)
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中定义
template<typename To, typename From>
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));
}

//创建非阻塞套接字
int sockets::createNonblockingOrDie(sa_family_t family)
{
#if VALGRIND
  int sockfd = ::socket(family, SOCK_STREAM, IPPROTO_TCP);
  if (sockfd < 0)
  {
    LOG_SYSFATAL << "sockets::createNonblockingOrDie";
  }

	//设置非阻塞和close on exec
  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 number,所以先把它保存起来。
    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;
}

int sockets::connect(int sockfd, const struct sockaddr* addr)
{
  return ::connect(sockfd, addr, static_cast<socklen_t>(sizeof(struct sockaddr_in6)));
}

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";
  }
}

//将地址转化为ip和port的字符串放在buffer中,点分十进制
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 port = sockets::networkToHost16(addr4->sin_port);
  assert(size > end);
  snprintf(buf+end, size-end, ":%u", port);
}

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(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转化sockadd_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;
}

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;
  }
}


三: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;

///
/// Wrapper of socket file descriptor.
///
/// It closes the sockfd when desctructs.
/// It's thread safe, all operations are delegated 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_; }
  // return true if success.
  bool getTcpInfo(struct tcp_info*) const;
  bool getTcpInfoString(char* buf, int len) const;

  /// 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).
  ///
  void setTcpNoDelay(bool on);

  ///
  /// Enable/disable SO_REUSEADDR
  ///
  void setReuseAddr(bool on);

  ///
  /// Enable/disable SO_REUSEPORT
  ///
  void setReusePort(bool on);

  ///
  /// Enable/disable SO_KEEPALIVE
  ///
  void setKeepAlive(bool on);

 private:
  const int sockfd_;
};

}
}
#endif  // MUDUO_NET_SOCKET_H

实现文件:
//使用RAII机制封装,不会忘记关闭文件描述符
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;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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_);
}

//Nagle算法可以一定程度上避免网络拥塞,实际上就是延迟小的数据包,等待后续的数据包合并一次发送。
//TCP_NODELAY选项可以禁用Nagle算法,不等待
//禁用Nagle算法,可以避免连续发包出现延迟,这对于编写低延迟的网络服务很重要
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
}



endian.h文件 windows编译probuf扩展时vs会缺少endian.h包,只需将这个文件包含在项目目录中即可通过编译 立即下载

相关推荐

endian:用于操作字节序的 C++ 头文件库

字节序 用于字节序检测和操作的 C++ 头文件库 从stackoverflow上的可爱评论中提取 用于处理大端格式和小端格式之间的转换的仅标头库 (endian.h)。 它包括系统字节序的运行时检查。 使用它来强制大端: int64_t j = to_big_endian<int64>(i); 或者,强制为小端: int64_t j = to_little_endian<int64>(i); 或者首先检测您是否需要交换字节顺序: bool should_swap = IsBigEndian(); /* ... */ if (should_swap) { i = swap_endian<int64>(i); } 添加一名作者 许可证:麻省理工学院

c语言中.h文件中的宏定义,endian.h这个头文件里面的宏可以直接用么?

该楼层疑似违规已被系统折叠隐藏此楼查看此楼endian.h头文件中以宏的形式定义了大端字节序、小端字节序和混合字节序#define __LITTLE_ENDIAN 1234#define __BIG_ENDIAN   4321#define __PDP_ENDIAN   3412并且宏__BYTE_ORDER确定了当下机器所采用的字节序,根据描述,这个宏定义在头文件bits/endian.h中/...

weixin_29284201的博客 1384

endian.h:C的可移植字节序转换功能

字节序 这在Windows,Linux,* BSD和Mac OS X上提供了endian.h的endian转换功能。gcc仍需要使用-std=gnu99而不是-std=c99 。 这些函数实际上可能是宏。 功能:htobe16,htole16,be16toh,le16toh,htobe32,htole32,be32toh,le32toh,htobe64,htole64,be64toh,le64toh。 该实现由MathiasPanzenböck编写,并在本发布。 安装 使用[clib(1)]安装: clib install mikepb/endian.h 用法 # include < stdint> # include " endian.h " uint32_t endian32 ( const uint32_t i) { return be32toh (i); } 执照

gcc中高效的位操作内联函数(endian.h)

x86机器本机是小端序,在endian.h中有定义如下: /* i386/x86_64 are little-endian. */ #define __BYTE_ORDER __LITTLE_ENDIAN 对于位的翻转操作定义如下: # if __BYTE_ORDER == __LITTLE_ENDIAN # define htobe16(x) __bswap_16 (x) # ...

dong_beijing的博客 5062

【Android】条形码/二维码扫描——ZXing源码分析

正在更新中 针对3.2.1版本源码 与其他版本代码可能会有出入,但核心思想基本不变。 首先从com.google.zxing.client.android包中的目录结构分析:Book:这个文件夹中有5个类: BrowseBookListener 实现了adapter的点击事项响应,通过获取ISBN,然后跳转到Google books中查询响应的详细信息。 SearchBookContents

年轻的学徒 2453

CSP历年真题201503-1-图像旋转(C/C++)

一、问题描述 旋转是图像处理的基本操作,在这个问题中,你需要将一个图像逆时针旋转90度。 计算机中的图像表示可以用一个矩阵来表示,为了旋转一个图像,只需要将对应的矩阵旋转即可。 输入格式 二、输入格式 输入的第一行包含两个整数n, m,分别表示图像矩阵的行数和列数。 接下来n行每行包含m个整数,表示输入的图像。 三、输出格式 输出m行,每行包含n个整数,表示原始矩阵逆时针旋转90度后的矩阵。 四、...

GTboy100的博客 1671

(P31)muduo_base库源码分析:Socket封装

文章目录1.Socket封装 1.Socket封装 Endian.h 封装了字节序转换函数(全局函数,位于muduo::net::sockets名称空间中)。 SocketsOps.h/ SocketsOps.cc 封装了socket相关系统调用(全局函数,位于muduo::net::sockets名称空间中)。 Socket.h/Socket.cc(Socket类) 用RAII方法封装socket file descriptor InetAddress.h/InetAddress.cc(I

喜欢打篮球的普通人 378

Win10下Delphi 10.4.2 (RAD Studio 10.4.2 )安装教程图解

Win10下Delphi 10.4.2 (RAD Studio 10.4.2 )安装和破解教程图解

1万+

muduo库 --socket的封装

Linux高性能网络编程:Socket封装与muduo网络库核心思想 摘要 本文介绍了Linux高性能网络编程中Socket的基础封装方法,为学习muduo网络库奠定基础。主要内容包括: Socket通信的基本概念和工作原理 关键API的封装实现: 创建套接字(socket) 绑定地址(bind) 监听连接(listen) 连接管理(connect/accept) 数据收发(recv/send) 非阻塞和套接字复用设置 客户端和服务器的快速创建方法 文章通过代码示例详细展示了每个核心功能的实现逻辑,包括错误

2301_80127108的博客 224

飞腾UEFI配置GPIO—飞腾FT2000/4 (D2000/8) GPIO引脚配置及使用

讲解了在飞腾UEFI代码中如何添加GPIO配置相关代码,并以GPIO1_B0—B7为例,将这8个引脚配置为GPIO工作模式并默认输出低电平

qq_30135687的博客 5350

基于AI大模型实现自然语言转SQL、SQL解释、SQL优化和SQL转换

随着大数据和人工智能技术的发展,数据分析和数据挖掘在各行各业中的应用越来越广泛。SQL(Structured Query Language)作为关系数据库的查询语言,是数据分析的重要工具。然而,SQL语言的复杂性和专业性使得许多非技术背景的用户难以直接使用,阻碍了数据的广泛利用。为了降低SQL的使用门槛,许多研究者和企业开始探索如何通过自然语言处理(NLP)技术,将自然语言转化为SQL查询语句,从而让用户可以通过自然语言与数据库进行交互。

AI天才研究院 2240

483-手写C++muduo库(socket封装fd,Acceptor)

我们在之前已经完成了对前面5个模块的剖析和重写。 现在我们看Acceptor Acceptor就是处理accept,监听新用户的连接,拿到跟客户端通信的clientfd,打包成channel,根据muduo的轮询算法找一个subloop,把subloop唤醒,把接收的channel给subloop。 我们打开TCPServer,处理一下Acceptor Acceptor运行在我们的baseloop(mainreactor)里面 封装了socket socket封装fd Socket.h #pra.

LINZEYU666的博客 506

【AI智能体】基于OpenCode 搭建Skills环境与项目实战开发详解

基于OpenCode 搭建Skills环境与项目实战开发详解

congge 8903

仿muduo库实现高并发服务器—Socket封装

1024MAX_LISTEN是监听队列的最大长度,也就是listen()的第二个参数backlog。1024 表示内核为这个监听 socket 维护的已完成连接队列和未完成连接队列之和的最大值。简单说就是:最多允许有多少个客户端同时等待被accept()。private :_sockfd就是保存 socket 文件描述符的成员变量。Linux 中 socket 也是一个文件,所以它用一个整数 fd 来表示。

hehelm的博客 400

FPGA电路设计1——芯片原理图和封装制作流程

本文详细介绍了FPGA电路板设计的学习过程,以Xilinx Kintex-7系列FPGA为例。主要内容包括:1)从官网下载芯片引脚分配文件的方法;2)原理图库绘制流程,重点讲解Bank划分(配置Bank、HR/HP IO Bank、高速收发器Bank)及利用Excel预处理数据;3)使用Altium Designer的Symbol Wizard工具实现引脚自动化导入;4)原理图设计要点,包括电源系统设计(多电压需求与上电时序)、配置电路(JTAG/Flash接口)和时钟设计。

在读研究生,FPGA电路设计与功能开发。 1387

基于四旋翼模型的火箭型无人机视线角保持控制仿真设计

本文针对火箭型无人机的视线角保持控制问题展开研究。基于四旋翼动力学模型,通过改造设计了一种摄像头朝上安装的特殊无人机系统,用于追踪空中目标。文章详细推导了坐标系定义、运动学和动力学方程,重点分析了摄像头安装与视线几何关系,建立了目标运动模型和视线向量计算方法。通过解算期望姿态角,实现了使机体Z轴始终对准目标的控制目标。仿真结果表明,该系统能有效完成视线角保持任务,为空对空监视等应用场景提供了可行方案。~~~~~

huanghm88的专栏 143

muduo库net源码分析六(Socket 封装)

SocketsOps.h/ SocketsOps.cc 封装了socket相关系统调用(全局函数,位于muduo::net::sockets名称空间中)。 Socket.h/Socket.cc(Socket类) 用RAII方法封装socket file descriptor。 InetAddress.h/InetAddress.cc(InetAddress类) 网际地址sockaddr_in封装 Endian.h 封装了字节序转换函数(全局函数,位于muduo::net::sockets名..

侯彩桦 439

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

muduo库net源码分析七(Socket 封装)

Acceptor用于accept(2)接受TCP连接 Acceptor的数据成员包括Socket、Channel,Acceptor的socket是listening socket(即server socket)。Channel用于观察此socket的readable事件,并回调Accptor::handleRead(),后者调用accept(2)来接受新连接,并回调用户callback。 Acceptor 示例 void newConnection(int sockfd, const InetAd

侯彩桦 195

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

muduo学习笔记:net部分之Socket、SocketsOpts和InetAddress

muduo实现非阻塞的TCP连接,对socket相关内容进行了非常详尽的封装,主要封装Socket、SocketsOpts和InetAddress。另外在Socket使用了Endian的跨平台使用的大小端转换函数。 有关socket网络编程更详尽的介绍和使用,可以参考专栏【socket网络编程】。 1、Socket Socket类是封装了socket文件描述符的类,通过RAII实现了声明周期的管理,在对象析构时自动关闭socket描述符。该类仅提接口,具体操作均封装在了SocketsOpts中。 class

热爱生活,忠于自己 678

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

muduo网络库源码剖析系列

1.muduo源码剖析专栏 注: 此系列来自于专栏:https://blog.csdn.net/FreeeLinux/column/info/13805 muduo库的Socket封装 muduo库的Acceptor类剖析 muduo库的TcpServer和TcpConnection用法 muduo应用层缓冲区设计 muduo库TcpConnection对send、shutdown、SIGPIP...

qq_40028201的博客 1031

[muduo网络库]——muduo库Socket类,Acceptor类,Connector类

Socket类实际上就是封装套接字socket fd,请参考游双《Linux高性能服务器编程》第五章用于接受TCP连接, 它是TcpServer的成员,生命期由后者控制。Acceptor类用于创建套接字socket,接受新客户端连接并分发连接给SubReactor(SubEventLoop)用于发起TCP连接, 它是TcpClient的成员,生命期由后者控制。它负责主动发起连接,不负责创建socket,只负责连接的建立,和Acceptor类恰好相反。Connector。

weixin_45807759的博客 1535

【Muduo】套接字:InetAddress、Socket

在 Muduo中,InetAddress和Socket是偏向底层的两个模块,封装了底层的一些系统调用,提供了好用的接口。

qq_20756957的博客 516

muduo库分析——net篇(4)Socket相关

muduo将Socket中系统调用封装在sockets命名空间中,这是对socket各种操作的一种抽象socket本身的一些操作比如bind,accept等等单独抽象成一个socket类由于在linux下,有各种socket地址结构体,因此 还有专门的InetAddress地址器先看SocketsOps文件,这是socket底层操作的封装创建一个socketint sockets::createN...

renhaopeng的博客 726

1.muduo之Socket类

前言:每篇阅读某个类的文章,我都会将头文件放在第一部分注释,cc文件放在第二部注释。仅当作我作为学习muduo库的记录。 该类主要作用:Socket类其实就是对于一个调用过socket()函数所生成的文件描述符sockfd的一个封装,该类里面主要实现了bind()和listen()函数的功能,还有accpet()。还可设置sockfd的各种属性,比如开启Nagle算法,保活机制等, 1. Socket.h头文件 /// sockfd的封装类 /// 销毁对象时会关闭sockfd /// 该类是线程安全的,所

qq_42987442的博客 367

muduo库的Connector以及TcpClient的使用

一:Connector     Connector可以说是muduo库的连接器,负责客户端向服务器发起连接。实际上说白了就是封装了socket的connect操作。      Connector类的成员如下: class Connector : boost::noncopyable, public boost::enable_shared_from_th

FreeeLinux's blog 2081
上一篇: 判断tl树中是否有与t2树拓扑结构完全相同的子树
下一篇: muduo库的Acceptor类剖析
FreeeLinux
博客等级 码龄11年 421粉丝 356原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值