1、套接字是通信端点的抽象。
//创建套接字,成功则返回描述符
int socket(int domain, int type, int protocol);
(1)domain域确定通信的特性,如地址格式,AF=address family
AF_INET IPv4因特网域
AF_INET6 IPv4因特网域
AF_UNIX UNIX域
AF_UNSPEC 未指定
(2)type套接字类型,进一步确定通信特征
SOCK_DGRAM 固定长度数据包,两个进程不需要连接,只需要向其套接字发送一个报文
SOCK_RAM IP协议的数据报接口,之间访问IP层,绕过传输协议,应用自己构造协议头部
SOCK_SEQPACKET 固定长度、有序、面向连接的的报文传递
SOCK_STREAM 字节流,需要建立连接
(3)protocol协议,为0则根据域和套接字类型自动选择协议
IPPROTO_IP IPv4网际协议
IPPROTP_IP6 IPv6网际协议
IPPROTP_ICMP 因特网控制报文协议
IPPROTP_RAW 原始IP数据包协议
IPPROTP_TCP 传输控制协议
IPPROTP_UDP 用户数据包协议
//禁止套接字的IO(IO指读和写)
int shutdown(int sockfd, int how);
2、字节序:印第安序,Intel处理器一般为小端,TCP/IP协议栈使用大端
大端:低地址放高字节,从低地址开始读数
小端:低地址放低字节
进程标志由两部分组成:计算机网络地址;计算机上用端口号表示的服务
//htonl:host to net long
uint32_t htonl(uint32_t hostint32);
uint16_t htons(uint16_t hostint16);
uint32_t ntohl(uint32_t netint32);
uint16_t ntohs(uint16_t netint16);
3、地址格式
不同格式地址会被强制转换成一个通用的地址结构srtuct sockaddr。Linux中IPv4因特网域中的套接字
struct sockaddr_in{
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
struct in_addr{
in_addr_t s_addr;//IPv4地址
};
//二进制地址格式与点分十进制字符转换
const char *inet_ntop(int domain, const void *restrict addr, char *restrict str, socklen_t size);
int inet_pton(int domain, const void *restrict str, void *restrict str);
4、地址查询
//主机信息
struct hostent{
char *h_name;
char **h_aliases;//执行主机别名数组的指针
int h_addrtype;//地址类型
int h_length;
char **h_addr_list;
}
//网络信息
struct netent{
char *n_name;
char **n_aliases;
int n_addrtype;
uint32_t n_net;
}
//协议信息
struct protoent{
char *p_name;
char **p_aliases;
int p_proto;
};
//服务信息
服务是由地址的端口号部分表示的,每个服务由一个唯一的总所周知的端口号支持。
struct servent{
char *s_name;
char **s_aliases;
int s_prot;
char *s_proto;
};
struct addrinfo{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
socklen_t ai_addrlen;
struct sockaddr *ai_addr;
char *ai_canonname;
struct addrinfo *ai_next;
};
//将一个主机名和一个服务名映射到一个地址
//提供host主机名(ip)和service服务名(pid),hint为筛选模板,res为返回值
int getaddrinfo(const char *restrict host, const char *restrict service, const struct addrinfo *restrict hint, struct addrinfo **restrict res);
5、服务器需要给一个发起请求的接收客户端套接字关联上一个已知的地址(某个名字的服务)。
//关联地址和套接字
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
//发现绑定在套接字上的地址
int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);
//套接字已经和对等方连接时,找到对方地址
int getpeername(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);
//客户端向服务器端-建立连接
//addr:想与之通信的服务器地址,服务器必须绑定到一个想与之连接的地址上
int connect(int sockfd, const struct sockaddr *addr, socklen_t len);
//服务器表示可以接收连接请求
//backlog提示服务器未完成请求连接的数量
int listen(int sockfd, int backlog);
//建立连接
//返回请求连接的客户端套接字描述符
//addr:存放地址的缓冲区
int accept(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict len);
调用accept,没有请求到达会一直阻塞直到一个请求到达。服务器可以使用poll或select等待一个请求到达。