函数文档三

IP 地址结构

struct in_addr{
uint32_t s_addr;
}

IP地址和点分十进制结构

客户端主机和服务端主机的表示方式可能大大的不相同, 一个可能采用的是小端法,另外一个采用的可能是大端法,所以可以根据自己的结构调整顺序。

# include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint32_t htons(uint16_t hostshort);
返回值:按照网络字节顺序

# include <arpa/inet.h>
uint32_t ntonl(uint32_t hostlong);
uint32_t ntons(uint16_t hostshort);
返回值:按照主机字节顺序

套接字结构

/*IP 套接字i地址结构*/
struct sockaddr_in{
    uint16_t sin_family; /*使用的协议类型 AF_INET*/
    uint16_t sin_port;
    struct in_addr sin_addr; /*ip地址*/
    unsigned char sin_zero[8];
};
/*通用的套接字地址结构*/
struct sockaddr {
    uni16_t sa_family;
    char sa_data[4];
}

socket 函数

客户端和服务器使用socket函数创建一个套接字描述符

# include <sys/types.h>
# include <sys/socket.h>

int socket(int domain, int type, int protocol);

让套接字称为链接的一个端点
int clientfd = socket(AF_INET, SOCK_STREAM, 0);
AF_INET 32 位地址
SOCK_STREAM 表示套接字连接的一个端点

通常使用getaddrinfo 自动生成相关的参数

connect函数

include <sys/socket.h>

int connet(int clientfd, const struct sockaddr *addr, socklen_t addlen); addrlen = sizeof(sockaddr_in)

connect会造成阻塞,得到的连接是由套接字对

(x:y, addr.sin_addr:addr.sin_port)

描述

服务器用来和客户端建立连接的函数

bind函数

# include <sys/socket.h>
int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen);

b1ind函数服务器套接字地址和sockfd联系起来,和addr中的套接字地址联系起来

listen函数

# include <sys/socket.h>
int listen(int sockfd,int backlog);

listen函数将socket函数创建的主动套接字变成一个监听套接字,这个套接字可以接收来自客户端的连接请求,backlog暗示内核在拒绝链接请求时,队列中排队的请求数量,通常设置为一个很大的值。

accept 函数

#include <sys/socket.h>
int accept(int listenfd, struct sockaddr *addr,int addlen);

listenfd 由listen函数提供,addr是客户端的套接字地址,返回一个已连接描述符。

已连接描述符每次客户端连接请求的时候都会被创建一次,存在于一个客户端服务中。
监听描述符存在于服务器整个生命周期。

监听描述符可以帮助服务器进行并发编程,如果每有一个新的连接请求到达监听描述符可以fork一个新的进程。

getaddinfo函数

将主机名 主机地址 服务名和端口号的字符串转化成套接字结构

# include <sys/types.h>
# include <sys/socket.h>
# include <netdb.h>

int getaddrinfo(const char *host, consta char *service, const struct addrinfo *hints, struct addrinfo **result);

host 参数可以是域名也可以是数字地址(如点分十进制IP地址)
service函数可以是服务名(http),或者是实际你只端口号

result 指的是一个addrinfo结构的链表

void freeaddrinfo(struct addrinfo *result);

//将getaddrinfo中的错误信息转换为消息字符串
const char *gai_strerror(int errcode);

客户端调用getaddrinfo之后 会遍历result 链表,指导socket和connect成功,最后需要释放这个链表避免内存泄露

struct addrinfo {
	int	ai_flags;	/* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
	int	ai_family;	/* PF_xxx */
	int	ai_socktype;	/* SOCK_xxx */
	int	ai_protocol;	/* 0 or IPPROTO_xxx for IPv4 and IPv6 */
	socklen_t ai_addrlen;	/* length of ai_addr */
	char	*ai_canonname;	/* canonical name for hostname */
	struct	sockaddr *ai_addr;	/* binary address */
	struct	addrinfo *ai_next;	/* next structure in linked list */
};
  • ai_socktype 表示连接数据报,ai_socktype = SOCK_STREAM 将列表限制为每一个地址组多一个的addrinfo结构 结构的套接字地址可以作文连接的一个端点。

  • ai_flag

    • AI_ADDRCONFIG 如果在使用连接使用这个标志,当本地主机被配置IPV4的时,getaddrinfo就回返回这个地址
    • AI_CANNONNAME 将列表中的第一个addinfo结构的ai_canonname指向host的权威名字
    • AI_NUMBERICSERV 参数service可以为服务名或者段括号,这个标志强制参数为端口号
    • AI_PASSIVE getaddrinfo会返回套接字地址,客户端可以在调用connect的时候这个套接字地址作为主动套接字。这个参数可以让套接字地址为监听套接字。这时,host应该为NULL得到的套接字地址结构的字段是通配符地址,告诉内核服务器会接受发送到该主机的所有IP地址的请求

getnameinfo

# include <sys/socket.h>
# include <netdb.h>

int getnameinfo
(const struct sockaddr *sa,socklen_t salen,
char *host, size_t hostlen,
char *service, size_t servlen, int flags);

//如果成功则为0,如果错误则为非零的错误代码

sa 指向salen字节地套接字地址,host指向大小为hostlen的缓冲区。
getnameinfo将套接字地址结构转换成对应的主机和服务名字符串。

上述两个程序都可以使用gai_strerro转换成字符串

同样也有flags代码

  • NI_NUMBERICHOSTf getnameinfo默认返回host中的域名,改变之后返回一个数字字符串。
  • NI_NUMBERICSERV 会返回服务名而不是端口号,这样的话会直接返回端口号

套接字接口的辅助函数

# include "csapp.h"
int open_clientfd(char *hostname, char *post);

运行在hostname上 并且在port 监听请求。返回一个套接字描述符。

# include "csapp.h"
int open_listenfd(char *post);

open_clientfd 内部实现

open_listenfd 内部实现