Linux网络编程学习笔记(一)网络编程基础API

这里是本人对Linux网络编程的学习做一个记录,主要参考书籍如下:

  • Linux高性能服务器编程
  • Unix网络编程 卷1:套接字联网API
    socket是一个实现内核空间与用户空间的通信的接口。

一、四层网络模型

二、socket地址API

(1)通用socket地址

socket地址结构体

  1. //头文件:<bits/socket.h>
  2. struct sockaddr {
  3. //地址族类型(与协议族对应,如ipv4/ipv6)
  4. sa_family_t sa_family;
  5. //实际存储地址
  6. char sa_data[14];
  7. }

地址族与协议族的关系表

协议族 地址族 描述
AF_UNIX PF_UNIX UNIX本地域协议族
AF_INET PF_INET TCP/IPv4协议
AF_INET6 PF_INET6 TCP/IPv6协议

通过以上结构体的定义,可以看出sa_data只有14位,无法保存更长的地址数据,因此,一般使用专用的socket地址来保存特定的socket地址

(2)专用socket地址

unix本地域地址:

  1. //头文件:<sys/un.h>
  2. struct sockaddr_un {
  3. //地址族(这里就是AF_UNIX)
  4. sa_family_t sin_family;
  5. //socket文件存放的地址
  6. char sun_path[108];
  7. }

ipv4地址族

  1. //头文件<netinet/in.h>
  2. struct sockaddr_in {
  3. //地址族(这里是AF_INET)
  4. sa_family_t sin_family;
  5. //地址结构体
  6. struct in_addr sin_addr;
  7. //端口
  8. in_port_t sin_port;
  9. //sockaddr结构体填充的大小
  10. unsigned char sin_zero[sizeof (struct sockaddr) -
  11. (sizeof (unsigned short int)) -
  12. sizeof (in_port_t) -
  13. sizeof (struct in_addr)];
  14. }

ipv4地址结构体in_addr结构:

  1. //头文件<netinet/in.h>
  2. struct in_addr {
  3. //整型的地址
  4. in_addr_t s_addr;
  5. };

ipv6地址族

  1. //头文件<netinet/in.h>
  2. struct sockaddr_in6 {
  3. //地址族(这里是AF_INET6)
  4. sa_family_t sin_family;
  5. //端口
  6. in_port_t sin6_port;
  7. //ipv6流信息
  8. uint32_t sin6_flowinfo;
  9. //ipv6地址结构体
  10. struct in6_addr sin6_addr;
  11. //ipv6范围ID
  12. uint32_t sin6_scope_id;
  13. };

ipv6地址结构体in6_addr结构:

  1. struct in6_addr {
  2. union {
  3. uint8_t__u6_addr8[16];
  4. #ifdef __USE_MISC
  5. uint16_t __u6_addr16[8];
  6. uint32_t __u6_addr32[4];
  7. #endif
  8. } __in6_u;
  9. #define s6_addr__in6_u.__u6_addr8
  10. #ifdef __USE_MISC
  11. # define s6_addr16__in6_u.__u6_addr16
  12. # define s6_addr32__in6_u.__u6_addr32
  13. #endif
  14. };

三、ip地址转换函数

这里只列举ipv4的地址,ipv6的相关函数类似。

我们经常看到ip地址存储在数据库中,有人习惯存储为int型,有人习惯存储为varchar(字符串)。其实在linux底层已经内置了两种存储类型之间的转换函数。

(1)inet_addr
  • 原型:extern in_addr_t inet_addr (const char *cp)

  • 参数说明:const char *cp表示传入的是一个只读字符指针(其实就是一个字符串)

  • 作用:将一个字符串的ipv4地址转换为int型

  • 返回值:返回转换后的结果

举个例子:

  1. #include <arpa/inet.h>
  2. #include <stdio.h>
  3. /**
  4. * 实现一个将字符串型的ipv4地址转换为整型
  5. * @param char *address:传入的是一个字符串型的ipv4地址
  6. * @return long
  7. */
  8. long ip2long(char *address)
  9. {
  10. //返回的整型ip地址
  11. long ip;
  12. //调用系统函数计算
  13. ip = inet_addr(address);
  14. return ip;
  15. }
  16. int main(void)
  17. {
  18. printf("the address of 8.8.8.8:%d\n", ip2long("8.8.8.8"));
  19. return 0;
  20. }
(2)inet_aton
  • 原型:extern int inet_aton (const char *cp, struct in_addr *inp)

  • 参数说明:

    • const char *cp:要传入的字符串地址

    • struct in_addr *inp:要传入的用来存储转换后的结果的结构体指针

  • 作用:将一个字符串的ipv4地址转换为int型(它与inet_addr的区别就是它不直接返回结果,需要将声明一个用来存储结果的结构体指针)

  • 返回值:如果转换成功,则返回1;否则为0

注:struct in_addr的结构:

  1. //头文件<netinet/in.h>
  2. struct in_addr {
  3. //整型的地址
  4. in_addr_t s_addr;
  5. };

举个例子:

  1. #include <stdio.h>
  2. #include <arpa/inet.h>
  3. /**
  4. * 实现一个将字符串型的ipv4地址转换为整型
  5. * @param char *address : 传入的是一个字符串型的ipv4地址
  6. * @return long
  7. */
  8. long ip2int(char *address)
  9. {
  10. //存储转换是否成功状态
  11. int res;
  12. //存储转换结果
  13. long ip = 0;
  14. //需要使用in_addr结构体
  15. struct in_addr iaddr;
  16. //传入原始字符串指针和用来保存结果的指针
  17. res = inet_aton(address, &iaddr);
  18. //处理结果1表示成功,0表示失败
  19. if (res == 1) {
  20. ip = iaddr.s_addr;
  21. }
  22. return ip;
  23. }
  24. int main()
  25. {
  26. printf("address of 8.8.8.8:%d\n", ip2int("8.8.8.8"));
  27. return 0;
  28. }
(3)inet_ntoa
  • 原型:extern char *inet_ntoa (struct in_addr in)

  • 参数说明:

    • struct in_addr in:要传入用来转换的地址结构体变量
  • 作用:将一个整型的ipv4地址转换为字符串型的ipv4地址

  • 返回值:char *

举个例子:

  1. #include <stdio.h>
  2. #include <arpa/inet.h>
  3. /**
  4. * 整型ipv4地址转换为字符串型的地址
  5. * @param long ip :要转换的整型ipv4地址
  6. * @return char *
  7. */
  8. char *long2ip(long ip)
  9. {
  10. //用来存储结果
  11. char *address;
  12. //声明地址结构体变量
  13. struct in_addr iaddr;
  14. //赋值给结构体成员
  15. iaddr.s_addr = ip;
  16. //调用系统函数转换
  17. address = inet_ntoa(iaddr);
  18. return address;
  19. }
  20. int main()
  21. {
  22. printf("ip address of 134744072:%s\n", long2ip(134744072));
  23. return 0;
  24. }