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-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
} // namespace
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
//创建一个socket
int sockfd = ::socket(family, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0)
{
LOG_SYSFATAL << "sockets::createNonblockingOrDie";
}
//设置socket为非阻塞
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;
}
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);
#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* 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是ipv6
if (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);
//将端口号从网络字节序转换为本机字节序,再将其写人buf
uint16_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);
//将端口号从网络字节序转换为本机字节序,再将其写人buf
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)
{
//判断ipv4
if (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));
}
//判断ipv6
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));
}
}
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);
//如果这是一个ipv4
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);
//判断本地和远端的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;
}
}