muduo源码剖析之SocketOps类

news/2025/2/12 23:50:58/
SocketOps

对socket设置API的封装

比较简单,已经编写注释

// 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.
//创建一个非阻塞的socket
int createNonblockingOrDie(sa_family_t family);//调用socket的connect函数连接服务端
int  connect(int sockfd, const struct sockaddr* addr);//调用socket的bind函数绑定
void bindOrDie(int sockfd, const struct sockaddr* addr);//调用socket套接字的listrn函数
void listenOrDie(int sockfd);//接收一个连接并设置非阻塞
int  accept(int sockfd, struct sockaddr_in6* addr);//调用socket套接字read函数
ssize_t read(int sockfd, void *buf, size_t count);//调用socket套接字readv函数(分块读)
ssize_t readv(int sockfd, const struct iovec *iov, int iovcnt);//调用socket套接字write函数
ssize_t write(int sockfd, const void *buf, size_t count);//调用socket套接字close关闭套接字函数
void close(int sockfd);//调用shutdown函数优雅关闭写端
void shutdownWrite(int sockfd);//将将addr参数中的ip地址转换为点分十进制的字符串,
//并获取port端口号,
//将数据写入buf参数
void toIpPort(char* buf, size_t size,const struct sockaddr* addr);//将addr参数中的ip地址转换为点分十进制的字符串写入buf参数
void toIp(char* buf, size_t size,const struct sockaddr* addr);//这是ipv4/ipv6版本
//将ip和port赋值给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);//sockaddr结构体转换函数
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);//获取本地或者远程的套接字地址信息,包括远程 IP 地址和端口号
struct sockaddr_in6 getLocalAddr(int sockfd);
struct sockaddr_in6 getPeerAddr(int sockfd);//判断是不是本地连接
bool isSelfConnect(int sockfd);}  // namespace sockets
}  // namespace net
}  // namespace muduo#endif  // MUDUO_NET_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)#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 <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)
void setNonBlockAndCloseOnExec(int sockfd)
{// non-blockint flags = ::fcntl(sockfd, F_GETFL, 0);flags |= O_NONBLOCK;int ret = ::fcntl(sockfd, F_SETFL, flags);// FIXME check// close-on-execflags = ::fcntl(sockfd, F_GETFD, 0);flags |= FD_CLOEXEC;ret = ::fcntl(sockfd, F_SETFD, flags);// FIXME check(void)ret;
}
#endif}  // namespaceconst 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//创建一个socketint sockfd = ::socket(family, SOCK_STREAM, IPPROTO_TCP);if (sockfd < 0){LOG_SYSFATAL << "sockets::createNonblockingOrDie";}//设置socket为非阻塞setNonBlockAndCloseOnExec(sockfd);
#elseint sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);if (sockfd < 0){LOG_SYSFATAL << "sockets::createNonblockingOrDie";}
#endifreturn sockfd;
}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";}
}void sockets::listenOrDie(int sockfd)
{int ret = ::listen(sockfd, SOMAXCONN);if (ret < 0){LOG_SYSFATAL << "sockets::listenOrDie";}
}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);
#elseint connfd = ::accept4(sockfd, sockaddr_cast(addr),&addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
#endifif (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 errorserrno = savedErrno;break;case EBADF:case EFAULT:case EINVAL:case ENFILE:case ENOBUFS:case ENOMEM:case ENOTSOCK:case EOPNOTSUPP:// unexpected errorsLOG_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);
}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* addr)
{//如果ip是ipv6if (addr->sa_family == AF_INET6){buf[0] = '[';//先转换ip地址toIp(buf+1, size-1, addr);size_t end = ::strlen(buf);const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr);//将端口号从网络字节序转换为本机字节序,再将其写人bufuint16_t port = sockets::networkToHost16(addr6->sin6_port);assert(size > end);snprintf(buf+end, size-end, "]:%u", port);return;}//如果走到这里,那么这是一个ipv4//先转换ip地址toIp(buf, size, addr);size_t end = ::strlen(buf);const struct sockaddr_in* addr4 = sockaddr_in_cast(addr);//将端口号从网络字节序转换为本机字节序,再将其写人bufuint16_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)
{//判断ipv4if (addr->sa_family == AF_INET){assert(size >= INET_ADDRSTRLEN);const struct sockaddr_in* addr4 = sockaddr_in_cast(addr);//网络字节序转换为点分十进制表示的 IPv4 或 IPv6 地址。写入buf::inet_ntop(AF_INET, &addr4->sin_addr, buf, static_cast<socklen_t>(size));}//判断ipv6else 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));}
}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";}
}int sockets::getSocketError(int sockfd)
{int optval;socklen_t optlen = static_cast<socklen_t>(sizeof optval);//获取当前套接口的错误状态。填入optlen参数if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0){return errno;}else{return optval;}
}struct sockaddr_in6 sockets::getLocalAddr(int sockfd)
{struct sockaddr_in6 localaddr;memZero(&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;
}struct sockaddr_in6 sockets::getPeerAddr(int sockfd)
{struct sockaddr_in6 peeraddr;memZero(&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);//如果这是一个ipv4if (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);//判断本地和远端的ip和port是否相同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;}
}

http://www.ppmy.cn/news/1201362.html

相关文章

MapReduce:大数据处理的范式

一、介绍 在当今的数字时代&#xff0c;生成和收集的数据量正以前所未有的速度增长。这种数据的爆炸式增长催生了大数据领域&#xff0c;传统的数据处理方法往往不足。MapReduce是一个编程模型和相关框架&#xff0c;已成为应对大数据处理挑战的强大解决方案。本文探讨了MapRed…

RK3568平台 内存的基本概念

一.Linux的Page Cache page cache&#xff0c;又称pcache&#xff0c;其中文名称为页高速缓冲存储器&#xff0c;简称页高缓。page cache的大小为一页&#xff0c;通常为4K。在linux读写文件时&#xff0c;它用于缓存文件的逻辑内容&#xff0c;从而加快对磁盘上映像和数据的访…

五:ffmpe主要参数的使用

目录 一&#xff1a;回顾一下主要参数 二&#xff1a;使用主要参数操作视频 1、-i 输入流的使用 2、-i 配合 输出流-f使用 三、使用-ss开始时间进行转换 四、使用-t参数&#xff0c;设置转换的时长 一&#xff1a;回顾一下主要参数 -i 设定输入流。 支持本地和网络流 -f …

webpack 的 Loader 和 Plugin 的区别,常见的 loader 和 plugin 有哪些?

结论先行&#xff1a; 1、 Loader 和 Plugin 的区别 Loader 也叫做就是“加载器”&#xff0c;因为 webpack 原生只能解析 js 文件&#xff0c;而对于其他类型文件&#xff0c;则需要借助 loader。所以 loader 的作用就是实现对不同格式文件的解析和处理&#xff0c;例如把 E…

金蝶云星空的网络控制设置

文章目录 金蝶云星空的网络控制设置说明网控参数加入网络控制清除网络控制清除网络控制&#xff08;单个&#xff09;清除网络控制&#xff08;批量&#xff09;清除网络控制&#xff08;批量&#xff0c;参数是拼接好的业务对象&#xff09; 金蝶云星空的网络控制设置 说明 …

汽车电子中的深力科推荐一款汽车用功率MOSFET NVTFS6H888NLTAG N沟道

NVTFS6H888NLTAG MOSFET是符合AEC-Q101标准的汽车用功率MOSFET&#xff0c;采用WDFN-8封装&#xff0c;实现紧凑设计。具有低QG和电容&#xff08;最大限度地降低驱动器损耗&#xff09;和低 RDS(on)&#xff08;降低传导损耗&#xff09;。还提供可湿性侧翼选项&#xff0c;用…

解决若依Ruoyi 插入数据返回1,实现主键回填,返回主键ID

最开始的时候ruoyi 插入数据会返回1&#xff0c;开始以为是id&#xff0c;后来发现返回的逻辑是 0失败&#xff0c;1成功。 即便他利用mybatis设置了如下, useGeneratedKeys"true" keyProperty"id"​​​​​​​<selectKey></selectKey> 如…

openGauss学习笔记-116 openGauss 数据库管理-设置数据库审计-审计概述

文章目录 openGauss学习笔记-116 openGauss 数据库管理-设置数据库审计-审计概述116.1 背景信息116.2 操作步骤 openGauss学习笔记-116 openGauss 数据库管理-设置数据库审计-审计概述 116.1 背景信息 数据库安全对数据库系统来说至关重要。openGauss将用户对数据库的所有操作…