字节序问题:
现代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);
int socket(int domain, int type, int protocol);
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);
常见error
- EACCES:被绑定的地址是受保护的,普通用户将socket绑定到知名服务器端口,bind将返回EACCES
- EADDRINUSE:被绑定的地址在使用中
int listen(int sockfd, int backlog);
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
监听队列中处于ESTABLISHED状态的连接对应的客户端出现网络异常(掉线)或提前退出,accept调用成功。accept只是从监听队列中取出连接,不论连接处于何种状态。
int connect(int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen);
常见errno:
int close(int fd);
close系统调用并非总是立即关闭一个连接,而是将fd的引用计数-1。只有fd的引用计数==0时,才关闭连接。
多进程程序中,一次fork系统调用将使父进程打开的socket引用计数+1,必须在父、子进程中都对该socket执行close才能关闭连接。
int shutdown(int sockfd, int howto);
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
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);
int getsockname(int sockfd, struct sockaddr* address, socklen_t* address_len);
int getpeername(int sockfd, struct sockaddr* address, socklen_t* address_len);
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);
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 */
}
struct servent *getservbyname(const char *name, const char *proto);
struct servent *getservbyport(int port, const char *proto);
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
int dup(int oldfd);
- 复制文件描述符,新文件描述符和oldfd指向相同的文件、管道、socket
- 通过dup复制的文件描述符并不继承原文件描述符的属性,如close-on-exec,non-blocking。
应用:CGI服务器
先关闭标准输出文件描述符STDOUT_FILENO(值==1),调用dup(),复制connfd文件描述符,dup总是使用系统最小的可用文件描述符(此时值==1),即标准输出指向connfd。服务器输出到标准输出的内容会直接被客户端获得。