文章目录
5.网络编程api
5.1 主机字节序、网络字节序
字节序问题:
现代CPU的累加器一次能装载至少4个字节(32位机器),这4个字节在内存中排列的顺序将影响它被累加器装载成的整数的值。
- 大端字节序:高位字节存储在内存的低位地址
- 小端字节序:高位字节存储在内存的高位地址
大部分主机采用小端字节序,所以小端字节序又称为主机字节序。
大端字节序 == 网络字节序
端口的转换:
unsigned short int htons(unsigned short int hostshort);
unsigned short int ntohs(unsigned short int netshort);
IP地址转换:
点分十进制字符串表示的地址 <========>网络字节序整数表示的地址
int inet_aton(const char* ip, struct in_addr* inp);
int inet_pton(int af, const char* src, void* src);
char* inet_ntoa(struct in_addr in);
const char* inet_ntop(int af, const void* src, char* dst, socklen_t cnt);
5.2 创建socket
int socket(int domain, int type, int protocol);
5.3 绑定地址
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);
常见error
- EACCES:被绑定的地址是受保护的,普通用户将socket绑定到知名服务器端口,bind将返回EACCES
- EADDRINUSE:被绑定的地址在使用中
5.4 创建一个监听队列来存放待处理的客户连接
int listen(int sockfd, int backlog);
5.5 从监听对列中接受一个连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
监听队列中处于ESTABLISHED状态的连接对应的客户端出现网络异常(掉线)或提前退出,accept调用成功。accept只是从监听队列中取出连接,不论连接处于何种状态。
5.6 发起连接
int connect(int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen);
常见errno:
- ECONNREFUSED:目标端口不存在
- ETIMEDOUT:连接超时
5.7 关闭连接
int close(int fd);
close系统调用并非总是立即关闭一个连接,而是将fd的引用计数-1。只有fd的引用计数==0时,才关闭连接。
多进程程序中,一次fork系统调用将使父进程打开的socket引用计数+1,必须在父、子进程中都对该socket执行close才能关闭连接。
int shutdown(int sockfd, int howto);
立即关闭socket。
5.8 数据读写
- TCP
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
flags设为0
- UDP
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t *addrlen);
size_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);
也可用于TCP,把后两个参数==NULL,因为已经建立连接,知道其地址
- 通用数据读写
ssize_t recvmsg(int sockfd, struct msghdr* msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr* msg, int flags);
5.9 获取socket地址(本端、对端)
int getsockname(int sockfd, struct sockaddr* address, socklen_t* address_len);
int getpeername(int sockfd, struct sockaddr* address, socklen_t* address_len);
5.10 获取、设置socket选项
fcntl
int getsockopt(int sockfd, int level, int option_name, void* option_value);
int setsockopt(int sockfd, int level, int option_name, const void* option_value, socklen_t option_len);
SO_REUSEADDR
5.11 根据主机名(IP)获取主机的完整信息
struct hostent *gethostbyname(const char *name);
struct hostent *gethostbyname(const char *name);
struct hostent {
char *h_name; /* official name of host */
char **h_aliases; /* alias list */
int h_addrtype; /* host address type */
int h_length; /* length of address */
char **h_addr_list; /* list of addresses */
}
5.12 根据名称(端口号)获取某个服务的完整信息
struct servent *getservbyname(const char *name, const char *proto);
struct servent *getservbyport(int port, const char *proto);
6. 高级I/O函数
6.1 pipe、socketpair
int pipe(int pipefd[2]);
- 写端文件描述符pipefd[1]的引用计数减少到0,没有任何进程往管道里写数据,则read fd[0],返回0
- 读端文件描述符pipefd[0]的引用计数减少到0,没有任何进程从管道里读数据,则write fd[1],返回SIGPIPE
//创建双向管道
int socketpair(int domain, int type, int protocol, int sv[2]);
domain:AF_UNIX
6.2 dup
int dup(int oldfd);
- 复制文件描述符,新文件描述符和oldfd指向相同的文件、管道、socket
- 通过dup复制的文件描述符并不继承原文件描述符的属性,如close-on-exec,non-blocking。
应用:CGI服务器
先关闭标准输出文件描述符STDOUT_FILENO(值==1),调用dup(),复制connfd文件描述符,dup总是使用系统最小的可用文件描述符(此时值==1),即标准输出指向connfd。服务器输出到标准输出的内容会直接被客户端获得。
6.3 fcntl
将一个文件描述符设置为非阻塞