• WebServer高性能服务器 NK


    一、LINUX网络编程基础API

    1、socket地址API

    1.主机字节序和网络字节序

    即小端字节序和大端字节序,linux提供htonl、htons、ntohl、ntohs4个函数来实现主机字节序和网络字节序的转换。

    2.通用socket地址

    socket网络编程接口中表示socket地址的是sockaddr结构体:

    struct socadd{
         sa_family_t sa_family;
         char sa_data[4];          
    }

    sa_family_t为地址族类型(地址族与协议族对应)

    linux下的通用socket结构体:

    3.专用socket地址

    UNIX本地域协议族专用socket地址结构体:

    sockaddr_un\sockaddr_in\sockaddr_in6

     

    4.IP地址转换函数

    in_addr_t inet_addr(const char * strptr):点分十进制的IPv4地址转换为用网络字节序整数表示的IPv4,失败INADDR_NONE;

    int inet_aton(const char* cp, struct in_addr* inp):和inet_addr功能相同,但结果是转化为存储于参数inp指向的地址结构中,成功1,是啊白0;

    char * inet_ntoa( struct in_addr in):将用网络字节序整数表示的IPv4地址转化为用点分十进制字符串表示的IPv4地址。

    同时适用于IPv4和IPv6的函数:

    指定cnt大小的宏定义:

    2、创建socket

     domain参数:使用哪个底层协议,TCP/IP协议族:PF_INET,PF_INET6,UNIX本地域协议族:PF_UNIX;

    type参数:指定服务类型,SOCK_STREAM(流服务,TCP)和SOCK_UGRAM(数据报服务,UDP);

    protocal参数:在前两个参数构成的协议集合下,再选择一个具体的协议,默认为0(别动它)。

    socket系统调用成功时返回一个socket文件描述符,失败返回-1并设置errno。

    3、命名socket

     bind将my_addr所指的socket地址分配给未命名的sockfd文件描述符,addrlen参数指出该socket地址长度

    bind成功时返回0,失败返回-1并设置errno

    两种常见errno:

    EACCES:被绑定的地址是受保护的,仅超级用户能访问。

    EADDRINUSE:被绑定地址正在使用。

    4、监听socket

    创建监听队列:

     sockfd参数:指定被监听的socket;

    backlog参数:提示内核监听队列的最大长度,长度超过将不受理;

    listen成功时返回0,失败则返回-1并设置errno。

    5、接受连接

    从listen监听队列中接受一个连接:

    sockfd参数:执行过listen系统调用的监听socket;

    addr参数:获取被接受连接的远端socket地址;

    addrlen参数:addr参数获取的socket地址的长度;

    accept成功返回一个新的连接socket,该socket唯一地标识了被接受的这个连接,服务器可通过读写该socket来与被接受连接对应的客户端通信;

    accpet失败返回-1并设置errno。

    6、发起连接

     客户端主动与服务器建立连接的函数:

    sockfd参数:由socket系统调用返回一个socket;

    serv_addr参数:服务器监听的socket地址;

    addr_len参数:指定这个地址的长度;

    connect成功返回0,一旦成功建立连接,sockfd就唯一标识了这个连接,客户端就可以通过读写sockfd来与服务器通信,

    失败则返回-1,并设置errno,常见errno:

    ECONNREFUSED:目标端口不存在,连接被拒绝。

    ETIMEDOUT:连接超时。

    7、关闭连接

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

     fd参数是待关闭的socket

    close系统调用并非总是立即关闭一个连接,而是将fd的引用计数减1,只有当fd为0时才真正关闭连接,

    系统调用默认将使父进程中打开的socket的引用计数加1,因此必须在父进程和子进程中都对该socket执行close调用才能将连接关闭。

    强制关闭:

     sockfd参数:待关闭的socket;

    howto参数:

    shutdown成功返回0,失败返回-1并设置errno。

    8、数据读写

    1.TCP数据读写

    TCP数据流读写的系统调用:

    recv读socket上数据,buf指定读缓冲区的位置,len指定读缓冲区的大小,flags参数通常为0;

    recv成功时返回实际读取到的数据的长度,可能会小于预期长度,这时可能会多次调用recv才能得到完整数据;

    recv返回0就意味着通信对方已经关闭连接;

    recv出错时返回-1并设置errno。

    send写socket上数据,buf指定写缓冲区的位置,len指定写缓冲区的大小;

    send成功时返回实际写入数据的长度;

    send失败时返回-1并设置errno。

    flags参数为数据的收发提供额外的控制:

     MSG_OOB选项给应用程序提供了发送和接收带外数据的方法。

    2.UDP数据读写

    recvfrom读取sockfd上的数据,buf指定读缓冲区的位置,len指定读缓冲区的大小,

    因为UDP通信没有连接的概念,所以每次读取数据都需要获取发送端的socket地址,即参数src_addr所指的内容,

    addrlen指定src_addr地址的长度。

    sendto往sockfd上写数据,buf指定读缓冲区的位置,len指定读缓冲区的大小,

    dest_addr参数指定接收端的socket地址,

    addrlen指定src_addr地址的长度。

    flags和send/recv系统调用的flags一致,返回值也相同。

    注意,如果奖最后两个参数都设置为NULL,那么他们也可以用于面向连接的数据读写。

    3.通用数据读写函数

    TCP和UDP通用的数据读写系统调用:

    msghdr结构体定义:

    msg_name成员指向一个socket地址,它指定通信双方的socket地址,

    对于TCP协议,该成员变量无意义,必须被设置为NULL,因为对数据流socket来说,对方的地址已经知道。

    msg_namelen成员指定msg_name所指socket的长度。

    msg_ios成员是iovec结构体类型指针:

    iovec结构体封装了一块内存的起始位置和长度,

    msg_iovlen指定这样的iovec结构对象有多少个。

    recvmsg的分散读(scatter read):数据被读取并存在msg_iovlen块分散的内存中,这些内存的位置和长度由msg_iov指向的数组指定。

    sendmsg的集中读(gather write):msg_iovlen块分散内存中的数据将被一并发送。

    msg_control和msg_controllen成员用于辅助数据的传送。

    msg_flags成员无须设定,它会赋值recvmsg/sendmsg的flags参数的内容以影响程序读写过程,

    recvmsg调用结束前会将某些更新后的标志设置到msg_flags中。

    注,recvmsg和sendmsg的flags参数含义和recv、send一致。

     9、带外标记

    内核通知应用程序带外数据到达的两种方式:I/O复用和SIGURG信号。

    应用程序得到带外数据需接收的通知后,用sockatmark判断sockfd是否处于带外标记:

     即下一个被读取到的数据是否是带外数据

    socktamark返回1,此时就可以用带MSG_OOB标志的recv调用来接收带外数据,

    如果不是,则返回0。

    10、地址信息函数

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

    getsockname获取sockfd对应的本端socket地址,并将其存储在address参数指定的内存,该socket地址的长度存储在address_len参数指向变量中,

    如果实际长度大于address所指内存区的大小,则该socket地址将被截断,

    getsockname成功返回0,失败返回-1并设置errno。

    getpeername获取sockfd对应的远端socket地址,其他参数含义和 getsockname一致。

    11、socket选项

    fcntl系统调用是控制文件描述符熟悉的通用POSIX方法

    两个专门用来读取和设置的两个系统调用:

    sockfd参数:指定被操作的socket;

    level参数:指定要操作哪个协议的选项(属性,如IPv4、IPv6、TCP等);

    option_name参数:指定选项的名字(见下表);

    option_value参数:被操作选项的值;

    option_len参数:被操作选项的长度。

    getsockopt和setsockopt成功返回0,失败返回-1并设置errno。

    部分重要的socket选项实现: (后续补充2022.04.25记)

    1.SO_REUSEADDR选项

    2.SO_RCVBUF和SO_SNDBUF选项

    3.SO_RCVLOWAT好SO_SNDLOWAT选项

    4.SO_LINGER选项


    12、网络信息API

    1.gethostbyname和gethostbyaddr

    gethostbyname函数根据主机名称获取主机的完整信息,gethostbyaddr函数根据IP地址获取主机的完整信息。

    gethostbyname获取主机顺序:本地/etc/hosts配置文件中查找主机->DNS服务器。

    两个函数的定义:

    name参数:指定主机的主机名

    addr参数:指定目标主机的IP地址

    len参数:指定addr所指IP地址的长度

    type参数:指定addr所指IP地址的类型(AF_INET和AF_INET6)

    这两个函数的返回值都是hostent结构体类型的指针:

    2.getservbyname和getservbyport

    getservbyname函数根据名称获取某个服务的完整信息,getservbyport函数根据端口号获取某个服务的完整信息,

    它们都是通过读取/etc/service文件来获取服务信息的,其结构体如下:

     注:

    上面的4个函数都是不可重入的,即非线程安全的。

    在netdb.h头文件给出了它们的可重入版本,即在它们的尾部加入 _r(re-entrant)

    3.getaddrinfo

    getaddrinfo函数即能通过主机名获取IP地址,也能通过服务名获取端口号(内部分别使用了gethostbyname和getservbyname)

    getaddinfo定义:

     

     hostname参数:可以接收主机名,也可以接收字符表示的IP地址。

    service参数:可以接收服务名,也可以接收字符串表示的十进制端口号。

    hints参数:应用程序给getaddrinfo的一个提示,以对getaddrinfo的输出进行更精确的控制。hists的参数为NULL时,表示允许getaddrinfo反馈任何可用的结果。

    result参数:指向一个链表,该链表用于存储getaddrinfo反馈的结果。

    getaddrinfo反馈的每一条结果都是addrinfo结构体类型的对象,其定义如下:

     使用hints参数的时候,可设置ai_flags、ai_family、ai_socktype、ai_protocol四个字段,其他字段必须设置为NULL

    由于getaddrinfo会隐式地分配内存,所以必须使用配套的一个函数来释放其分配的内存:

    4.getnameinfo

    getnameinfo函数能通过socket地址同时获取以字符串表示的主机名和服务名(分别使用了gethostbyaddr和getservport)

    getnameinfo函数定义如下:

     getnameinfo将返回的主机名存储在艾host参数指向的缓存中,

    将服务名存储在serv参数指向的缓存中,

    hostlen和servlen参数分别指定这两块缓存的长度,

    flags参数表:

     getaddrinfo和genameinfo函数成功时返回0,失败时返回错误码:

     Linux下的strerror函数能将数值错误码errno转换成易读的字符串,下面的函数也可将上表中的错误码转换成其字符串形式:

     二、高级I/O函数

    1、pipe函数

    2、dup函数和dup2函数

    3、readv函数和writev函数

    4、sendfile函数

    5、mmap函数和munmap函数

    6、splice函数

    7、tee函数

    8、fcntl函数

    ****参考说明****

    《Linux高性能服务器编程》--游双

  • 相关阅读:
    汇编随笔(第一章 基础知识)
    排序集锦(rough)
    如何让编写的Java代码规范整洁
    二分法查询数据java实现
    归并排序的学习与java实现
    小白的软件测试之路
    PyInstaller打包python脚本
    数据库SQL优化总结
    JQuery选择器
    软件测试面试题
  • 原文地址:https://www.cnblogs.com/nkcat/p/16190480.html
Copyright © 2020-2023  润新知