1、套接字描述符:
套接字是通信端点的抽象,在unix系统中套接字是由文件描述符实现的
int socket(int domain, int type, int protocol);
domain确定通信的特性,各个域的常熟都以AF_开头,指地址组(address family)。(AF_INET,AF_INET6,AF_UNIX,AF_UNSPEC)
type确定套接字的类型,SOCK_DGRAM,SOCK_RAW,SOCK_SEQPACKET,SOCK_STREAM。SOCK_RAW套接字提供一个借口用于直接访问下面的网络层。
套接字是双向的,可以用shutdown来禁止套接字上的输入输出:
int shutdown(int sockfd, int how); how是SHUT_RD,SHUT_WR,SHUT_RDWR。
2、字节序 (大对大,小对小)
TCP/IP协议栈采用大端字节序。
处理器和网络字节序转换
#include <arpa/inet.h>
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、地址格式
通用地址格式:
struct sockaddr{
sa_family_t sa_family;
char sa_data[];
.........
}
Internet addresses are defined in <netinet/in.h>. In the IPv4 Internet domain (AF_INET), a socket address is represented by asockaddr_in structure
struct in_addr { in_addr_t s_addr; /* IPv4 address */ }; struct sockaddr_in { sa_family_t sin_family; /* address family */ in_port_t sin_port; /* port number */ struct in_addr sin_addr; /* IPv4 address */ };IP地址在二进制和字符串之间的转换:
#include <arpa/inet.h>
const char *inet_ntop(int domain, const void* restrict addr, char *restrict str, socklen_t size);
Returns: pointer to address string on success, NULL on error
int inet_pton(int domain, const char *restrict str, void *retrcit addr);
Returns: 1 on success, 0 if the format is invalid, or 1 on error
The inet_ntop function converts a binary address in network byte order into a text string;inet_pton converts a text string into a binary address in network byte order.
4、地址查询
查询主机信息gethostent:
#include <netdb.h>
struct hostent *gethostent(void);
Returns: pointer if OK, NULL on error
void sethostent(int stayopen);
void endhostent(void);
struct hostent { char *h_name; /* name of host */ char **h_aliases; /* pointer to alternate host name array */ int h_addrtype; /* address type */ int h_length; /* length in bytes of address */ char **h_addr_list; /* pointer to array of network addresses */ . . . };
struct netent *getnetbyaddr(uint32_t net, int type);
struct netent *getnetbyname(const char *name);
struct netent { char *n_name; /* network name */ char **n_aliases; /* alternate network name array pointer */ int n_addrtype; /* address type */ uint32_t n_net; /* network number */ . . . };此处省略一部分函数及结构体的介绍,因为现在一般都用新的函数 getaddrinfo
The getaddrinfo function allows us to map a host name and a service name to an address. ------------map映射,主机名和服务名对地址的映射
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *restrict host, const char *restrict service, const struct addrinfo *restrict hint, struct addrinfo **restrict res);
return : 0 if OK, 非0则是错误码
We need to provide the host name, the service name, or both. If we provide only one name, the other should be a null pointer. The host name can be either a node name or the host address in dotted-decimal notation.
struct addrinfo { int ai_flags; /* customize behavior */ int ai_family; /* address family */ int ai_socktype; /* socket type */ int ai_protocol; /* protocol */ socklen_t ai_addrlen; /* length in bytes of address */ struct sockaddr *ai_addr; /* address */ char *ai_canonname; /* canonical name of host */ struct addrinfo *ai_next; /* next in list */ . . . };
服务器名可以是个端口号“字符串”。如果service在/etc/services文件里没有登记的话,要不得在/etc/services下登记服务。
Flag | Description |
---|---|
AI_ADDRCONFIG | Query for whichever address type (IPv4 or IPv6) is configured. |
AI_ALL | Look for both IPv4 and IPv6 addresses (used only with AI_V4MAPPED). |
AI_CANONNAME | Request a canonical name (as opposed to an alias). |
AI_NUMERICHOST | Return the host address in numeric format. |
AI_NUMERICSERV | Return the service as a port number. |
AI_PASSIVE | Socket address is intended to be bound for listening. //当service是端口号的时候需要制定监听 |
AI_V4MAPPED | If no IPv6 addresses are found, return IPv4 addresses mapped in IPv6 format. |
getaddrinfo函数的错误处理不能用perror strerror 有专门的gai_strerror
#include <netdb.h> const char* gai_strerror(int error);.
getnameinfo将地址转换成主机名或者服务名。
套接字与地址绑定:
与客户端套接字关联的地址没有太大意义,但服务器需要给接受客户端请求的套接字绑定个众所周知的地址。
客户端为服务器保留一个地址并且在/etc/services或者摸个名字服务中注册。
int bind( int sockfd, const struct sockaddr *addr, socklen_t len); 0 if OK, 1 on error
The port number in the address cannot be less than 1,024 unless the process has the appropriate privilege
For the Internet domain, if we specify the special IP address INADDR_ANY, the socket endpoint will be bound to all the system's network interfaces
getsockname发现绑定到一个套接字的地址。
int getsockname( int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);
如果套接字已经和对方连接,可以调用getpeername来找到对方的地址。
int getpeername(int sockfd, strcut sockaddr *restrict addr, socklen_t *restrict addr);