• 【网络编程】TCPIP_3_地址族与数据序列



    前言

    说明:

    • demo 基于 Linux。

    3. 地址族与数据序列

    // 	调用 bind 函数分配IP地址和端口号。
    //	成功时返回0,失败时返回-1
    #include <sys/socket.h>
    int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);
    
    /* 	补充 client 部分 */
    //	成功时返回0,失败时返回-1
    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    

    3.1 分配给套接字的 IP 地址与端口号

    参考: 李柱明博客园

    3.2 参数 IP 地址

    由于原生的参数 struct sockaddr 类型不够直观,所以采用类型转换的 struct sockaddr_in 只要保证其字节大小一样,然后把其当做一段微内存即可。

    3.2.1 IPV4 地址的结构体

    // 原生,不建议直接用
    struct sockaddr {
    	sa_family_t	sa_family;	/* address family, AF_xxx	*/
    	char		sa_data[14];	/* 14 bytes of protocol address	*/
    };
    
    // 格式转换后,推荐使用
    struct sockaddr_in
    {
        sa_family_t sin_family;  //地址族(Address Family)
        uint16_t sin_port;       //16 位 TCP/UDP 端口号
        struct in_addr sin_addr; //32位 IP 地址
        char sin_zero[8];        //为了保证其大小一致,目前不使用
    };
    
    struct in_addr
    {
        in_addr_t s_addr; //32位IPV4地址
    }
    

    3.2.2 地址族(Address Family)

    成员 sa_family_t sin_family;

    具体地址族类型参考 地址族(附件)

    地址族(Address Family) 含义
    AF_INET IPV4用的地址族
    AF_INET6 IPV6用的地址族
    AF_LOCAL 本地通信中采用的 Unix 协议的地址族

    3.2.3 端口号

    成员 uint16_t sin_port;

    16 byte。
    以网络字节序保存。(CPU 分大小端,为了统一,网络协同使用一种字节序来保证数据正确,到对端后再按需转换即可)

    小知识

    • 可以这样区分 IP 和 端口号:一个主机可以共用一个 IP,端口号 用来区分主机程序。
    • 知名端口是要把该端口分配给特定的应用程序,范围是 0~1023 ,HTTP 的端口号是 80 ,FTP 的端口号是20和21。

    3.2.4 IP 地址

    成员 struct in_addr sin_addr;

    32 byte。
    以网络字节序保存。

    小知识

    • 127.0.0.1 表示本机 IP。协议规定的。

    3.2.5

    成员 char sin_zero[8];

    为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节,目前没有其它用途。

    3.3 实例参考

    注意:客户端创建socket后使用的函数是connect()。

    #define cHOST "192.168.112.128" // 服务器端IP
    #define cPORT 8080              // 服务器进程端口号
    
    // 客户端
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET; // IPV4
    serv_addr.sin_addr.s_addr = inet_addr(cHOST); // 地址
    serv_addr.sin_port = htons(cPORT); //端口
    //调用 connect 函数向服务器发送连接请求
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
    	error_handling("connect() error!");
    

    3.4 网络字节序

    3.4.1 字节序

    得先了解大小端的问题。
    本人的快速记忆是 小高高,意思是 字节放在位。
    因为CPU有大小端的差异,如果不统一网络字节序就会导致数据交互错乱,如图:

    网络字节序统一使用大端。
    所以在收发前,先对数据进行检查、转换,再进行网络传输。

    3.4.2 字节序转换相关函数

    前后缀:

    • h:表示 host ,主机字节。
    • n:表示 network,网络字节。
    • s:表示 short。
    • l:表示 long。
    unsigned short htons(unsigned short);
    unsigned short ntohs(unsigned short);
    unsigned long htonl(unsigned long);
    unsigned long ntohl(unsigned long);
    

    3.5 字符串转为网络字节序的整数形

    3.5.1 inet_addr()

    函数 inet_addr()

    inet_addr是一个计算机函数,功能是将一个点分十进制的IP转换成一个长整数型数(u_long类型)等同于inet_addr()。

    注意:一字节的范围为 [0:255]

    // 返回:若字符串有效则将字符串转换为32位二进制网络字节序的IPV4地址,否则为INADDR_NONE
    #include <arpa/inet.h> // Linux
    in_addr_t inet_addr(const char* strptr);
    
    // 例子:
    unsigned long conv_addrA = inet_addr("1.2.3.4"); // conv_addrA 为 0x4030201
    
    unsigned long conv_addrB = inet_addr("1.2.3.256"); // conv_addr ERR,因为范围为 [0:255]
    

    3.5.2 inet_aton()

    函数 inet_aton()

    函数 inet_aton() 和 函数 inet_addr() 在功能上是一样的,也是将字符串形式的IP地址转换成整数型的IP地址。
    不同的是该函数得到的结果保存到 in_addr 结构体参数里面了,这样就可以判断有没有转换成功。

    /*	
    	string: 含有需要转换的IP地址信息的字符串地址值
    	addr: 将保存转换结果的 in_addr 结构体变量的地址值
    	成功时返回 1 ,失败时返回 0
    */
    #include <arpa/inet.h>
    int inet_aton(const char *string, struct in_addr *addr);
    

    3.5.3 inet_ntoa()

    函数 inet_ntoa()

    该函数更好和 inet_aton() 相反,n -> a。
    把网络字节整数型序转换为地址点分字符串形式。

    特别注意

    • 该函数特点:其返回值为指针,实际内存实在函数里面申请的,该函数的实现里,只申请一次,下次调用时使用同样的已申请了的内存,(而不是重新申请,返回新的指针),所以下次调用该函数时,会把上次数据覆盖。
    • 使用注意:获取到返回的指针后,在下次调用该函数前,必须使用完毕或者把数据拷贝到新的内存里慢慢享受。
    #include <arpa/inet.h>
    char *inet_ntoa(struct in_addr adr);
    

    3.6 网络地址初始化参考

    struct sockaddr_in addr;
    char *serv_ip = "192.168,1.2";          	//声明IP地址族
    char *serv_port = "8080";                  	//声明端口号字符串
    memset(&addr, 0, sizeof(addr));            	//结构体变量 addr 的所有成员初始化为0
    addr.sin_family = AF_INET;                 	//制定地址族
    addr.sin_addr.s_addr = inet_addr(serv_ip); 	//基于字符串的IP地址初始化
    addr.sin_port = htons(atoi(serv_port));    	//基于字符串的IP地址端口号初始化
    

    地址族(附件)

    /* Supported address families. */
    #define AF_UNSPEC	0
    #define AF_UNIX		1	/* Unix domain sockets 		*/
    #define AF_LOCAL	1	/* POSIX name for AF_UNIX	*/
    #define AF_INET		2	/* Internet IP Protocol 	*/
    #define AF_AX25		3	/* Amateur Radio AX.25 		*/
    #define AF_IPX		4	/* Novell IPX 			*/
    #define AF_APPLETALK	5	/* AppleTalk DDP 		*/
    #define AF_NETROM	6	/* Amateur Radio NET/ROM 	*/
    #define AF_BRIDGE	7	/* Multiprotocol bridge 	*/
    #define AF_ATMPVC	8	/* ATM PVCs			*/
    #define AF_X25		9	/* Reserved for X.25 project 	*/
    #define AF_INET6	10	/* IP version 6			*/
    #define AF_ROSE		11	/* Amateur Radio X.25 PLP	*/
    #define AF_DECnet	12	/* Reserved for DECnet project	*/
    #define AF_NETBEUI	13	/* Reserved for 802.2LLC project*/
    #define AF_SECURITY	14	/* Security callback pseudo AF */
    #define AF_KEY		15      /* PF_KEY key management API */
    #define AF_NETLINK	16
    #define AF_ROUTE	AF_NETLINK /* Alias to emulate 4.4BSD */
    #define AF_PACKET	17	/* Packet family		*/
    #define AF_ASH		18	/* Ash				*/
    #define AF_ECONET	19	/* Acorn Econet			*/
    #define AF_ATMSVC	20	/* ATM SVCs			*/
    #define AF_RDS		21	/* RDS sockets 			*/
    #define AF_SNA		22	/* Linux SNA Project (nutters!) */
    #define AF_IRDA		23	/* IRDA sockets			*/
    #define AF_PPPOX	24	/* PPPoX sockets		*/
    #define AF_WANPIPE	25	/* Wanpipe API Sockets */
    #define AF_LLC		26	/* Linux LLC			*/
    #define AF_IB		27	/* Native InfiniBand address	*/
    #define AF_MPLS		28	/* MPLS */
    #define AF_CAN		29	/* Controller Area Network      */
    #define AF_TIPC		30	/* TIPC sockets			*/
    #define AF_BLUETOOTH	31	/* Bluetooth sockets 		*/
    #define AF_IUCV		32	/* IUCV sockets			*/
    #define AF_RXRPC	33	/* RxRPC sockets 		*/
    #define AF_ISDN		34	/* mISDN sockets 		*/
    #define AF_PHONET	35	/* Phonet sockets		*/
    #define AF_IEEE802154	36	/* IEEE802154 sockets		*/
    #define AF_CAIF		37	/* CAIF sockets			*/
    #define AF_ALG		38	/* Algorithm sockets		*/
    #define AF_NFC		39	/* NFC sockets			*/
    #define AF_VSOCK	40	/* vSockets			*/
    #define AF_KCM		41	/* Kernel Connection Multiplexor*/
    #define AF_QIPCRTR	42	/* Qualcomm IPC Router          */
    #define AF_SMC		43	/* smc sockets: reserve number for
    				 * PF_SMC protocol family that
    				 * reuses AF_INET address family
    				 */
    

    参考:

  • 相关阅读:
    Linux-3.14.12内存管理笔记【构建内存管理框架(3)】
    Linux-3.14.12内存管理笔记【构建内存管理框架(2)】
    Linux-3.14.12内存管理笔记【构建内存管理框架(1)】
    Linux-3.14.12内存管理笔记【建立内核页表(3)
    Linux power supply class(1)_软件架构及API汇整【转】
    Linux-3.14.12内存管理笔记【建立内核页表(2)】-低端内存的建立
    Linux-3.14.12内存管理笔记【建立内核页表(1)】
    linux防火墙相关 iptables
    shell 备份 source code
    crontab清理日志
  • 原文地址:https://www.cnblogs.com/lizhuming/p/15149539.html
Copyright © 2020-2023  润新知