一、Socket类型
流式套接字提供可靠的、面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性。
数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证是可靠、无
差错的。它使用数据报协议UDP。
原始套接字允许对底层协议如IP或ICMP进行直接访问,它功能强大但使用较为不便,主要用于一些协议的开发。
二、地址数据结构
• 使用C/C++开发socket程序时,使用sockaddr和sockaddr_in这两个结构类型来保存socket信息。
{
unsignedshortsa_family; /*协议族*/
charsa_data[14]; /*14字节的 协议地址,包含该socket的IP地址和端口号。*/
};
structsockaddr_in
{
shortintsa_family; /*协议族*/
unsignedshortintsin_port; /*端口号*/
structin_addrsin_addr; /*IP地址*/
unsignedcharsin_zero[8]; /*填充0以保持与structsockaddr同样大小*/
};
四、协议族
上述结构中的sa_family字段用于描述socket中的协议族,其定义于netinet/in.h
五、数据存储有限顺序
七、地址格式转化
• 通常用户在表达地址时采用的是点分十进制表示的数值(或者是以冒号分开的十进制IPv6地址),而在通常使
用的socket编程中所使用的则是二进制值,这就需要将这两个数值进行转换。
• 在IPv4中用到的函数有inet_aton()、inet_addr()和inet_ntoa(),而IPv4和IPv6兼容的函数
有inet_pton()和inet_ntop()。由于IPv6是下一代互联网的标准协议,后面涉及的函数都能够同时兼容IPv4和IPv6,
但在具体举例时仍以IPv4为例。
• 这里inet_pton()函数是将点分十进制地址映射为二进制地址,而inet_ntop()是将二进制地址映射为点分十进制
地址。
八、inet_pton函数
九、inet_ntop函数
十、主机名
• 通常,人们在使用过程中都不愿意记忆冗长的IP地址,尤其到IPv6时,地址长度多达128位。因此,使用
主机名将会是很好的选择。
• 在Linux中,同样有一些函数可以实现主机名和地址的转化,最为
常见的有gethostbyname()、gethostbyaddr()和getaddrinfo()等,它们都可以实现IPv4和IPv6的地址和主机名
之间的转化。其中gethostbyname()将主机名转化为IP地址,gethostbyaddr()则是逆操作,将IP地址转化
为主机名,另外getaddrinfo()还能实现自动识别IPv4地址和IPv6地址。
• gethostbyname()和gethostbyaddr()都涉及一个hostent的结构体。
十一、hostent结构体
• 调用gethostbyname()函数或gethostbyaddr()函数后就能返回hostent结构体的相关信息。
structhostent
{
char *h_name; /*正式主机名*/
char **h_aliases; /*主机别名*/
inth_addrtype; /*地址类型*/
inth_length; /*地址字节长度*/
char **h_addr_list; /*指向IPv4或IPv6的地址指 针数组*/
};
十二、addrinfo结构体
structhostent
{
char *h_name; /*正式主机名*/
char **h_aliases; /*主机别名*/
inth_addrtype; /*地址类型*/
inth_length; /*地址字节长度*/
char **h_addr_list; /*指向IPv4或IPv6的地址指 针数组*/
};
十三、addrinfo常见选项值
• 通常服务器端在调用getaddrinfo()之前,ai_flags设置AI_PASSIVE,用于bind()函数(用于端口和地址的绑定,后
面会讲到),主机名nodename通常会设置为NULL。
• 客户端调用getaddrinfo()时,ai_flags一般不设置AI_PASSIVE,但是主机名nodename和服务名servname(端
口)则应该不为空。
• 即使不设置ai_flags为AI_PASSIVE,取出的地址也可以被绑定,很多程序中ai_flags直接设置为0,即3个标志位都
不设置,这种情况 下只要hostname和servname设置的没有问题就可以正确绑定。
/*#include files… */
int main()
{
structaddrinfo hints, *res = NULL;
intrc;
memset(&hints, 0, sizeof(hints));
/*设置addrinfo结构体中各参数 */
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype =SOCK_DGRAM;
hints.ai_protocol =IPPROTO_UDP;
/*调用getaddinfo函数*/
rc =getaddrinfo("localhost", NULL, &hints, &res);
if (rc != 0)
{
perror("getaddrinfo");
exit(1);
}
else
{
printf("Host name is %s\n",res->ai_canonname);
}
exit(0);
}
十四、socket编程常用函数
• socket编程的基本函数有socket()、bind()、listen()、accept()、send()、sendto()、recv()以及recvfrom()等,其
中根据客户端还是服务端,或者根据使用TCP协议还是UDP协议,这些函数的调用流程都有所区别。
2013.11.18 上午