【Linux网络编程】基础API

总结《Linux高性能服务器编程》第5章

第五章 Linux网络编程基础API

socket地址API

  • socket最开始的含义是一个IP地址和端口对(ip,port),它唯一地表示了使用TCP通信的一端;

  • 主机字节序和网络字节序
    • 字节序分为大端字节序/网络字节序(big endian)和小端字节序/主机字节序(little endian)

    • 大端字节序是指一个整数的高位字节(23~31 bit)存储在内存的低地址处,低位字节(0
      ~7 bit)存储在内存的高地址处;

    • Linux提供了如下4个函数来完成主机字节序和网络字节序之间的转换

      #include<netinet/in.h>
      unsigned long int htonl(unsigned long int hostlong);
      unsigned short int htons(unsigned short int hostshort);
      unsigned long int ntohl(unsigned long int netlong);
      unsigned short int ntohs(unsigned short int netshort);
      
  • 通用socket地址
    • socket网络编程接口中表示socket地址的是结构体sockaddr以及sockaddr_storage;

      #include<bits/socket.h>
      struct sockaddr
      {
      sa_family_t sa_family; //地址族类型(sa_family_t)的变量,与协议族类型对应
      char sa_data[14]; //存放socket地址值
      }
      

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eHVGWxFa-1668427347952)(img/Linux高性能服务器编程/image-20221025085429539.png)]

  • 专用socket地址
    • UNIX本地域协议族:结构体sockaddr_un;
    • TCP/IP协议族:结构体sockaddr_in和sockaddr_in6;
    • 所有专用socket地址(以及sockaddr_storage)类型的变量在实际使用时都需要转化为通用socket地址类型sockaddr;
  • IP地址转换函数
    • 将用点分十进制字符串表示的IPv4地址转化为用网络字节序整数表示的IPv4地址

      in_addr_t inet_addr(const char*strptr);
      int inet_aton(const char*cp, struct in_addr*inp);
      int inet_pton(int af,const char*src, void*dst);
      
    • 将用网络字节序整数表示的IPv4地址转化为用点分十进制字符串表示的IPv4地址

      char*inet_ntoa(struct in_addr in);
      const char*inet_ntop(int af, const void*src, char*dst, socklen_t cnt);
      

创建socket

  • Linux中,所有东西都是文件,socket也是可读、可写、可控制、可关闭的文件描述符

  • 使用socket系统调用可创建一个socket

    #include<sys/types.h>
    #include<sys/socket.h>
    int socket(int domain,int type,int protocol);
    
    • domain参数告诉系统使用哪个底层协议族:PF_INET、PF_INET6、PF_UNIX;
    • type参数指定服务类型:SOCK_STREAM、SOCK_UGRAM;
    • protocol参数是在前两个参数构成的协议集合下,再选择一个具体的协议,默认设置为0;

命名socket

  • 将一个socket与socket地址绑定称为给socket命名,系统调用是bind

    #include<sys/types.h>
    #include<sys/socket.h>
    int bind(int sockfd, const struct sockaddr*my_addr, socklen_t addrlen);
    
    • bind将my_addr所指的socket地址分配给未命名的sockfd文件描述符;
    • 绑定时两种常见错误:
      • EACCES,被绑定的地址是受保护的地址,仅超级用户能够访问;
      • EADDRINUSE,被绑定的地址正在使用中;

监听socket

  • 服务器通过listen调用来被动接受连接;

  • 使用listen系统调用创建监听队列以存放待处理的客户连接

    #include<sys/socket.h>
    int listen(int sockfd,int backlog);
    
    • sockfd参数指定被监听的socket,backlog参数提示内核监听队列的最大长度,监听队列的长度如果超过backlog,服务器将不受理新的客户连接;

接受连接

  • accept系统调用从listen监听队列中接受一个连接

    #include<sys/types.h>
    #include<sys/socket.h>
    int accept(int sockfd, struct sockaddr*addr, socklen_t*addrlen);
    

发起连接

  • 客户端需要通过connect系统调主动与服务器建立连接;

    #include<sys/types.h>
    #include<sys/socket.h>
    int connect(int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen);
    
    • 连接时两种常见错误:
      • ECONNREFUSED,目标端口不存在,连接被拒绝;
      • ETIMEDOUT,连接超时;

关闭连接

  • 关闭该连接对应的socket;

  • 通过关闭普通文件描述符的系统调用来完成;

    #include<unistd.h>
    int close(int fd);
    
    • fd:file describeter,文件描述符
    • 每次将fd的引用计数减1,只有当fd的引用计数为0时,才真正关闭连接;
  • 无论如何都要立即终止连接,使用shutdown系统调用

    #include<sys/socket.h>
    int shutdown(int sockfd,int howto);
    

数据读写

  • TCP数据读写
    • 对文件的读写操作read和write同样适用于socket;

    • socket编程接口提供了专用于socket数据读写的系统调用:

      #include<sys/types.h>
      #include<sys/socket.h>
      ssize_t recv(int sockfd,void*buf,size_t len,int flags);
      ssize_t send(int sockfd,const void*buf,size_t len,int flags);
      
  • UDP数据读写
    • socket编程接口中用于UDP数据报读写的系统调用

      #include<sys/types.h>
      #include<sys/socket.h>
      ssize_t recvfrom(int sockfd, void*buf, size_t len, int flags, struct sockaddr* src_addr, socklen_t* addrlen);
      ssize_t sendto(int sockfd,const void*buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);
      
  • 通用数据读写函数
    • TCP流数据/UDP数据报均可以使用

      #include<sys/socket.h>
      ssize_t recvmsg(int sockfd,struct msghdr*msg,int flags);
      ssize_t sendmsg(int sockfd,struct msghdr*msg,int flags);
      
      //msg参数是msghdr结构体类型的指针
      

带外标记

  • 内核通知应用程序带外数据到达的两种常见方式:I/O复用产生的异常事件和SIGURG信号;

  • 使用sockatmark系统调用判断sockfd是否处于带外标记,即下一个被读取到的数据是否是带外数据

    #include<sys/socket.h>
    int sockatmark(int sockfd);
    

地址信息函数

  • 获取一个连接socket的本端以及远端的socket地址

    #include<sys/socket.h>
    int getsockname(int sockfd, struct sockaddr*address, socklen_t* address_len);
    int getpeername(int sockfd, struct sockaddr*address, socklen_t* address_len);
    

socket选项

  • 读取和设置socket文件描述符属性的方法

    #include<sys/socket.h>
    int getsockopt(int sockfd,int level,int option_name, void* option_value, socklen_t* restrict option_len);
    int setsockopt(int sockfd,int level, int option_name, const void* option_value, socklen_t option_len);
    
    • 常用socket选项

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F1QJ2auL-1668427347953)(img/Linux高性能服务器编程/image-20221025093741649.png)]

网络信息API

  • socket地址的两个要素,即IP地址和端口号,都是用数值表示的,不便于记忆和扩展;

  • 可用使用网络信息API实现主机名到IP地址的转换等功能;

  • 获取主机的完整信息
    #include<netdb.h>
    struct hostent* gethostbyname(const char*name);
    struct hostent* gethostbyaddr(const void*addr, size_t len,int type);
    
    • gethostbyname:根据主机名称获取主机的完整信息;
    • gethostbyaddr:根据IP地址获取主机的完整信息;
  • 获取主机的完整信息
    #include<netdb.h>
    struct servent* getservbyname(const char*name, const char*proto);
    struct servent* getservbyport(int port, const char*proto);
    
    • getservbyname:根据名称获取某个服务的完整信息;
    • getservbyport:根据端口号获取某个服务的完整信息;
  • getaddrinfo
    #include<netdb.h>
    int getaddrinfo(const char*hostname, const char*service,const
    struct addrinfo* hints, struct addrinfo** result);
    
    • 既能通过主机名获得IP地址,也能通过服务器名获得端口号;
  • getnameinfo
    #include<netdb.h>
    int getnameinfo(const struct sockaddr*sockaddr,socklen_t addrlen, char*host, socklen_t hostlen, char*serv, socklen_t servlen, int flags);
    
    • 通过socket地址同时获得以字符串表示的主机名和服务器名;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值