总结《Linux高性能服务器编程》第5章
socket最开始的含义是一个IP地址和端口对(ip,port),它唯一地表示了使用TCP通信的一端;
字节序分为大端字节序/网络字节序(big endian)和小端字节序/主机字节序(little endian);
大端字节序是指一个整数的高位字节(23~31 bit)存储在内存的低地址处,低位字节(0
~7 bit)存储在内存的高地址处;
Linux提供了如下4个函数来完成主机字节序和网络字节序之间的转换
#include<netinet/in.h>
unsigned long int htonl(unsigned long int hostlong);
unsigned short int htons(unsigned short int hostshort);
unsigned long int ntohl(unsigned long int netlong);
unsigned short int ntohs(unsigned short int netshort);
socket网络编程接口中表示socket地址的是结构体sockaddr以及sockaddr_storage;
#include<bits/socket.h>
struct sockaddr
{
sa_family_t sa_family; //地址族类型(sa_family_t)的变量,与协议族类型对应
char sa_data[14]; //存放socket地址值
}
将用点分十进制字符串表示的IPv4地址转化为用网络字节序整数表示的IPv4地址:
in_addr_t inet_addr(const char*strptr);
int inet_aton(const char*cp, struct in_addr*inp);
int inet_pton(int af,const char*src, void*dst);
将用网络字节序整数表示的IPv4地址转化为用点分十进制字符串表示的IPv4地址:
char*inet_ntoa(struct in_addr in);
const char*inet_ntop(int af, const void*src, char*dst, socklen_t cnt);
Linux中,所有东西都是文件,socket也是可读、可写、可控制、可关闭的文件描述符;
使用socket系统调用可创建一个socket
#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain,int type,int protocol);
将一个socket与socket地址绑定称为给socket命名,系统调用是bind
#include<sys/types.h>
#include<sys/socket.h>
int bind(int sockfd, const struct sockaddr*my_addr, socklen_t addrlen);
服务器通过listen调用来被动接受连接;
使用listen系统调用创建监听队列以存放待处理的客户连接
#include<sys/socket.h>
int listen(int sockfd,int backlog);
accept系统调用从listen监听队列中接受一个连接
#include<sys/types.h>
#include<sys/socket.h>
int accept(int sockfd, struct sockaddr*addr, socklen_t*addrlen);
客户端需要通过connect系统调主动与服务器建立连接;
#include<sys/types.h>
#include<sys/socket.h>
int connect(int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen);
关闭该连接对应的socket;
通过关闭普通文件描述符的系统调用来完成;
#include<unistd.h>
int close(int fd);
无论如何都要立即终止连接,使用shutdown系统调用
#include<sys/socket.h>
int shutdown(int sockfd,int howto);
对文件的读写操作read和write同样适用于socket;
socket编程接口提供了专用于socket数据读写的系统调用:
#include<sys/types.h>
#include<sys/socket.h>
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);
socket编程接口中用于UDP数据报读写的系统调用
#include<sys/types.h>
#include<sys/socket.h>
ssize_t recvfrom(int sockfd, void*buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addrlen);
ssize_t sendto(int sockfd,const void*buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);
TCP流数据/UDP数据报均可以使用
#include<sys/socket.h>
ssize_t recvmsg(int sockfd,struct msghdr*msg,int flags);
ssize_t sendmsg(int sockfd,struct msghdr*msg,int flags);
//msg参数是msghdr结构体类型的指针
内核通知应用程序带外数据到达的两种常见方式:I/O复用产生的异常事件和SIGURG信号;
使用sockatmark系统调用判断sockfd是否处于带外标记,即下一个被读取到的数据是否是带外数据
#include<sys/socket.h>
int sockatmark(int sockfd);
获取一个连接socket的本端以及远端的socket地址
#include<sys/socket.h>
int getsockname(int sockfd, struct sockaddr*address, socklen_t* address_len);
int getpeername(int sockfd, struct sockaddr*address, socklen_t* address_len);
读取和设置socket文件描述符属性的方法
#include<sys/socket.h>
int getsockopt(int sockfd,int level,int option_name, void* option_value, socklen_t* restrict option_len);
int setsockopt(int sockfd,int level, int option_name, const void* option_value, socklen_t option_len);
socket地址的两个要素,即IP地址和端口号,都是用数值表示的,不便于记忆和扩展;
可用使用网络信息API实现主机名到IP地址的转换等功能;
#include<netdb.h>
struct hostent* gethostbyname(const char*name);
struct hostent* gethostbyaddr(const void*addr, size_t len,int type);
#include<netdb.h>
struct servent* getservbyname(const char*name, const char*proto);
struct servent* getservbyport(int port, const char*proto);
#include<netdb.h>
int getaddrinfo(const char*hostname, const char*service,const
struct addrinfo* hints, struct addrinfo** result);
#include<netdb.h>
int getnameinfo(const struct sockaddr*sockaddr,socklen_t addrlen, char*host, socklen_t hostlen, char*serv, socklen_t servlen, int flags);