在socket网络编程中经常用到一些宏定义、结构和函数,这些经常包含在相关的头文件中,使用时直接include相关头文件即可。下面简单描述下相关的一些结构及头文件。
1. sockaddr / bits/socket.h
socket编程最基本的就是socket地址,其定义在bits/socket.h中。但sys/socket.h包含bits/socket.h,且bits/socket.h明确指出该头文件不能直接使用,应使用sys/socket.h代替。
struct sockaddr { __SOCKADDR_COMMON (sa_); /* Common data: address family and length. */ char sa_data[14]; /* Address data. */ };
其中__SOCKADDR_COMMON()宏定义在bits/sockaddr.h中
#define __SOCKADDR_COMMON(sa_prefix) \ sa_family_t sa_prefix##family #define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))
替换后为
struct sockaddr{ unsigned short sa_family; char sa_data[14]; };
在bits/socket.h中还定义了协议族(Protocol families,PF_xxx)和地址族(Address families,AF_xx),两者一一对应,因此可以互换,应用场合根据概念稍有不同。
#define PF_UNSPEC 0 /* Unspecified. */ #define PF_LOCAL 1 /* Local to host (pipes and file-domain). */ #define PF_UNIX PF_LOCAL /* POSIX name for PF_LOCAL. */ #define PF_FILE PF_LOCAL /* Another non-standard name for PF_LOCAL. */ #define PF_INET 2 /* IP protocol family. */ #define PF_AX25 3 /* Amateur Radio AX.25. */ #define PF_IPX 4 /* Novell Internet Protocol. */ #define PF_APPLETALK 5 /* Appletalk DDP. */ #define PF_INET6 10 /* IP version 6. */ #define PF_LLC 26 /* Linux LLC. */ #define PF_CAN 29 /* Controller Area Network. */ #define PF_NFC 39 /* NFC sockets. */ #define PF_VSOCK 40 /* vSockets. */ #define PF_MAX 41 /* For now.. */
2. sys/socket.h
该头文件包含常用的socket编程函数接口,如:
socket() bind() listen() connect() accept() shutdown()
send() recv() sendto() recvfrom() sendmsg() recvmsg() sendmmsg() recvmmsg()
socketpair() getsockname() getpeername()
getsockopt() setsockopt()
除此外,sys/socket.h包含bits/socket.h,需要bits/socket.h的函数直接include sys/socket.h即可。
3. 网络socket地址 sockaddr_in -- netinet/in.h
与internet网络相关的头文件大部分在netinet目录下,如in.h ip.h(ip协议相关数据结构) tcp.h(tcp协议) udp.h(udp协议) ip_icmp.h(icmp协议) ip6.h icmp6.h等。
在网络编程中用到的socket地址是经过转换的网络socket地址sockaddr_in:
/* Structure describing an Internet socket address. */ struct sockaddr_in { __SOCKADDR_COMMON (sin_); /* unsigned short sin_family; */ in_port_t sin_port; /* Port number. */ struct in_addr sin_addr; /* Internet address. */ /* Pad to size of `struct sockaddr'. */ unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof (in_port_t) - sizeof (struct in_addr)]; };
网络地址
/* Internet address. */ typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; };
网络端口
/* Type to represent a port. */ typedef uint16_t in_port_t;
据此也可推断出:唯一确定一个连接(socket)的五要素:目的IP,目的端口,源IP,源端口,协议。
经典的4个主机网络字节序转换函数
/* Functions to convert between host and network byte order. Please note that these functions normally take `unsigned long int' or `unsigned short int' values as arguments and also return them. But this was a short-sighted decision since on different systems the types may have different representations but the values are always the same. */ extern uint32_t ntohl (uint32_t __netlong) __THROW __attribute__ ((__const__)); extern uint16_t ntohs (uint16_t __netshort) __THROW __attribute__ ((__const__)); extern uint32_t htonl (uint32_t __hostlong) __THROW __attribute__ ((__const__)); extern uint16_t htons (uint16_t __hostshort) __THROW __attribute__ ((__const__));
netinet/in.h定义了标准协议enum:
enum { IPPROTO_IP = 0, /* Dummy protocol for TCP. */ #define IPPROTO_IP IPPROTO_IP IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */ #define IPPROTO_ICMP IPPROTO_ICMP IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */ #define IPPROTO_IGMP IPPROTO_IGMP IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94). */ #define IPPROTO_IPIP IPPROTO_IPIP IPPROTO_TCP = 6, /* Transmission Control Protocol. */ #define IPPROTO_TCP IPPROTO_TCP IPPROTO_EGP = 8, /* Exterior Gateway Protocol. */ #define IPPROTO_EGP IPPROTO_EGP IPPROTO_PUP = 12, /* PUP protocol. */ #define IPPROTO_PUP IPPROTO_PUP IPPROTO_UDP = 17, /* User Datagram Protocol. */ #define IPPROTO_UDP IPPROTO_UDP IPPROTO_IDP = 22, /* XNS IDP protocol. */ IPPROTO_IPV6 = 41, /* IPv6 header. */
#define IPPROTO_IPV6 IPPROTO_IPV6
IPPROTO_RAW = 255, /* Raw IP packets. */
#define IPPROTO_RAW IPPROTO_RAW
IPPROTO_MAX };
标准端口enum
enum { IPPORT_ECHO = 7, /* Echo service. */ IPPORT_DISCARD = 9, /* Discard transmissions service. */ IPPORT_SYSTAT = 11, /* System status service. */ IPPORT_DAYTIME = 13, /* Time of day service. */ IPPORT_NETSTAT = 15, /* Network status service. */ IPPORT_FTP = 21, /* File Transfer Protocol. */ IPPORT_TELNET = 23, /* Telnet protocol. */ IPPORT_SMTP = 25, /* Simple Mail Transfer Protocol. */ IPPORT_TIMESERVER = 37, /* Timeserver service. */ IPPORT_NAMESERVER = 42, /* Domain Name Service. */ IPPORT_WHOIS = 43, /* Internet Whois service. */ IPPORT_MTP = 57, IPPORT_TFTP = 69, /* Trivial File Transfer Protocol. */ IPPORT_RJE = 77, IPPORT_FINGER = 79, /* Finger service. */ IPPORT_TTYLINK = 87, IPPORT_SUPDUP = 95, /* SUPDUP protocol. */ IPPORT_EXECSERVER = 512, /* execd service. */ IPPORT_LOGINSERVER = 513, /* rlogind service. */ IPPORT_CMDSERVER = 514, IPPORT_EFSSERVER = 520, /* UDP ports. */ IPPORT_BIFFUDP = 512, IPPORT_WHOSERVER = 513, IPPORT_ROUTESERVER = 520, /* Ports less than this value are reserved for privileged processes. */ IPPORT_RESERVED = 1024, /* Ports greater this value are reserved for (non-privileged) servers. */ IPPORT_USERRESERVED = 5000 };
ABCD四类网络,常用IP地址
#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0) #define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) #define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) #define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) /* Address to accept any incoming messages. */ #define INADDR_ANY ((in_addr_t) 0x00000000) /* Address to send to all hosts. */ #define INADDR_BROADCAST ((in_addr_t) 0xffffffff) /* Address indicating an error return. */ #define INADDR_NONE ((in_addr_t) 0xffffffff) /* Network number for local host loopback. */ #define IN_LOOPBACKNET 127
还有IPv6、filter相关结构及函数。
4. 网络地址二进制与字符串转换 -- arpa/inet.h
推荐使用inet_pton()或inet_aton(),而非inet_addr()或inet_network(),因为返回值-1代表IP地址255.255.255.255。
extern int inet_aton (const char *__cp, struct in_addr *__inp) __THROW; extern char *inet_ntoa (struct in_addr __in) __THROW; /* Convert from presentation format of an Internet number in buffer starting at CP to the binary network format and store result for interface type AF in buffer starting at BUF. */ extern int inet_pton (int __af, const char *__restrict __cp, void *__restrict __buf) __THROW; /* Convert a Internet address in binary network format for interface type AF in buffer starting at CP to presentation form and place result in buffer of length LEN astarting at BUF. */ extern const char *inet_ntop (int __af, const void *__restrict __cp, char *__restrict __buf, socklen_t __len) __THROW;
#define servip "192.168.1.103" inet_pton(AF_INET, servip, &servaddr.sin_addr.s_addr);
实现二进制网络ip与字符串ip之间的转换,均以inet开头。
此外arpa还包含ftp.h tftp.h telnet.h nameser.h nameser_compat.h。
5. netdb.h -- network data base library
/* All data returned by the network data base library are supplied in host order and returned in network order (suitable for use in system calls). */
提供主机/域名等结构体或函数。
/* Description of data base entry for a single host. */ struct hostent { char *h_name; /* Official name of host. */ char **h_aliases; /* Alias list. */ int h_addrtype; /* Host address type. */ int h_length; /* Length of address. */ char **h_addr_list; /* List of addresses from name server. */ #if defined __USE_MISC || defined __USE_GNU # define h_addr h_addr_list[0] /* Address, for backward compatibility.*/ #endif };
/* Description of data base entry for a single service. */ struct servent { char *s_name; /* Official service name. */ char **s_aliases; /* Alias list. */ int s_port; /* Port number. */ char *s_proto; /* Protocol to use. */ };
/* Description of data base entry for a single service. */ struct protoent { char *p_name; /* Official protocol name. */ char **p_aliases; /* Alias list. */ int p_proto; /* Protocol number. */ };
提供的常用函数:
extern struct hostent *gethostent (void); extern struct hostent *gethostbyaddr (const void *__addr, __socklen_t __len, int __type); extern struct hostent *gethostbyname (const char *__name); extern struct servent *getservbyname (const char *__name, const char *__proto); extern struct servent *getservbyport (int __port, const char *__proto); extern struct protoent *getprotobyname (const char *__name); extern struct protoent *getprotobynumber (int __proto);
6. sys/un.h--unix域头文件
un.h中包含Unix域套接字的地址结构体sockaddr_un。
#include <sys/un.h>
#define UNIX_PATH_MAX 108 struct sockaddr_un { __kernel_sa_family_t sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* pathname */ };
实际地址长度为:offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1