说明:
调用sockets命名空间中对基本的Linux系统函数socket,bind,listen,accept的封装函数。
Socket.h
#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).
///
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
Socket.cpp
#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
using namespace muduo;
using namespace muduo::net;
Socket::~Socket()
{
sockets::close(sockfd_);
}
/*
调用命名空间sockets 的bindOrDie 给sockfd_绑定地址
*/
void Socket::bindAddress(const InetAddress& addr)
{
sockets::bindOrDie(sockfd_, addr.getSockAddrInet());
}
/*
调用命名空间sockets 的listenOrDie 监听sockfd_
*/
void Socket::listen()
{
sockets::listenOrDie(sockfd_);
}
/*
调用命名空间sockets 的accept 获得客户端的connfd
并将地址存于peeraddr 中
*/
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;
}
/*
调用命名空间sockets 的shutdownWrite 关闭写端
*/
void Socket::shutdownWrite()
{
sockets::shutdownWrite(sockfd_);
}
/*
http://blog.csdn.net/ygm_linux/article/details/25784465
只要发送数据就立马发出去,不管数据包的大小
*/
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
}
/*
调用标准库的setsockopt 允许地址复用
*/
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
}
/*
调用标准库的setsockopt 允许端口复用
*/
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)
{
LOG_SYSERR << "SO_REUSEPORT failed.";
}
#else
if (on)
{
LOG_ERROR << "SO_REUSEPORT is not supported.";
}
#endif
}
/*
调用标准库的setsockopt 设置保持心跳
*/
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
}