网络编程期末复习

简介: 网络编程期末复习

函数解释

三:套接口编程简介

void bzero(void* dest,size_t nbytes);

  • 将内存块(字符串)的前nbytes个字节清零
  • 参数:
    • dest:内存(字符串)指针
    • nbytes:需要清零的字节数

void memset(void dest,int c,size_t len);

  • 将指针变量 dest所指向的前len字节的内存单元用一个“整数” c 替换,注意 c 是 int 型。dest是 void* 型的指针变量,所以它可以为任何类型的数据进行初始化。
  • 参数:
    • dest:指针变量
    • c:替换后的结果
    • len:需要初始化的前len个字节
  • bzero和memset辨析:
    • bzero:清零
    • memset:初始化为int型的任意值

uint16_t htons(uint16_t host16bitvalue)

  • 将16位主机字符顺序转换成网络字符顺序
  • 参数:
    • host16bitvalue:主机字符顺序

uint16_t ntohs(uint16_t net16bitvalue);

  • ntohs()用来将参数指定的16 位netshort 转换成主机字符顺序.
  • 参数
    • net16bitvalue:网络字符顺序

int inet_aton(const char cp, struct in_addr inp);

  • 将网络地址转成网络二进制的数字
  • inet_aton()用来将参数cp 所指的网络地址字符串转换成网络使用的二进制的数字, 然后存于参数inp 所指的in_addr 结构中.
  • 返回值:
    • 成功则返回非0值,
    • 失败则返回0.

in_addr_t inet_addr(const char* strptr);

  • 将网络地址转成二进制的数字
  • inet_addr()用来将参数cp 所指的网络地址字符串转换成网络所使用的二进制数字. 网络地址字符串是以数字和点组成的字符串, 例如:"163. 13. 132. 68".
  • 返回值:
    • 成功则返回对应的网络二进制的数字
    • 失败返回-1.

int inet_pton(int family,const char strptr,void addrptr);

  • 将点分十进制串转换成网络字节序二进制值
  • 参数:
    • family:选择的协议簇
      • AF_INET:IPv4
      • AF_INET6:IPv6
    • strptr:指向点分十进制串的指针
    • addrptr:指向转换后的网络字节序的二进制值的指针

const char inet_ntop(int af, const void src, char *dst, socklen_t cnt);

  • 将网络字节序二进制值转换成点分十进制串
  • 参数:
    • af:选择的协议簇
      • AF_INET:IPv4
      • AF_INET6:IPv6
    • src:指向网络字节序的二进制值的指针;
    • dst:指向转换后的点分十进制串的指针;
    • cnt:参数是目标的大小,以免函数溢出其调用者的缓冲区。

void bcopy(const void src, void dest, size_t nbytes)

  • bcopy() 函数用来复制内存(字符串)。
  • bcopy() 不检查内存(字符串)中的空字节 NULL。
  • 参数:
    • src:源内存块(字符串)指针
    • dest:目标内存块(字符串)指针
    • nbytes:要复制的内存(字符串)的前 n 个字节长度。

void memcpy ( void dest, const void * src, size_t num );

  • 复制内存内容(忽略\0)
  • bcopy和memcpy辨析:
    • bcopy()与memcpy()一样都是用来拷贝src 所指的内存内容前n 个字节到dest 所指的地址,不过参数src 与dest 在传给函数时是相反的位置。
    • bcopy() 不检查内存(字符串)中的空字节 NULL。
    • memcpy() 并不关心被复制的数据类型,只是逐字节地进行复制,这给函数的使用带来了很大的灵活性,可以面向任何数据类型进行复制。

int bcmp(const void ptr1,const voidptr2,size_t nbytes);

  • 比较内存(字符串)的前n个字节是否相等
  • bcmp() 函数不检查NULL。
  • 参数:
    • ptr1, ptr2 为需要比较的两块内存(或两个字符串),
    • nbytes 为要比较的长度。
  • 返回值:
    • 如果 ptr1, ptr2 的前 nbytes 个字节相等或者 nbytes 等于 0,则返回 0,
    • 否则返回非 0 值。

int memcmp(const voids1,const void*s2,size_t n);

  • 比较内存前n个字节
  • memcmp()用来比较s1 和s2 所指的内存区间前n 个字符。
  • 字符串大小的比较是以ASCII 码表上的顺序来决定,次顺序亦为字符的值。memcmp()首先将s1 第一个字符值减去s2 第一个字符的值,若差为0 则再继续比较下个字符,若差值不为0 则将差值返回。例如,字符串"Ac"和"ba"比较则会返回字符'A'(65)和'b'(98)的差值(-33)。
  • 返回值:
    • 若参数s1 和s2 所指的内存内容都完全相同则返回0 值。
    • s1 若大于s2 则返回大于0 的值。
    • s1 若小于s2 则返回小于0 的值。
  • bcmp和memcmp辨析:
    • bcmp不检查NULL值
    • memcmp不仅检查是否相等,还能检测比较字符串的大小

四:基本 TCP 套接口编程

int socket(int family,int type,int protocol);

  • 创建socket套接字
  • 参数:
    • family:协议栈
      • AF_INET:IPv4
      • AF_INET:IPv6
    • type:类型
      • SOCK_STREAM(TCP):字节流套接字
      • SOCK_DGRAM(UDP):数据报套接字
    • protocol:协议,默认为0

int connect(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen);

  • 建立socket连线
  • connect()用来将参数sockfd 的socket 连至参数serv_addr 指定的网络地址. 结构sockaddr请参考bind(). 参数addrlen 为sockaddr 的结构长度.
  • 参数:
    • sockfd:套接字ID
    • addr_len:结构体sockaddr的长度,通过sizeof取值
    • servaddr:在输入servaddr参数时,记得强制类型转
struct in_addr
{
   
    in_addr_t          s_addr;      //表示32位的IP地址,32位无符号整型
}

struct sockaddr_in
{
   
    uint8_t            sin_len;       //表示该结构体的长度,8位无符号整型
    sa_family_t        sin_family;    //表示套接口使用的协议族,8位无符号整型
    in_port_t          sin_port;      //表示套接口使用的端口号,16位无符号整型
    struct in_addr     sin_addr;      //表示IP地址,32位无符号整型
    char               sin_zero[8];   //该成员基本不使用,总是置为0
}

int bind(int sockfd,const struct sockaddr * myaddr,socklen_t addrlen);

  • 对socket定位
  • 用来给socket绑定对应IP和Port
  • 参数:
    • sockfd:套接字ID
    • addrlen:结构体myaddr的长度,通过sizeof取值
    • myaddr:在输入myaddr参数时,记得强制类型转

int listen(int sockfd,int backlog)

  • 设置服务器能处理的最大连接数
  • 参数:
    • sockfd:套接字ID
    • backlog:最大连接数
  • 返回值:
    • 0:成功
    • -1:失败

int accept(int s, struct sockaddr addr, int addrlen);

  • 接受socket连线
  • accept()用来接受参数s 的socket 连线. 参数s 的socket 必需先经bind()、listen()函数处理过, 当有连线进来时accept()会返回一个新的socket 处理代码, 往后的数据传送与读取就是经由新的socket处理, 而原来参数s 的socket 能继续使用accept()来接受新的连线要求. 连线成功时, 参数addr 所指的结构会被系统填入远程主机的地址数据, 参数addrlen 为scokaddr 的结构长度. 关于机构sockaddr 的定义请参考bind().
  • 返回值:
    • 成功:返回新的socket 处理代码,
    • 失败:返回-1, 错误原因存于errno 中.

int close(int sockfd);

  • 关闭套接字连接
  • 对套接字描述符的访问计数值减1,当减为0时,才执行关闭动作。

int getsockname(int sockfd,struct sockaddr localaddr,socklen_t addrlen);

  • 返回与套接口关联的本地协议地址

int getpeername(int sockfd,struct sockaddr localaddr,socklen_t addrlen);

  • 返回与套接口关联的远程协议地址

pid_t wait(int * statloc);

  • 结束(中断)进程函数(常用)
  • wait()会暂时停止目前进程的执行, 直到有信号来到或子进程结束. 如果在调用wait()时子进程已经结束, 则wait()会程识别码也会一快返回. 如果不在意结束状态值, 则参数 status 可以设成NULL. 子进程的结束状态值请参考waitpid().
  • 返回值:
    • 成功:子进程识别码(PID),
    • 失败:返回-1. 失败原因存于errno 中

pid_t waitpid(pid_t pid,int * statloc,int options)(非阻塞版wait函数);

  • 中断(结束)进程函数(等待子进程中断或
  • waitpid()会暂时停止目前进程的执行, 直到有信号来到或子进程结束. 如果在调用wait()时子进程已经结束, 则wait()会立即返回子进程结束状态值. 子进程的结束状态值会由参数status 返回, 而子进程的进程识别码也会一快返回. 如果不在意结束状态值, 则参数status 可以设成NULL. 参数pid 为欲等待的子进程识别码, 其他数值意义如下:
    • pid<-1 等待进程组识别码为pid 绝对值的任何子进程
    • pid=-1 等待任何子进程, 相当于wait()
    • pid=0 等待进程组识别码与目前进程相同的任何子进程
    • pid>0 等待任何子进程识别码为pid 的子进程

const char inet_ntop(int family,const void addrptr,char * strptr,size_t l en);

  • 将网络字节序二进制值转换成点分十进制串
  • 参数:
    • af:选择的协议簇
      • AF_INET:IPv4
      • AF_INET6:IPv6
    • src:指向网络字节序的二进制值的指针;
    • dst:指向转换后的点分十进制串的指针;
    • cnt:参数是目标的大小,以免函数溢出其调用者的缓冲区。

六:I/O 复用:select 和 poll 函数

int select( int maxfdp1,fd_set readset,fd_set writeset,fd_set exceptset ,const struct timeval timeout);

  • I/O多工机制
  • select()用来等待文件描述词状态的改变. 参数maxfdp1代表最大的文件描述词加1, 参数readset、writeset和exceptset 称为描述词组, 是用来回传该描述词的读, 写或例外的状况. 底下的宏提供了处理这三种描述词组的方式:
    • FD_CLR(inr fd, fd_set* set); 用来清除描述词组set 中相关fd 的位
    • FD_ISSET(int fd, fd_set *set); 用来测试描述词组set 中相关fd 的位是否为真
    • FD_SET(int fd, fd_set*set); 用来设置描述词组set 中相关fd 的位
    • FD_ZERO(fd_set *set); 用来清除描述词组set 的全部位
  • 参数 timeout 为结构timeval, 用来设置select()的等待时间, 其结构定义如下:
  • 微秒级
struct timeval
{
   
   time_t tv_sec;
   time_t tv_usec;
};

int pselect(int maxfdp1,fd_set readset,fd_set writeset,fd_set exceptset ,const struct timespec timeout,const sygset_t * sigmask);

  • 纳秒级

pselect相对于正常的select有两个变化:

  • pselect使用结构timespec,这是Posix.lg实时标准的一个发明,而不使用结构timeval。
struct timespec
{
   
    time_t tv_sec;
    long tv_nsec;
};
  • 这两个结构的区别在第二个成员上:新结构的成员tv-nsec规定纳秒数,而老结构的成员tv-usec规定微秒数。
  • 函数pselect增加了第六个参数:指向信号掩码的指针。这允许程序禁止递交某些信号,测试由这些当前禁止的信号的信号处理程序所设置的全局变量,然后调用pselect,告诉它临时重置信号掩码。

int poll(struct pollfd * fdarray,unsigned long nfds,int timeout);

poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。
poll允许工作在任何描述字上。poll提供了与select相似的功能,但当涉及到流设备时,它还提供附加信息。

int shutdown(int sockfd , int howto);

  • 断开连接
  • 参数:
    • sockfd:套接字
    • howto:断开方式
      • SHUT_RD:关闭读连接
      • SHUT_WR:关闭写连接
      • SHUT_RDWR:关闭读写连接,相当于调用了两遍shutdown函数

uint32_t ntohl(uint32_t net32bitvalue);

  • 将32位网络字符顺序转换成主机字符顺序
  • 参数:
    • net32bitvalue:32位网络字节顺序

ssize_t readline(int filedes,void * buff,size_t maxlen);

  • 从文件描述符filedes一次读取一行数据
  • 参数:
    • filedes:需要读取的文件
    • buff:要将读取的内容保存的缓冲区
    • maxlen:最大读取长度

ssize_t writen(int filedes,const void * buff,size_t nbytes);

  • 向文件描述符filedes一次写长度位n的数据

八:基本 UDP 套接口编程

ssize_t recvfrom(int sockfd,void buff,size_t nbytes,int flags,struct sockad dr from,socklen_t * addrlen);

  • 经socket接收数据
  • recv()用来接收远程主机经指定的socket 传来的数据, 并把数据存到由参数buf 指向的内存空间, 参数len 为可接收数据的最大长度. 参数flags 一般设0, 其他数值定义请参考recv(). 参数from 用来指定欲传送的网络地址, 结构sockaddr 请参考bind(). 参数fromlen 为sockaddr 的结构长度.
  • 参数:
    • sockfd:指向的描述字
    • buff:指向读入或写出缓冲区的指针
    • nbytes:读写字节数
    • flags:一般设0

ssize_t sendto(int sockfd,const void buff,size_t nbytes,int flags,const str uct sockaddr to,socklen_t addrlen);

  • 经socket传送数据
  • sendto() 用来将数据由指定的socket 传给对方主机. 参数s 为已建好连线的socket, 如果利用UDP协议则不需经过连线操作. 参数msg 指向欲连线的数据内容, 参数flags 一般设0, 详细描述请参考send(). 参数to 用来指定欲传送的网络地址, 结构sockaddr 请参考bind(). 参数tolen 为sockaddr 的结果长度.
  • 参数:
    • sockfd:指向的描述字
    • buff:指向读入或写出缓冲区的指针
    • nbytes:读写字节数
    • flags:一般设0

char sock_ntop(const struct sockaddr sockaddr,socklen_t addrlen);

uint32_t htonl(uint32_t host32bitvalue)

  • 将32位主机字符顺序转换成网络字符顺序
  • htonl ()用来将参数指定的32 位hostlong 转换成网络字符顺序.

char inet_ntoa(struct in_addr inaddr);

  • 将网络二进制的数字转换成网络地址
  • inet_ntoa()用来将参数in 所指的网络二进制的数字转换成网络地址, 然后将指向此网络地址字符串的指针返回.

ssize_t readn(int filedes,void * buff,size_t nbytes);

  • 读取长度为n的数据
  • 参数:
    • filedes:文件描述符
    • buff:指向读入或写出缓冲区的指针
    • nbytes:读写字节数

九:基本名字与地址转换

struct hostent gethostbyname(const char hostname);

  • 通过域名获取IP地址
struct hostent{
   
    char *h_name;              // 主机名
    char **h_aliases;          // 别名列表
    int  h_addrtype;          // 主机地址类型
    int  h_length;          // 地址长度
    char **h_addr_list;      // 地址列表
}

struct hostent gethostbyname2(const char hostname,int family);

  • 通过域名获取IP地址
  • 允许指定地址簇,支持IPv6

struct servent getservbyport(int port,const char protoname);

  • 在给定端口号和可选协议后查找相应的服务。

int gethostname(char * name,size_t namelen);

  • 函数gethostname也返回当前主机的名字

struct hostent gethostbyaddr(const char addr,size_t len,int family

  • 通过IP地址获取主机的完整信息

struct servent getservbyname(const char servname,const char * protoname);

  • 根据给定名字查找服务。

简答题

三:套接口编程简介

在套接口编程中,经常看到函数htons的使用,它的作用是什么?

将16位主机字符顺序转换成网络字符顺序。使sort(port)类型的数据能按照网络中的传输方式进行传输。

函数 bcopy 和 memcpy 的区别是什么?

  • bcopy()与memcpy()一样都是用来拷贝src 所指的内存内容前n 个字节到dest 所指的地址,不过参数src 与dest 在传给函数时是相反的位置。
  • bcopy() 不检查内存(字符串)中的空字节 NULL。
  • memcpy() 并不关心被复制的数据类型,只是逐字节地进行复制,这给函数的使用带来了很大的灵活性,可以面向任何数据类型进行复制。

为什么函数 readn 和 writen 都将 void 型指针转换为 char 型指针?

在ANSI C标准中,不允许对void指针进行算术运算如pvoid++或pvoid+=1等,需要转换为char类型指针才能对指针进行加减操作。

为什么诸如套接口地址结构长度这样的值-结果参数要用指针来传递?

调用时,需要传递结构体长度,避免写操作越界,在调用后,参数的结构又是另一个结果,所以需要使用值-结果参数。

在并发服务器程序中,需要调用什么函数派生一个进程,这个函数的特点是什么?

fork函数
特点:一次调用,两次返回,在父进程中,返回子进程的标识,在子进程中,返回0

简述 TCP 的四分节终止序列(四次挥手)。

  1. 客户端向服务器返送FIN J(终止序列)已经ACK应答K
  2. 服务器收到客户端的请求后,发送收到ACK应答J+1
  3. 服务器向客户端发送断开请求FIN K,及ACK应答J+1
  4. 客户端收到请求后,向服务器发送收到应答 K+ 1

在并发服务器程序中,常用 fork 函数派生一个进程,简述其特点

特点:一次调用,两次返回,在父进程中,返回子进程的标识,在子进程中,返回0

四:基本TCP套接口编程

accept 函数的最后一个参数为什么要使用值-结果参数?

因为在accept函数中,调用时,需要传递结构体长度,避免写操作越界,在调用后,参数的结构又是另一个结果,所以需要使用值-结果参数。

简述 TCP 套接口编程中,服务器和客户端的几个主要步骤,TCP 的三路握手是在哪个步骤完成的?

服务器:

  1. 调用 socket 函数创建 socket(侦听socket)
  2. 调用 bind 函数 将 socket绑定到某个ip和端口的二元组上
  3. 调用 listen 函数 开启侦听
  4. 当有客户端请求连接上来后,调用 accept 函数接受连接,产生一个新的 socket(客户端 socket)
  5. 基于新产生的 socket 调用 send 或 recv 或 write 或 read 函数开始与客户端进行数据交流
  6. 通信结束后,调用 close 函数关闭侦听 socket

客户端:

  1. 调用 socket函数创建客户端 socket
  2. 调用 connect 函数尝试连接服务器
  3. 连接成功以后调用 send 或 recv 或 write 或 read 函数开始与服务器进行数据交流
  4. 通信结束后,调用 close 函数关闭侦听socket

三次握手:三次握手在客户端实在connect函数发起的,客户端调用connect向服务器发起连接请求。服务器在accept函数监听到客户端的连接请求,与客户端建立连接,生成与该客户端对应的套接字。

当派生一个进程后,套接口描述字一般需要调用两次 close 才能引发四分节终止序列,为什么?

当创建socket套接字后,与该套接字关联的访问计数值为1,当fork派生一个进程后,访问计数值加1,调用close函数时,是对访问计数值进行减1操作,当访问计数值为0时,才能终止序列。所以需要两次,如果想直接终止程序的话,可以通过shutdown函数操作。

当调用 fork 函数派生一个进程时,返回值有几个?分别是什么含义?

两个,分别在父进程和子进程返回一个返回值。
父进程:返回子进程的标识,通过标识可以对子进程进行操作。
子进程:返回0,子进程拥有唯一的父进程,可以通过函数获取,同时,在子进程内部,不需要获取自身的标识,通过返回值0,可以在接收返回值时,有效的判断是父进程还是子进程。

简述 TCP 套接口编程中,服务器程序所调用的套接口函数有哪些?

  1. 调用 socket 函数创建 socket(侦听socket)
  2. 调用 bind 函数 将 socket绑定到某个ip和端口的二元组上
  3. 调用 listen 函数 开启侦听
  4. 当有客户端请求连接上来后,调用 accept 函数接受连接,产生一个新的 socket(客户端 socket)
  5. 基于新产生的 socket 调用 send 或 recv 或 write 或 read 函数开始与客户端进行数据交流
  6. 通信结束后,调用 close 函数关闭侦听 socket

当派生一个进程后,套接口描述字一般需要调用几次 close 才能正常关闭,为什么?

两次,见 当派生一个进程后,套接口描述字一般需要调用两次 close 才能引发四分节终止序列,为什么?

getsockname 函数的最后一个参数为什么要使用值-结果参数?

getpeername 函数的最后一个参数为什么要使用值-结果参数?

函数原型:

  • int getsockname(int sockfd,struct sockaddr localaddr, socklen_t addrlen):返回与套接口关联的本地协议地址
  • int getpeername(int sockfd,struct sockaddr peeraddr,socklen_t addrlen):返回与套接口关联的远程协议地址

因为在getsockname和getpeername函数中,调用时,需要传递结构体长度,避免写操作越界,在调用后,参数的结构又是另一个结果,所以需要使用值-结果参数。

简述 TCP 套接口编程中,客户程序所调用的套接口函数有哪些?

  1. 调用 socket函数创建客户端 socket
  2. 调用 connect 函数尝试连接服务器
  3. 连接成功以后调用 send 或 recv 函数 或 write 或 read 开始与服务器进行数据交流
  4. 通信结束后,调用 close 函数关闭侦听socket

当派生一个进程后,已存在的套接口描述字的访问计数有什么变化?有什么影响?

已存在套接口描述字访问计数值加1,当调用close函数时,不会直接关闭tcp连接,而是访问计数值减1,所以派生进程后,需要调用2次close才能真正关闭tcp连接。

当派生多个进程后,套接口描述字的访问计数值是如何变化的?

每派生一个进程,套接口描述字的访问计数值加1,每调用一次close,套接口描述字的访问计数值减1.

在 TCP 编程中,三路握手一般是由哪一端调用什么函数发起的?简述三次握手的过程

客户端

  1. 客户端发送连接请求SYN,在连接请求包中带上本次连接序号J。
  2. 服务器收到客户端连接请求后,向客户端返回收到应答J+1(SYN长度为1),并带上服务器向客户端的连接请求SYN K
  3. 客户端收到应答后,客户端连接建立完成,客户端向服务器发送应答K+1

五:TCP 客户-服务器程序例子

请说明 wait 和 waitpid 的区别。

  • 在一个子进程终止前,wait使其调用者阻塞
  • waitpid有一个选项,可以使调用者不阻塞
  • waitpid等待一个指定的子进程,wait等待所有的子进程,返回任一一个终止的子进程

处理 SIGCHLD 信号的作用是什么?

  • 维护子进程的信息,以便父进程在稍后的某个时候取回
  • 结束后告诉父进程wait回收

在套接口编程中,调用函数 Signal(SIGCHLD, sig_chld)的作用是什么?

  • 通知内核对子进程的结束不关心,由内核回收
  • 表示父进程忽略SIGCHLD信号。
  • SIGCHLD信号:该信号是子进程退出的时候向父进程发送的。 子进程结束时, 父进程会收到这个信号。

在 TCP 编程中,为了避免僵尸进程的出现,常用什么函数?为什么?

waitpid。
避免僵尸进程:通过捕获信号SIGCHLD来处理。接着,信号处理程序调用waitpid。
wait函数容易产生阻塞,且在发生多个信号时只执行一次,当有多个僵尸进程产生时,wait不足以避免所有的僵尸进程。

在 TCP 编程中,常用 waitpid 函数避免僵尸进程的出现,而不用 wait 函数,为什么?

见 在 TCP 编程中,为了避免僵尸进程的出现,常用什么函数?为什么?

在 TCP 编程中,如果调用 wait 函数来避免僵尸进程的出现,会出现什么后果?为什么?

wait函数等待所有的子进程,不能针对指定的子进程进行等待,wait在使用时会阻塞调用者,所以使用wait来避免僵尸进程时,可能存在多个子进程终止时,仍有部分子进程作为僵尸进程存在,不足以避免僵尸进程出现。

在 I/O 复用中,要经常使用宏 void FD_ZERO(fd_set *fdset),其作用是什么?

将指定文件的描述符集清空

在 I/O 复用中,要经常使用宏 int FD_ISSET(int fd, fd_set *fdset),其作用是什么?

测试文件描述符是否在该集合中

在函数 int select(int maxfdp1,fd_set readset,fd_set writeset,fd_set exce ptset, const struct timeval timeout)中,如果把第 2、3、4 个参数全部置空,这个函数的作用是什么?

微秒级计时器

在函数 int pselect(int maxfdp1,fd_set readset,fd_set writeset,fd_set exc eptset, const struct timespec timeout,const sygset_t * sigmask)中,如果把第 2 、3、4 个参数全部置空,这个函数的作用是什么?

纳秒级计时器

六:I/O 复用:select 和 poll 函数

I/O 有几种模型?分别是什么?

5种:

  • 阻塞I/O
  • 非阻塞I/O
  • I/O复用(select和poll )
  • 信号驱动I/O ( SIGIO )
  • 异步I/O ( Posix.1的aio-系列函数)

阻塞 I/O 和 I/O 复用两种模型的区别是什么?

  • 阻塞IO:在准备阶段即同步阻塞,应用进程调用I/O操作时阻塞,只有等待要操作的数据准备好,并复制到应用进程的缓冲区中才返回;
  • IO复用:多路IO共用一个同步阻塞接口,任意IO可操作都可激活IO操作,这是对阻塞IO的改进(主要是select和poll、epoll,关键是能实现同时对多个IO端口进行监听)。此时阻塞发生在select/poll的系统调用上,而不是阻塞在实际的I/O系统调用上。IO多路复用的高级之处在于:它能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select等函数就可以返回。

请说明 close 和 shutdown 的区别。

close:描述符的访问计数值减1,当计数值为0时,同时关闭写缓存和读缓存
shutdown:根据指定的关闭方式进行关闭,有读关闭,写关闭,读写关闭,可以实现半关闭,可以直接关闭,而不是调用多次后才完成关闭

I/O 复用模型阻塞于哪个函数调用?它比起阻塞 I/O 模型优势在哪里?

阻塞与select/poll的函数调用。
能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select等函数就可以返回。

请说明 shutdown 的特点。

可以实现TCP的半关闭,可以根据关闭方式实现读关闭,写关闭,读写关闭。调用后就直接关闭,无需多次调用。

在 select 和 pselect 两个函数中,都带有一个参数,分别是结构体 timeval 和 timespec, 这两个结构体有什么不同?

timeval:微秒级
timespec:纳秒级

I/O 复用模型的优点是什么?

阻塞发生在select/poll的系统调用上,而不是阻塞在实际的I/O系统调用上。IO多路复用的高级之处在于:它能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select等函数就可以返回。

函数 select 中,第一个参数 int maxfdp1 的含义是什么?

请说明函数 int select(int maxfdp1,fd_set readset,fd_set writeset,fd_set exceptset,const struct timeval timeout);第 2、3、4 个参数分别代表的含义。

请说明函数 int pselect(int maxfdp1,fd_set readset,fd_set writeset,fd_set exceptset, const struct timespec timeout,const sygset_t * sigmask);第 2、3、4

各参数分别代表的含义。

  • maxfdp1:指集合中所有文件描述符的范围,即所有文件描述符的最大值加1
  • readset:可读文件集合,若集合中对应的文件描述符可写,则返回一个大于0的值
  • writeset:可写文件集合,若集合中对应的文件描述符可写,则返回一个大于0的值
  • exceptset:异常文件集合,若集合中对应的文件描述符可存在,则返回一个大于0的值

shutdown 可以避免 close 的两个限制,分别是什么?

  • close仅将访问计数值减1,为0时才进行关闭
  • close直接将读写的两个方向的数据传输全部关闭

八:基本 UDP 套接口编程

recvfrom 函数的最后一个参数为什么要使用值-结果参数?

因为在recvfrom 函数中,调用时,需要传递结构体长度,避免写操作越界,在调用后,参数的结构又是另一个结果,所以需要使用值-结果参数。

简述 UDP 套接口编程中,服务器所调用的套接口函数有哪些?

  1. 调用 socket 函数创建 socket(侦听socket)
  2. 调用 bind 函数 将 socket绑定到某个ip和端口的二元组上
  3. 调用 recvfrom 函数阻塞到收到客户端发送数据
  4. 调用 sendto 函数向客户端发送应答
  5. 通信结束后,调用 close 函数关闭侦听 socket

简述 UDP 套接口编程中,客户端所调用的套接口函数有哪些?

  1. 调用 socket 函数创建 socket(侦听socket)
  2. 调用 recvfrom 函数阻塞到收到客户端发送数据
  3. 调用 sendto 函数向客户端发送应答
  4. 通信结束后,调用 close 函数关闭侦听 socket

在 UDP 套接口编程中,调用 connect 函数后,程序功能发生了哪些主要变化?

没有三路握手过程。内核只是记录对方的IP地址和端口号,它们包含在传递给connect的套接口地址结构中,并立即返回给调用进程。
对于已连接UDP套接口,与缺省的未连接UDP套接口相比,发生了三个变化:

  • 我们再也不能给输出操作指定目的IP地址和端口号。也就是说,我们不使用sendto,而使用write或send写到已连接UDP套接口上的任何东西都自动发送到由connect所指定的协议地址(例如IP地址和端口号)
  • 我们不用recvfrom而用read或recv。在已连接UDP套接口上由内核为输入操作返回的唯一数据报是那些来自connect 所指定协议地址的数据报。目的地址为已连接UDP套接口的本地协议地址(例如IP地址和端口号),但不是从connect所指定套接口协议地址到达的数据报,不传递给已连接套接口。这就限制了已连接UDP套接口能且只能与一个对方交换数据报。
  • 异步错误由已连接UDP套接口返回给进程,由此推断,未连接UDP套接口不接收任伺异步错误

给一个 UDP 套接口多次调用 connect 可以达到两个目的,分别是什么?

  • 指定新的IP地址和端口号;断开套接口。
  • 断开套接口。

在 TCP 和 UDP 编程中,客户端都可以调用 connect,它们的主要区别是什么?

没有三路握手过程。内核只是记录对方的IP地址和端口号,它们包含在传递给connect的套接口地址结构中,并立即返回给调用进程。

在 UDP 编程中,调用 connect 与不调用 connect 有什么不同?

对于已连接UDP套接口,与缺省的未连接UDP套接口相比,发生了三个变化:

  • 我们再也不能给输出操作指定目的IP地址和端口号。也就是说,我们不使用sendto,而使用write或send写到已连接UDP套接口上的任何东西都自动发送到由connect所指定的协议地址(例如IP地址和端口号)
  • 我们不用recvfrom而用read或recv。在已连接UDP套接口上由内核为输入操作返回的唯一数据报是那些来自connect 所指定协议地址的数据报。目的地址为已连接UDP套接口的本地协议地址(例如IP地址和端口号),但不是从connect所指定套接口协议地址到达的数据报,不传递给已连接套接口。这就限制了已连接UDP套接口能且只能与一个对方交换数据报。
  • 异步错误由已连接UDP套接口返回给进程,由此推断,未连接UDP套接口不接收任伺异步错误

对于 UDP/IPv4 套接口,可传递给 sendto 的最大长度是多少?

65535-20(IP头)-8(UDP头)=65507

函数 poll 和 select 有什么不同?

  • poll涉及流设备时,提供附加信息。
  • poll没有最大连接数限制

九:基本名字与地址转换

已知 struct hostent 结构体定义如下,请说明各个成员的含义。(写在结构体的右边)

struct hostent{
   
    char *h_name;              // 主机名
    char **h_aliases;          // 别名列表
    int  h_addrtype;          // 主机地址类型
    int  h_length;          // 地址长度
    char **h_addr_list;      // 地址列表
}

在选项 RES_USE_INET6 打开时,函数 gethostbyname 和 gethostbyname2 的操作有什么不同?

  • gethostbyname:搜索AAAA记录,若找到,返回 IPv6 地址(h-length=16),否则搜索A记录。若找到,返回IPv4映射的IPv6地址(h-length=16),否则返回错误。
  • gethostbyname2:
    • AF_INET:搜索A记录,若找到,返回IPv4映射的IPv6地址(h-length=16),否则返回错误。
    • AF_INET6:搜索AAAA记录,若找到返回 IPv6地址(h-length=16),否则返回错误。

为什么应用程序会以参数 SHUT_RDWR 来调用 shutdown,而不是仅仅调用 close?

close函数首先减少1个访问计数值,在访问计数值为0时才进行关闭,而shutdown函数的SHUT_RDWR参数不管访问计数值是多少,都可以直接关闭描述字,断开连接。

将 shutdown 的第二个参数改为 SHUT_RD 时,会产生什么结果?

将调用者读数据传输方向的缓存区进行关闭,仍然允许向写缓存区写入数据。

相关文章
|
7月前
|
网络协议 网络架构
计算机网络期末复习——计算大题(一)
计算机网络期末复习——计算大题(一)
283 0
计算机网络期末复习——计算大题(一)
|
7月前
|
网络协议 算法 网络架构
计算机网络期末复习——基础知识汇总(二)
计算机网络期末复习——基础知识汇总(二)
105 0
|
5月前
|
网络协议 网络性能优化 网络虚拟化
《计算机网络》期末复习笔记
《计算机网络》期末复习笔记
|
7月前
|
传感器 网络协议 网络性能优化
《计算机网络》期末复习—第一章:概述
《计算机网络》期末复习—第一章:概述
125 0
|
7月前
《计算机网络》期末复习——第二章:物理层
《计算机网络》期末复习——第二章:物理层
63 0
|
7月前
|
存储 安全
《计算机网络》期末复习——第三章:数据链路层
《计算机网络》期末复习——第三章:数据链路层
157 0
|
7月前
|
传感器 网络协议 网络性能优化
《计算机网络》期末复习——第一章:概述
《计算机网络》期末复习——第一章:概述
110 0
|
网络协议 网络安全 网络性能优化
【计算机网络期末复习】重点知识总复习
【计算机网络期末复习】重点知识总复习
221 1
|
存储 缓存 网络协议
计算机网络期末知识点整理(合工大)
计算机网络期末知识点整理(合工大)
300 0
|
域名解析 网络协议
【计算机网络期末复习】第六章 应用层
【计算机网络期末复习】第六章 应用层
84 0