1.套接字描述符
套接字是通信端点的抽象。使用socket函数创建套接字。
#include <sys/socket.h>
int socket(int domain, int type, int protccol);
domin域:AF_INET ----IPv4因特网域 AF_INET6----IPv6因特网域 AF_UNIX--UNIX域 AF_UNSPEC----未指定
type类型:SOCK_DGRAM---长度固定的,无连接的不可靠报文传递 SOCK_RAM---IP协议的数据报接口 SOCK_SEQPACKET---长度固定、有序、可靠的面向连接报文传递 SOCK_STREAM---有序、可靠、双向面向连接的字节流。
protocol通常是零,表示按给定的域和套接字类型选择默认协议。在AF_INEF 通信域中套接字类型SOCK_STREAM默认协议是TCP(传输控制协议),在 AF_INET通信域中套接字类型SOCK_DGRAM的默认协议是UDP。
SOCK_DGRAM面向的是无连接的,SOCK_STREAM是需要连接的。
数据报是一种自包含报文。
套接字是双向的,可以使用shutdown来禁止套接字的输入/输出。
#include <sys/socket.h>
int shutdown(int sockfd, int how);
如果how是SHUT_RD(关闭读端),那么无法从套接字读取数据,如果how是 SHUT_WR(关闭写端),那么无法使用套接字发送数据,使用SHUT_RDWR则将同时无法读取和发送数据。
2.字节序
大端
n | n+1 | n+2 | n+3 |
MSB LSB
小端
n +3 | n+2 | n+1 | n |
TCP/IP采用的是大端字节序。
#include <arpa/inet.h>
uint32_t htonl (uint32_t hostint32);
uint32_t htons(uint16_t, hostint16);
uint32_t ntohl (uint32_t netint32)
uint32_t ntohs(uint16_t, netint16);
3.地址格式
地址标识了特定通信域中的套接字端点,地址格式与特定的通信域相关。地址被强制转换成通用地址结构sockaddr表示:
struct sockaddr{
sa_family_t sa_family;
char sa_data[]; /* variable-length address */
}
在IPv4因特网域(AF_INET)中,套接字地址用如下结构sockaddr_in表示:
struct in_addr{
in_addr_t s_addr;
}
struct sockaddr_in{
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
}
in_port_t 定义成uint16_t in_addr_t定义成uint32_t
#include <arpa/inet.h>
const char *inet_ntop (int domin, const void *restrict addr, char *restrict str, socklen_t size); 若成功返回地址字符串指针,若出错则返回NULL。
int inet_pton (int domain, const char *restrict str, void *restrict addr); 返回值:若成功则返回1,若格式无效则返回0,若出错则返回-1.
函数inet_ntop将网络字节序二进制转换成文本格式字符串格式。 函数inet_pton将文本格式字符串格式转换成网络字节序二进制地址。参数domin支持两个值: AF_INET和AF_INET6.
调用gethostent找到给定计算机的信息。
#include <netdb.h>
struct hostent *gethostent(void); 返回值:若成功则返回指针,若出错则返回NULL。
void sethostent (int stayopen);
void endhostent (void);
采用一套相似的接口获得网络名字和网络号
#include <netdb.h>
struct netent *getnetbyaddr(uint32_t net, int type);
struct netent *getnetbyname(const char *name);
struct netent *getnetent(void);
void setnetent(int stayopen);
void endnetent(void);
可以将协议名字和协议号采用以下函数映射:
#include <netdb.h>
struct protoent *getprotobyname(const char *name);
struct protoent *getprotobynumber (int proto);
struct protoent *getprotoent (void);
void setprotoent (int stayopen);
void endprotoent (void);
服务是由地址端口号部分表示的。
#include <netdb.h>
struct servent *getservbyname (const char *name); 将一个服务名字映射到一个端口号
struct servent *getservbyport(int port, const char *proto); 将一个端口号映射到一个服务名
struct servent *getservent (void);
void setservent(int stayopen);
void endservent (void);
函数getaddrinfo允许将一个主机名字和服务名字映射到一个地址。
#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);
void freeaddrinfo(struct addrinfo *ai);
调用gai_strerror将返回的错误码转换成错误消息。
#include <netdb.h>
const char *gai_strerror(int error);
函数getnameinfo将地址转换成主机名或者服务名
#include <sys/socket.h>
#include <netdb.h>
int getnameinfo (const struct sockaddr *restrict addr, socklen_t alen, char *restrict host, socklen_t hostlen, char *restrict service, socklen_t servlen, unsigned int flags);