您的位置:首页 > 理论基础 > 计算机网络

地址族与数据序列----------网络编程(linux----C)

2016-12-16 22:33 232 查看
地址族与数据序列----------网络编程(linux----C)1、分配给套接字的IP地址与端口号(1)网络地址IPv4:4字节地址族。IPv6:16字节地址族。IPv4标准的4字节IP地址分为网络地址和主机(指计算机)地址,分为A、B、C、D、E等类型。(2)用于区分套接字的端口号端口号就是在同一操作系统内为区分不同套接字而设置的,因此无法将1个端口号分配给不同套接字。端口号由16位构成,可分配的端口号范围为0-65535.虽然端口号不能重复,但TCP套接字和UDP套接字不会共用端口号,所以允许重复。例如:如果某TCP套接字使用9190号端口,则其他TCP套接字就无法使用该端口号,但UDP套接字可以使用。2、地址信息的表示应用程序中使用的IP地址和端口号以结构体的形式给出了定义。(1)表示IPv4地址的结构体
struct sockaddr_in
{
sa_family_t  sin_family;		//地址族(Address Family)
uint16_t	sin_port;		//16位TCP/UDP端口号
struct		sin_addr;		//32位IP地址
char 		sin_zero[8];		//不使用
};
//结构体in_addr用来存放32位IP地址
struct in_addr{In_addr_t s_addr; //32位IPv4地址};sockaddr_in成员分析:3、网络字节序与地址变换(1)字节序与网络字节序大端序:高位字节存放到低位地址。小端序:高位字节存放到高位地址。在0x20号开始的地址中保存4字节int类型数0x12345678。整数0x12345678中,0x12是最高位字节,0x78是最低位字节。(2)字节序转换转换字节序函数unsigned short htons(unsigned short);unsigned short ntohs(unsigned short);unsigned long htonl(unsigned long);unsigned long ntohl(unsigned long);htons中的h代表主机(host)字节序。htons中的n代表网络(network)字节序。s表示short,l指的是long。htons是h、to、n、s的组合,解释为“把short型数据从主机字节序转化为网络字节序”。ntohs解释为“把short型数据从网络字节序转化为主机字节序”。实例1、endian_conv.c代码:
#include <stdio.h>#include <arpa/inet.h>int main(int argc,char *argv[]){unsigned short host_port=0x1234;unsigned short net_port;unsigned long host_addr=0x12345678;unsigned long net_addr;net_port=htons(host_port);net_addr=htonl(host_addr);printf("Host ordered port:%#x \n",host_port);printf("Network ordered port:%#x \n",net_port);printf("Host ordered address:%#lx \n",host_addr);printf("Network ordered address:%#lx \n",net_addr);return 0;}
编译:gcc endian_conv.c -o conv执行:./conv结果:4、网络地址的初始化与分配(1)将字符串信息转换为网络字节序的整数型sockaddr_in中保存地址信息的成员为32位整数型。为了分配IP地址,需要将其表示为32位整数型数据。对于IP地址的表示,我们熟悉的是点分十进制表示法,而非整数型数据表示法。函数1:#include  <arpa/inet.h>in_addr_t  inet_addr(const  char *string);成功时返回32位大端序整数型值,失败时返回INADDR_NONE。实例2、函数调用过程inet.addr.c代码:
#include <stdio.h>#include <arpa/inet.h>int main(int argc,char *argv[]){char *addr1="1.2.3.4";char *addr2="1.2.3.256";unsigned long conv_addr=inet_addr(addr1);if(conv_addr==INADDR_NONE)printf("Error occured!\n");elseprintf("Network ordered integer addr:%#lx\n",conv_addr);conv_addr=inet_addr(addr2);if(conv_addr==INADDR_NONE)printf("Error occured!\n");elseprintf("Network ordered integer addr:%#lx\n",conv_addr);return 0;}
编译:gcc inet_addr.c -o addr执行:./addr不仅可以把IP地址转成32位整数型,而且可以检测无效的IP地址。函数2:#include <arpa/inet.h>int  inet_aton(const  char *sting ,  struct  in_addr *addr);成功返回1(true),失败返回0(false)。参数:string:含有需转换的IP地址信息的字符串地址值。addr:将保存转换结果的in_addr结构体变量的地址值。inet_aton函数与inet_addr函数在功能上完全相同,也将字符串形式的IP地址转换为32位网络字节序整数并返回,只不过该函数利用了in_addr结构体,且使用频率更高。实例3、函数调用过程inet_aton.c代码:
#include <stdio.h>#include <stdlib.h>#include <arpa/inet.h>void error_handling(char *message);int main(int argc,char *argv[]){char *addr="127.232.124.79";struct sockaddr_in addr_inet;if(!inet_aton(addr,&addr_inet.sin_addr))error_handling("Conversion error");elseprintf("Network ordered integer addr:%#x\n",addr_inet.sin_addr.s_addr);return 0;}void error_handling(char *message){fputs(message,stderr);fputc('\n',stderr);exit(1);}
编译:gcc inet_aton.c -o aton执行:./aton函数3:#include <arpa/inet.h>char *inet_ntoa(struct  in_addr  adr);成功时返回转换的字符串地址值,失败时返回-1.实例4、inet_ntoa.c代码:#include <stdio.h>#include <stdlib.h>#include <arpa/inet.h>int main(int argc,char *argv[]){struct sockaddr_in addr1,addr2;char *str_ptr;char str_arr[20];addr1.sin_addr.s_addr=htonl(0x1020304);addr2.sin_addr.s_addr=htonl(0x1010101);str_ptr=inet_ntoa(addr1.sin_addr);strcpy(str_arr,str_ptr);printf("Dotted-Decimal notation1:%s\n",str_ptr);inet_ntoa(addr2.sin_addr);printf("Dotted-Decimal notation2:%s\n",str_ptr);printf("Dotted-Decimal notation3:%s\n",str_arr);return 0;}编译:gcc inet_ntoa.c -o ntoa执行:./ntoa(2)网络地址初始化
struct sockaddr_in  addr;char *serv_ip="211.217.168.13";		//声明IP地址字符串char *serv_port="9190";			//声明端口号字符串memset(&addr,0,sizeof(addr));		//结构体变量addr的所有成员初始化为0addr.sin_family=AF_INET;		//指定地址族addr.sin_addr.s_addr=inet_addr(serv_ip);	//基于字符串的IP地址初始化addr.sin_port=htons(atoi(serv_port));		//基于字符串的端口号初始化
(3)客户端地址信息初始化上述的网络地址信息初始化过程主要针对服务器端而非客户端。服务器端的准备工作通过bind函数完成,而客户端则通过connect函数完成。因此,函数调用前需准备的地址值类型也不同。服务器端声明sockaddr_in结构体变量,将其初始化为赋予服务器端IP和套接字端口号,然后调用bind函数;而客户端则声明sockaddr_in结构体,并初始化为要与之连接的服务器端套接字的IP和端口号,然后调用connect函数。INADDR_ANY每次创建服务器端套接字都要输入IP地址会有些繁琐,此时可如下初始化地址信息:
struct  sockaddr_in  addr;char *serv_port="9190";			//声明端口号字符串memset(&addr,0,sizeof(addr));		//结构体变量addr的所有成员初始化为0addr.sin_family=AF_INET;		//指定地址族addr.sin_addr.s_addr=htonl(INADDR_ANY);addr.sin_port=htons(atoi(serv_port));		//基于字符串的端口号初始化
利用常数INADDR_ANY分配服务器端的IP地址,若采用这种方式,则可自动获取运行服务器端的计算机IP地址,不必亲自输入。若同一计算机中已分配多个IP地址,则只要端口号一致,就可以从不同的IP地址接收数据。因此,服务器端中优先考虑这种方式。客户端中除非带有一部分服务器端功能,否则不会采用。示例:hello_server.c和hello_client.c运行过程./hserver  9190分析可知,向main函数传递的9190端口号。通过此端口创建服务器套接字并运行程序,但未传送IP地址,因为可以通过INADDR_ANY指定IP地址。./hclient  127.0.0.1  9190(4)向套接字分配网络地址函数:#include <sys/socket.h>int  bind (int  sockfd,struct  sockaddr*myaddr,socklen_t  addrlen);成功时返回0,失败时返回-1。参数:sockfd:要分配地址信息(IP地址和端口号)的套接字文件描述符。myaddr:存有地址信息的结构体变量地址值。addrlen:第二个结构体变量的长度。服务器端常见套接字初始化过程:
int 	serv_sock;struct 	sockaddr_in 	serv_addr;char *serv_port="9190";/*创建服务器端套接字(监听套接字)*/serv_sock=socket(PF_INET,SOCK_STREAM,0);/*地址信息初始化*/memset(&serv_addr,0,sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=htonl(INADRR_ANY);serv_addr.sin_port=htons(atoi(serv_port));/*分配地址信息*/bind(serv_sock,(struct  sockaddr*)&serv_addr,sizeof(serv_addr));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: