套接字是通讯端点的抽象
创建一个套接字
#include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); 返回值:成功文件(套接字)描述符,失败-1
domain:即协议域,又称为协议族(family)。常用的协议族有,AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。 协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。 type:指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等(socket的类型有哪些?)。 protocal:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等 它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
套接字通信是双向的。可以禁止一个套接字的I/O
#include <sys/socket.h> int shutdown(int sockfd, int how); 返回值:成功0,出错-1 sockfd:套接字的描述符 how:三种SHUT_RD(0)关闭sockfd上的读功能 SHUT_WR(1)关闭sockfd上的写功能 SHUT_RDWR(2)关闭sockfd的读写功能
用来在处理器字节序和网络字节序之间实施转换的函数
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
返回值:以网络字节序表示的32位整数
uint16_t htons(uint16_t hostshort);
返回值:以网络字节序表示的16位整数
uint32_t ntohl(uint32_t netlong);
返回值:以主机字节序表示的32位整数
uint16_t ntohs(uint16_t netshort);
返回值:以主机字节序表示的16位整数
h表示主机字节序,n表示网络字节序,l表示长整型,s表示短整型
打印出能被人理解而不是计算机所理解的地址格式。同时支持IPv4和IPv6地址
#include <arpa/inet.h> const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); 返回值:成功地址字符串指针,出错NULL af:地址簇,仅支持AF_INET和AF_INET6 src:来源地址结构指针 dst:接收转换后的字符串 size:保存文本字符串的缓冲区大小 int inet_pton(int af, const char *src, void *dst); 返回值:成功1,格式无效0,出错-1 af:地址簇,仅支持AF_INET和AF_INET6 src:转换的地址字符串 dst:转换后的地址结构指针
找到给定计算机系统的主机信息
#include <netdb.h> struct hostent *gethostent(void); 返回值:成功返回指针,出错NULL void sethostent(int stayopen);
stayopen:true就是TCP,否则UDP void endhostent(void);
能够采用一套相似的接口来获得网络名字和网络编号
#include <netdb.h> struct netent *getnetbyaddr(uint32_t net, int type); struct netent *getnetbyname(const char *name); struct netent *getnetent(void); 返回值:成功返回指针,出错NULL void setnetent(int stayopen); void endnetent(void);
在协议名字和协议编号之间进行映射
#include <netdb.h> struct protoent *getprottobyname(const char *name); struct protoent *getprotobynumber(int proto); struct protoent *getprotoent(void); 返回值:成功返回指针,出错NULL void setprotoent(int stayopen); void endprotoent(void);
服务是由地址的端口号部分表示的,每个服务由一个唯一的众所周知的端口号来支持。可以使用getservbyname将一个服务名映射到一个端口号,使用函数getservbyport将一个端口号映射到一个服务名,使用函数getservent顺序扫描服务数据库。
#include <netdb.h> struct servent *getservbyname(const char *name, const char *proto); struct servent *getservbyport(int port, const char *proto); struct servent *getservent(void); 返回值:成功返回指针,出错NULL void setservent(int stayopen); void endservent(void);
将一个主机和一个服务名映射到一个地址
#include <sys/socket.h> #include <netdb.h> int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); 返回值:成功0,出错非0错误码 void freeaddrinfo(struct addrinfo *res);
addrinfo结构体
struct addrinfo { int ai_flags; int ai_family; //AF_INET,AF_INET6,UNIX etc int ai_socktype; //STREAM,DATAGRAM,RAW int ai_protocol; //IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc size_t ai_addrlen;//length of ai_addr char* ai_canonname; //full hostname struct sockaddr* ai_addr; //addr of host struct addrinfo* ai_next; }
错误码需要调用函数来转换成错误消息
#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> const char *gai_strerror(int errcode);
将一个地址转换成一个额主机名和一个服务名
#include <sys/socke.h> #include <netdb.h> int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags);
sockaddr结构体
struct sockaddr { __SOCKADDR_COMMON (sa_); /* Common data: address family and length. 协议族*/ char sa_data[14]; /* Address data. 地址+端口号*/ };