【Muduo源码剖析笔记】 网络库之SocketsOps
定义了一堆在sockets命名空间的全局函数
sockaddr_cast函数
有四个重载版本,可以接受sockaddr_in6和sockaddr_in这两个专用socket地址结构体,分别用于IPv6和IPv4利用。利用implicit_cast强制转换成了sockaddr类型
createNonblockingOrDie(sa_family_t family):
地址族类型sa_family_t,地址族类型通常与协议族类型对应。用来识别不同协议的,为什么要搞两套东西呢?这是因为之前UNIX有两种风格系统:BSD系统和POSIX系统,对于BSD系统,一直用的是AF,对于POSIX系统,一直用的是PF。Linux作为后起之秀,为了兼容,所以两种都支持,这样两种风格的UNIX下的软件就可以在Linux上运行了。
基于family使用socket系统调用,创建一个该协议类型的文件描述符,
socket(int domain, int type, int protocol)
默认封装的socket提供的服务类型有SOCK_STREAM(流服务),SOCK_NONBLOCK(非阻塞), SOCK_CLOEXEC(用fork调用创建子进程时在子进程中关闭该socket。)选择为TCP协议。
失败的话就会使用 LOG_SYSFATAL。
connect(int sockfd, const struct sockaddr* addr):
通过connect系统调用来主动建立连接,addr是服务器监听的socket地址。一旦建立连接,就唯一标识了这个连接,客户端就通过读写sockfd来与服务器通信。
sockaddr包含了socket的地址族类型、端口号和地址。实际使用的时候转换成通用的地址类型sockaddr就行。不同地址族会有不同的数据结构,比如IPv4使用sockaddr_in。
bindOrDie(int sockfd, const struct sockaddr* addr)
创建socket后,并没有指定使用该地址族中的哪个具体socket地址,将一个socket与socket地址绑定称为给socket命名。就是将socket和实际使用的协议地址进行绑定,创建socket的时候就只是指定了用哪个协议而已。服务器程序通常要命名socket,客户端不需要,采用匿名的方式,使用操作系统自动分配的socket地址。bind将addr地址分配给未命名的sockfd文件描述符。
listenOrDie(int sockfd)
对一个已经命名的sockfd(与一个socket bind)后,系统调用listen来创建一个监听队列来存放后续的客户连接。
int accept(int sockfd, struct sockaddr_in6* addr)
从listen监听队列中接收一个连接,函数内部实际调用accept4
accept4(sockfd, sockaddr_cast(addr),&addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC)
accept4()函数共有4个参数,相比accept()多了一个flags的参数,用户可以通过此参数直接设置套接字的一些属性.
sockfd是已经在监听socket了,addr参数用来获取被接收连接的socket地址。
如果接收连接失败就会保存日志信息。
成功就会返回一个与新连接的socket,该socket唯一标识了这个连接,服务器通过对这个socket读写来实现对应客户端的通信。
ssize_t read(int sockfd, void *buf, size_t count);
从sockfd中读取count长度的数据存放在buf中。
ssize_t readv(int sockfd, const struct iovec *iov, int iovcnt);
iovec结构体类型的指针
struct iovec
{
void *iov_base; //内存起始地址
size_t iov_len; //内存长度
}
write(int sockfd, const void *buf, size_t count);
close(int sockfd)
shutdownWrite(int sockfd)
toIp(char* buf, size_t size,const struct sockaddr* addr);
如果addr(包含端口号、地址族以及相应的地址等信息)表示是IPv4的话。使用sockaddr_in 数据保存addr,通过
const struct sockaddr_in* addr4 = sockaddr_in_cast(addr);
//把sockaddr cast成IPv4专用的socket地址结构体
::inet_ntop(AF_INET, &addr4->sin_addr, buf, static_cast<socklen_t>(size));
//将数值格式转化为点分十进制的ip地址格式
AF_INET表示地址族,sin_addr是具体地址,buf是char*类型的。
toIpPort(char* buf, size_t size,const struct sockaddr* addr);
好像是把addr地址的IP和端口号全部放进buf中。
int getSocketError(int sockfd)
sockaddr_in6 sockets::getLocalAddr(int sockfd) :
::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen)
getsockname可以获得一个与socket相关的地址。 服务器端可以通过它得到相关客户端地址。
sockaddr_in6 sockets::getPeerAddr(int sockfd)
::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen)
getpeername函数用于获取与某个套接字关联的外地协议地址
sockets::isSelfConnect(int sockfd)
通过获取本端地址和外端地址,判断是否是自己连接自己的sockfd。