《Unix网络编程》卷1:套接字联网API(第3版):广播、多播、信号驱动I/O、线程

全书共31章+附录。

计划安排:从第19章开始内容更深入,逐渐看不懂,故后续章节精简。
时间安排:计划时间1.5个月 == 6个周末 == 12个自然日。
2017.08.05    第01-03章:TCP/IP简介、传输层、套接字编程简介
2017.08.06    第04-06章:基本TCP编程、TCP客户端/服务器程序、I/O复用
2017.08.12    第07-09章:套接字选项、基本UDP编程、基本SCTP编程
2017.08.13    第10-12章:SCTP客户端/服务器程序例子、名字与地址互换、IPv4和IPv6互操作性
2017.08.19    第13-15章:守护进程和inetd超级服务器、高级I/O、Unix域协议
2017.08.20    第16-18章:非阻塞I/O、ioctl操作、路由套接字
2017.08.26    第19-27章:广播、多播、信号驱动I/O、线程、tcpdump

>>第19章丶密钥管理套接字
此章内容略。(目前的基础很难读懂)

>>第20章丶广播


单播:一个进程就与另一个进程通信。TCP只支持单播寻址。
《Unix网络编程》卷1:套接字联网API(第3版):广播、多播、信号驱动I/O、线程_第1张图片
图解要点:
(1) 多播支持在IPv4中是可选的,在IPv6中是必需的;
(2) IPv6不支持广播。使用广播的任何IPv4程序一旦移植到IPv6就必须改用多播重新编写;
(3) 广播和多播要求用于UDP或原始IP,它们不能用于TCP。

ARP,地址解析协议。IPv4的基本组成部分之一。使用链路层广播而不是IP层广播。ARP的广播请求为:IP地址为a.b.c.d的系统两名身份,告诉我你的硬件地址。
DHCP,动态主机配置协议。
NTP,网络时间协议。
路由守护进程,routed是最早实现且最常用的路由守护进程之一,它在一个局域网上广播自己的路由表。

SIGALRM信号引起的竞争状态,使用alarm函数和SIGALARM信号是对读操作设置超时的一个常用办法,这个微秒的错误在网络应用程序中比较常见,有三个正确的解决办法:
(1) 使用pselect;
(2) 使用sigsetjmp和siglongjmp
(3) 使用从信号处理函数到主循环的IPC(典型为管道)

>>第21章丶多播


单播地址标识单个IP接口;
广播地址标识某个子网的所有IP接口;一般用于局域网。
多播地址标识一组IP接口,既可用在局域网也可以跨广域网。

>>第25章丶信号驱动式I/O


信号驱动式I/O是指:进程预先告知内核,使得当某个描述符上发生某事时,内核使用信号通知相关进程。曾被称作异步I/O,但不是真正的异步I/O。

套接字的信号驱动式I/O要求进程执行以下3个步骤:
(1) 建立SIGIO信号的信号处理函数;
(2) 设置该套接字的属主,通常使用fcntl的F_SETOWN命令设置;
(3) 开启该套接字的信号驱动式I/O,通常通过使用fcntl的F_SETFL命令打开O_ASYNC标志完成。

>>第26章丶线程


并发服务器程序中,父进程accept一个连接,fork一个子进程,该子进程处理与该连接对端的客户之间的通信。
但该fork调用却存在一些问题:
(1) fork是昂贵的,fork要把父进程的内存映像复制到子进程,并在子进程中复制所有描述符。
(2) fork返回之后父进程之间信息的传递需要进程间通信IPC机制。

同一进程内的所有线程除了共享全局变量外还共享:
进程指令、大多数数据、打开的文件描述符、信号处理函数和信号处置、当前工作目录、用户ID和组ID。

每个线程有各自的:线程ID、寄存器集合、栈、errno、信号掩码、优先级。

线程创建
#include
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
Compile and link with -pthread.
// pthread_create相当于进程的fork

每个线程都有许多属性(attribute):优先级、初识栈大小、是否应该成为一个守护线程等。
可以在创建线程时通过初始化一个取代默认设置的 phtread_attr_t 变量指定这些属性。
通常情况下我们采用默认设置时,把attr参数指定为空指针。

线程终止
#include
int pthread_join(pthread_t thread, void **retval);
Compile and link with -pthread.
// pthread_join相当于进程的waitpid
// 如果本线程未曾脱离,它的线程ID和退出状态将一直留存到调用进程内的某个其他线程对它调用pthread_join

#include
int pthread_detach(pthread_t thread);
Compile and link with -pthread.
// 如果一个线程需要知道另一个线程什么时候终止,那就最好保持第二个线程的可汇合状态。

#include
void pthread_exit(void *retval);
Compile and link with -pthread.

线程ID
#include
pthread_t pthread_self(void);
Compile and link with -pthread.
// pthread_self相当于进程的getpid

互斥锁
#include
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

条件变量
#include
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_signal(pthread_cond_t *cond);
// 等待wait和唤醒signal相应条件变量上的单个线程

int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_broadcast(pthread_cond_t *cond);
// 一个线程唤醒多个线程需要使用broadcast

【调试测试小程序】


tcpdump
一边从网络读入分组一边显示关于这些分组的大量信息
$ tcpdump '(udp and port daytime) or icmp'
// 只显示所指定的准则匹配的那些分组
$ tcpdump 'tcp and port 80 and tcp[13:1] & 2 !=0'
// 只显示源端口或目的端口为13的UDP数据报亦或ICMP分组
$ tcpdump 'tcp and tcp[0:2] > 7000 and tcp[0:2] <= 7005'
// 只显示源端口或目的端口为80切设置了SYN标志的TCP分节。





2017.08.26
全书基本完... (除去部分更深入的内容,后续有需要时作为资料翻阅)

你可能感兴趣的:(Linux/Unix)