linux c/c++

时间:2023-03-09 15:32:41
linux c/c++
 string 字符串操作

 操作数的都是 ( char * )型,操作数必须是指向字符串的指针("a"),不能是字符('a'),操作时不考虑末尾的'\0'。

 size_t strlen( const char *s );    字符串求长,返回字符串或指针的实际大小,和 sizeof() 不同,比如创建字符数组 strlen 只返回其中字符串的大小,不包括 '\0'
 char *strrev( char *s );    字符串反转,不包括 NULL
 char *strcpy( char *dest, const char *src );    字符串复制, dest 必须有足够的空间来容纳 src 的字符串, dest 空间不够时结果是为定义的(结果显示增大了空间去容纳 src 的字符),dest 不能是字符指针
 int atoi( const char *nptr );    字符串转化为整数
 char *strcat( char *dest, const char *src );    字符串连接
 int strcmp( const char *s1, const char *s2 );    字符串比较,区分大小写
 int strcasecmp(const char *s1, const char *s2);    不区分大小写比较,在头文件 strings.h 中,可在字符串指针和字符数组之间相互比较,注意地址范围
 int strncasecmp(const char *s1, const char *s2, size_t n);    不区分大小写比较,只比较 s1 前 n 个字符
 char *strchr( const char *s, int c );    查找字符,返回首次出现 c 的位置的指针,如果 s 中不存在 c 则返回 NULL
  - n- )字符设为 '\0', strings.h 中

 void perror(const char *s);
 sprintf( buf, "hello world! %s\n", string );    将字符串写到 buf 中,而不是标准输出
 int scanf(const char *format, ...);    成功返回读取到是字符数,失败返回 EOF,目标是指针(数组指针)时不用 "&"
 int fscanf( FILE *stream, const char *format, ... );    从文件流中读取一个单词,不包含空格,读取的内容存到字符数组里,以 '\0' 结尾
 int sscanf(const char *str, const char *format, ...);
 int vscanf(const char *format, va_list ap);
 int getc(FILE *stream);    从文件流中读取一个字符
 int getchar(void);    从标准输入中读取一个字符,用 ASCII 码将字符转换为 int
 char *gets(char *s);    从 stdin 中读取一行放入 s 中,只到遇到 EOF 或者 newline
 int fgetc(FILE *stream);
 ,则读到 size- 个字符时结束,并在最后补充,则读取所有字符,并在最后补充  个字符。读取的字符包括换行符; stream 为文件指针

 文件 I/O 编程

 ) O_NOCTTY(如果 pathname 指的是终端设备,则不将此设备分配作为此进程的控制终端) O_NONBLOCK(如果打开的是一个 fifo 、块特殊文件或字符特殊文件则本次打开和后续 I/O 操作设为非阻塞) O_SYNC(使每次 write 都等到物理 I/O 操作完成) 中的一个或多个进行“ | ”运算构成; mode 只有创建文件时才使用,权限设置;失败返回 -

 ssize_t read(  个字节(linux);返回  时标是读到文件尾;
 ssize_t write( int fd, const void *buf, size_t count );    如果读写的大小 count 超出了给出字符串的大小不会出错,读文件后不会删除内容
 int close( int filedes );    进程结束内核会自动关闭打开的文件
 off_t lseek ((除非指定 O_APPEND); off_t 相当于 signed 

 FILE *fopen(const char *path, const char *mode);    mode 为 "r" 表示以只读放是打开文件, r 只读, w 只写, a 追加, t 文本文件(可省略不写), b 二进制文件,+ 读和写;凡用“r”打开一个文件时,该文件必须已经存在,有 + 时可以读写;用“w”打开的文件只能向该文件写入,若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件;若要向一个已存在的文件追加新的信息,只能用“a”方式打开文件,如果指定文件不存在则尝试创建该文件;把一个文本文件读入内存时,要将ASCII码转换成二进制码,而把文件以文本方式写入磁盘时,也要把二进制码转换成ASCII码,因此文本文件的读写要花费较多的转换时间,对二进制文件的读写不存在这种转换;标准输入文件(键盘),标准输出文件(显示器),标准出错输出(出错信息)是由系统打开的,可直接使用;出错返回 NULL
 FILE *fdopen(int fildes,const char * mode); fdopen()会将参数fildes 的文件描述词,转换为对应的文件指针后返回
 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
 int fclose(FILE * stream);

 int ioctl( int fd, int cmd, ...);    串口的波特率等设置,光盘的操作...; ioctl( fd, CDROMEJECT, NULL ) 弹出光驱,用 O_NONBLOCK 打开光驱,因为光驱中可能没有光盘
 ; readset 是被监控是否有输入的文件描述符集,不监控时设为 NULL,writeset 被监控是否可以输出的文件描述符集; exceptset 被监控是否由错误产生的文件描述符集; timeval 监控超时时间,设为 NULL 表示一直阻塞到有文件描述符被监控到有变化;成功返回  个集合中有指定变化的文件描述符数目,超时返回 ,失败返回 -
 FD_ZERO( &rset );    将文件描述符集 rset 的所有位清
 FD_SET( , &rset );    设置文件描述符集  ,监控文件描述符为  的文件( fd_set rfds; FD_SET( , rfds )
 FD_CLR( fileno( stdin ), &rset );    将文件描述符集 rset 的 bit  置
 FD_ISSET( socketfd, &rset );    若文件描述符集 rset 的 socketfd 位置 ,返回真,有输入时就被置
 ),超时而描述符没有就绪则返回 ,失败返回 -(例 fds[].fd = ; fds[].events = POLLIN; 设置事件 -> fds[].revents & POLLIN 判断事件是否发生)
 ,失败返回 -
 int lstat( const char *path, struct stat *buf );    和 stat 区别在于如果文件是软链接,会获取软链接本身的属性
 int fstat( const int filedes, struct stat *buf);    和 stat 区别在于他使用文件描述符

 int S_ISREG( buf.st_mode );    普通文件
 int S_ISDIR( buf.st_mode );    目录
 int S_ISCHR( buf.st_mode );    字符设备文件
 int S_ISBLK( buf.st_mode );    块设备
 int S_ISFIFO( buf.st_mode );    有名管道
 int S_ISLNK( buf.st_mode );    软链接
 int S_ISSOCK( buf.st_mode );    套结字文件

 int S_ISUID( buf.st_mode );    执行时设置用户 ID
 int S_ISGID( buf.st_mode );    执行时设置组 ID
 int S_ISVTX( buf.st_mode );    保存正文
 int S_IRWXU( buf.st_mode );    用户(所有者)读、写、执行
 int S_IRUSR( buf.st_mode );    用户读
 int S_IWUSR( buf.st_mode );    用户写
 int S_IXUSR( buf.st_mode );    用户执行
 int S_IRWXG( buf.st_mode );    组读、写、执行
 int S_IRGRP( buf.st_mode );    组读
 int S_IWGRP( buf.st_mode );    组写
 int S_IXGRP( buf.st_mode );    组执行
 int S_IRWXO( buf.st_mode );    其他读、写、执行
 int S_IROTH( buf.st_mode );    其他读
 int S_IWOTH( buf.st_mode );    其他写
 int S_IXOTH( buf.st_mode );    其他执行

 int MAJOR( buf->st_rdev );    获取主设备号
 int MINOR( buf->st_rdev );    获取次设备号

 time_t time( time_t *tp );    返回系统时间给 tp ,返回自 epoch 到现在的秒数;成功返回值也是 tp,失败返回 -
 ,失败返回 -;使用时不要使用结构体指针
 char *ctime( time_t *tp );    将日历时间转换为字符串返回,必须包含 time.h 头文件,不然会出现段错误
 struct tm *gmtime( time_t );
 sturct tm *localtime( time_t );    将日历时间转换为结构体记录的时间
 char *asctime( const struct *tm );    将结构体时间转换为字符串返回
 size_t strftime( char *s, size_t max, const char *format, const struct tm *tm );    将结构体记录时间转换为自定义格式的字符串
 time_t mktime( struct tm *tm );    将结构体记录的时间转换为日历时间
 clock_t clock(void);    成功返回程序开始到调用此函数时使用 CPU 的时间,不考虑子进程等,标准 POSIX 精确到10ms

 DIR *opendir( const char *name );    成功返回 DIR* 形态的目录流,失败返回 NULL
 struct dirent *readdir( DIR *dir );    每次读取一条目录结构;成功返回 dirent 指针,失败返回 NULL
 ;错误原因存在 errno 中
 void rewinddir( DIR *dirp );    回绕目录,回到目录流开始处,不用关闭目录

 ssize_t readlink( 

 struct passwd *getpwuid( uid_t uid );    在 pwd.h 中,获得 uid 对应用户的属性信息,失败返回 NULL
 struct group *getgrgid( gid_t gid );    在 grp.h 中,失败返回 NULL

 多进程编程

 pid_t getpid( void );    获得调用进程的 id
 pid_t getppid( void );
 char *getenv( const char *name );    获取环境变量
 int putenv( const char *str );    新建环境变量( str like " name = string " )
 int setenv( const char *name, const char *value, int rewrite );    设置环境变量,若已存在,则参考 rewrite 参数
  ,父进程返回子进程 pid,失败返回 - 给父进程
  ), 成功返回新的文件描述符
 int dup2( int fildes, int fildes2 );    进程内部复制文件描述符,如果 fildes2 已经是一个文件描述符,则先关闭,成功则返回 fildes2
 pid_t wait(
 pid_t waitpid( pid_t pid,  等待任何子进程, >  等待进程 id 和 pid 相等的子进程, ==  等待其组 id 等于调用进程的组 id 的任一子进程, < - 等待其组 id 等于 pid 的绝对值的任一子进程; options 设置等待方式,  不设置, WNOHANG 如果没有任何已结束的进程则立即返回, WUNTRACED 如果子进程进入暂停状态则立即返回

  );    成功不返回任何值,失败返回-;pathname 是执行文件的全路径名,arg0 是文件执行的第一个参数,以 (  表示命令行参数的结束
 int execv( const char *pathname, char *const argv[] );
 , char *const envp[] );    envp 是新程序的环境变量
  个是封装的 execve
  );
 int execvp( const char *filename, char *const argv[] );
 E 传递环境变量表,L 单独的参数传递(最后需要一个 NULL),V 传一个指针数组作为命令行参数,P 按照 PATH 查找新程序

 void fflush( stdout );    刷新输出缓冲区(强制 printf 提交内容)
 , stdin );    输入字符串

 void exit( int status );    stdlib.h, 返回内核前做些清理工作,包括调用 Exit handler, 彻底关闭 I/O 流(将缓冲区数据都提交给内核
 void _exit( int status );    unistd.h, 立即返回内核,不执行 exit handler, 不刷新 I/O 流
  个 exit handler,按注册顺序逆序调用;成功返回
 int on_exit( void ( *func )( int, void * ),void *arg );    注册 exit handler, 函数有两个参数,一个 int 参数(是系统回调函数时传给函数进程的退出值),另一个参数是指针 arg(任何指针都可做参数),参数的值为程序执行完后的值,这时缓冲区内容被删除了,堆栈区内容没有被删除

 void getpgrp()    返回调用进程的进程组 id (进程组组长的 id )
 void setpgid()    参加一个现有进程组或创建一个新进程组,创建守护进程 daemon ,创建时最好关闭所有文件描述符等
 int setsid();    如果调用此函数的进程不是一个进程组组长就创建一个新对话期( session )(多个进程组集合),此进程变为新对话期的首进程,成为新进程组的组长,此进程没有控制终端;是进程组组长则返回出错
 void chdir("/tmp");    改变工作目录
 );    将 umask 改为
 pid_t sysconf( _SC_OPEN_MAX );    返回系统允许打开的文件描述符最大数目
 pause();    暂停程序

 void openlog( const char *indent, int option, int facility );    使用 syslog 可以没有这个函数; indent 指向的字符串将出现在每条消息的最前面; option 为 LOG_CONS 表示当向 syslog 守护进程传送消息失败时把消息写入系统控制台, LOG_PID 表示守护进程的 pid 将出现在每条消息中, LOG_NDELAY LOG_NOWAIT LOG_ODELAY LOG_PERROR; facility 为 LOG_DAEMON 表示消息由系统守护进程发送, LOG_AUTH LOG_AUTHPRIV LOG_CRON LOG_FTP LOG_KERN LOG_NEWS LOG_SYSLOG LOG_USER LOG_UUCP LOG_LOCAL0~LOG_LOCAL7 OG_LPR OG_MAIL
 void syslog( int priority, const char *format,... );    向 syslogd 守护进程送出消息(写入 /var/log/messages 中); priority 表示消息紧急程度,可以是 LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG; format 是写入消息的字符串,可以和 printf 一样使用格式化串
 void closelog( void );    使用 syslog 可以没有这个函数;

 进程间通信

 void ( *signal( int signum, void (*handler)(int)) )(int);    可靠性低,在一个信号处理程序运行时接收到其他信号可能打断当前处理程序运行,可用 sigaction() 代替;成功返回可用信号处理函数( void (*)(int) ),失败返回 SIG_ERR; handler 时信号处理函数的函数指针,有个 int 参数(为系统传给处理函数的信号值),还可以是 SIG_IGN(忽略该信号)、 SIG_DFL(采用默认行为)
 ,失败返回 -
  则取消设置的闹钟;成功则返回上一个闹钟还剩多少时间,失败返回 -
 void abort(void);    结束进程,并向父进程发送 SIGABRT 信号

 int WIFEXINTED( int status );    判断子进程的返回状态是不是正常,正常退出返回真
 int WEXITSTATUS( int status );    返回子进程正常退出的状态值
 int WIFSIGNALED( int status );    判断子进程退出状态是否是非正常退出,非正常退出返回真
 int WTERMSIG( int status );    返回非正常退出状态的信号

  ,不阻塞任何信号
 int sigfillset( sigset_t *set );    将信号集合置位,阻塞相应的信号

 int sigpending( sigset_t *set );    将正在被阻塞的信号记录到集合中,获取阻塞了的信号集合
  则返回真,用来判断集合中是否由此信号
 int sigprocmask( int how, const sigset_t *set, sigset_t *oldset );    用来获得和改变调用进程的信号掩码,当前信号集合会赋值给 oldset;使用时在关键代码前设置掩码,然后执行关键代码,之后获取被阻塞的信号,逐步处理信号; how = SIG_BLOCK 信号集合掩码设置为当前信号集合与 set 的并集, how = SIG_UNBLOCK 设置为当前信号集合减去 set 中的信号, how =SIG_SETMASK 设置为 set

 int sigaction( int signum, const struct sigaction *act, struct sigaction *oldact );    signum 不能是 SIGSTOP 或者 SIG_KILL, oldact 返回以前的 act,可以指定为 NULL

 ] );    无名管道,写入 fd[], 从 fd[] 读取,只能在有亲缘关系的进程间通信;成功返回 ,失败返回 -

 ,读端关闭写端再写将产生 sigpipe 信号,默认结束进程

 ;shmflg 是进程对该共享内存的操作模式,SHM_RDONLY 表示只读模式, 表示可读可写;成功返回共享内存的虚拟地址起始地址(数组名),失败返回 -
 ,失败返回 -
 ,失败返回 -

 (若干个信号量组合在一起形成信号量数组,其实 nsems 就是指定数组元素个数); semflg 标志相当于信号量的访问权限;成功返回信号量标志码,失败返回 -
  个参数 buf; IPC_RMID 将信号量集从内存中删除; GETALL 读取信号量集中的所有信号量值; GETNCNT 返回正在等待资源的进程数目; GETPID 返回最后一个执行 semop 操作的进程 pid; GETVAL 返回信号量集中单个的信号量的值; GETZCNT 返回正在等待玩空空闲的资源的进程数目; SETALL 设置信号量集中的所有信号量的值; SETVAL 设置信号量集中的一个单独信号量的值,被设置的值在 union semun 类型的第  个参数的 val 中;最后的省略号表示可能有第  个参数,如果 cmd 要设置初值就是第  个参数

  则无数据),若发送的最长消息是 ,则定义结构体:];};, ptr 即指向这个结构体,接受这可以使用消息类型以非先进先出的次序; flag 为 IPC_NOWAIT 时,当消息队列满会使得 msgsnd 立即出错返回,errno 被置为 EAGAIN ,若不设为 IPC_NOWAIT,进程会一直阻塞直到有空闲空间或系统删除了此队列( errno 被置为 EIDRM )或捕捉到信号从信号处理程序返回( errno 被置为 EINTR );成功返回 ,失败返回 -
  返回队列中的第一个消息, type >  返回队列中消息类型为 type 的第一个消息, type <  返回队列中消息类型小于或等于 type 绝对值,且其类型值又最小的消息(设置优先级); flag 值为 IPC_NOWAIT 使操作不阻塞,这是如果没有指定消息,则出错返回 ENOMSG,不为 IPC_NOWAIT 时处理方式和 msgsnd 一样;成功返回数据长度,失败返回 -

 多线程编程初步

 int pthread_create( pthread_t *thread, pthread_attr_t *attr, void *(*func)(void*), void *arg);    thread 是被创建线程的标识; attr 是线程的属性的指针,NULL 为使用默认属性; func 被创建线程的程序代码( (void*) funcname ),无返回值; arg 是 func 的参数,是一个指针,可为 NULL。
 pthread_exit( void *reval );    线程自行结束,retval 存放线程退出状态
 ,失败 EINVAL、 ESRCH 或其他(失败原因可能是这个线程是分离的)

 pthread_mutex_t mutex;
 pthread_mutex_init( &mutex, NULL );    在主线程中初始化锁为解锁状态
 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;    在编译时初始化为解锁状态,不用上面的步骤咯
 pthread_mutex_lock( &mutex );    在访问对象前加锁( P 操作 ),如果已被加锁,则阻塞直到锁打开
 pthread_mutex_unlock( &mutex );    访问对象后解锁( V 操作 )
 pthread_mutex_trylock( &mutex );    加锁对象已被加锁,立即返回,返回值为 EBUSY

  时此信号在进程间共享,否则只能在当前进程的所有线程共享; value 给出信号量初值;成功返回 ,失败返回 -
 ;当 sem 为  时阻塞;成功返回 ,失败返回 -
 ;当有线程阻塞时调用这个函数使得其中一个进程不再阻塞,选择机制由线程调度策略决定;成功返回  ;失败返回 -
 ,失败返回 -

  MB 的堆栈,与进程相同优先级;绑定是将线程“绑”在一个轻进程上,被绑定的进程具有较高的响应速度;分离状态决定了线程以什么方式终结自己,非分离线程只有等待创建的线程结束才能释放自己占用的资源( pthread_join 返回时创建的线程擦才结束),而分离线程不会被其他线程所等待,运行结束就释放资源
 int pthread_attr_destroy( pthread_attr_t *attr );
 int pthread_attr_setscope( pthread_attr *attr, PTHREAD_SCOPE_SYSTEM );    设置绑定状态,PTHREAD_SCOPE_SYSTEM 为绑定,PTHREAD_SCOPE_PROCESS 为非绑定
 int pthread_attr_setdetachstate( pthread_attr_t *attr, int detachstate );    第二个参数选择 PTHREAD_CREATE_DETACHED 为分离, PTHREAD_CREATE_JOINABLE 为不分离
 int pthread_cond_timewait();    留出足够时间让函数 pthread_create 执行完,避免错误;设置一个分离线程,如果他运行很快,他可能在函数 pthread_create 返回之前就终止,这样函数就可能返回错误的线程号

 int pthread_attr_setschedparam( pthread_attr_t *attr, const struct sched_param *param );    设置线程优先级

 int pthread_cancel( pthread_t tid );    一个线程杀死另一个线程时调用, tid 是线程标识
 int pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );    设置线程属性拒绝被杀死, PTHREAD_CANCEL_ENABLE 表示允许被杀死(缺省)
 int pthread_setcanceltype( PTHREAD_CANCEL_DEFDERRED, NULL );    设置延后被杀死(缺省),PTHREAD_CANCEL_ASYNCHRONOUS 立即被杀死
 void pthread_testcancel( void );    用于设置杀死点,在延迟杀死的情况下,线程会在收到杀死请求后延迟至第一个杀死点时被杀死;杀死点是在被杀死的进程中,杀死点有调用 testcancel 的点和引起进程阻塞的系统调用( sleep )处,
 int pthread_detach( pthread_t tid );    设置线程不需要被 pthread_join, 因为已经结束的线程没有被 pthread_join 将会在系统中累积僵尸进程

 网络编程

  指定 family 和 type 的默认协议号;成功则返回 sockfd,失败返回 -
 ,失败返回 -
  ,失败返回 -

  次握手建立一个连接;成功返回 

 ssize_t sendto(  时等于 send; flags 发送标识,一般为 ; dest_addr 数据接收端地址结构体的指针;addrlen 数据接收端地址结构体大小;成功返回实际发送的数据,失败返回 -
 ssize_t recvfrom( 

 ssize_t send(  B( 8.5 K )
 ssize_t recv( 时等于 write/read, flags 参数为 MSG_DONTROUTE send 不查找路由表(目标在本地网络),MSG_OOB send/recieve 带外数据, MSG_PEEK recieve 查看数据并不从系统缓冲区移走数据, MSG_WAITALL recieve 阻塞,等待所有数据,返回值等于 len
 ssize_t sendmsg( int sockfd, const struct msghdr *msg, int flags );
 ssize_t recvmsg( int sockfd, const struct msghdr *msg, int flags );

 ,当计数变为  时才关闭该套结字,而 shutdown 直接就发送 FIN 分节(父进程的关闭操作将导致客户端的网络连接被关闭)

 uint16_t htons( uint16_t hostshort );    将 unsigned short 类型的数据的主机字节顺序转换为网络字节顺序
 unsigned long int htonl( unsigned long int hostlong );    将本机上的 long 转换为网络上的 long
 unsigned short int htons( unsigned short int hostshort );
 unsigned long int ntohl( unsigned long int netlong );
 unsigned short int ntohs( unsigned short int netshort );

 ,错误返回 -
 ;成功后返回转换后的地址,失败返回 NULL

 ,失败返回
 in_addr_t inet_addr(
 char *inet_ntoa(struct in_addr in);    将二进制地址转换为点分十进制

 struct hostent *gethostbyname( const char *hostname );    将机器名(如 linux.yu.net )转换为一个结构体指针,指针里存放了域名和 IP 地址等信息
 struct hostent *gethostbyaddr( const void *addr, int len, int type );    将一个 socket 地址结构体里面的 IP 地址转换为一个结构体指针;失败返回 NULL 且设置 h_errno 错误变量
 char *h_strerror(int errnum);    打印详细的错误信息( h_errno )

 ,失败返回 -
 int getpeername( int sockfd, struct sockaddr *peeraddr, int *addrlen );    获取套结口 sockfd 的远端 socket 地址
 struct servent *getservbyname( const char *servname, const char *protoname );    通过服务得到端口号
 struct servent *getservbyport( int port, const char *protoname );    得到指定端口号的服务(知名服务和端口号对应)

 int getsockopt( int sockfd, int level, int optname, void *optval, socklen_t *optlen );    获得 socket 属性
 int setsockopt( int sockfd, int level, int optname, const void *optval, socklen_t optlen );    设置 socket 属性
 ,表示 true;

 int setsockopt( s, SOL_SOCKET, SO_DONTLINGER, ( const char* )&bDontLinger, sizeof(bDontLinger) );    处于连接状态的 socket 在调用 close 后立即关闭,不经历 TIME_WAIT
 int setsockopt( socket, SOL_SOCKET, SO_SNDTIMEO, ( char * )&nNetTimeout, sizeof(int) );    设置发送时限为 nNetTimeout ,单位是毫秒
 int setsockopt( socket, SOL_SOCKET, SO_RCVTIMEO, ( char * )&nNetTimeout, sizeof(int) );    设置接收时限为 nNetTimeout
  *  B,避免 send() recv() 不断循环收发
 int setsockopt( s, SOL_SOCKET, SO_SNDBUF, ( const char* )&nSendBuf, sizeof(int) );    设置发送缓冲区大小
 , 在发送数据时不经历由系统缓冲区复制到 socket 缓冲区而影响程序性能
 , 在接收数据时不经历由 socket 缓冲区复制到系统缓冲区而影响程序性能
 , 发送的数据具有广播特性
 , client 连接服务器过程中,在非阻塞模式(阻塞模式下没用)下 connect 过程中设置 connect 延时到 accept 被呼叫
 ;在 close 过程中数据还没发送完毕时允许逗留 m_sLinger.l_linger = ;允许逗留  s;

 头文件

 stdlib.h    atexit, on_exit, pipe, malloc, abort
 stdio.h    printf, perror
 unistd.h    STDIN_FIFLNO(), STDOUT_FIFLNO, STDERR_FIFLNO, dup2, _exit, alarm
 fcntl.h    O_CREAT, O_APPEND, O_EXCL, O_RDONLY
 poll.h
 curses.h    编译时要指定库 ncurses,缺少时安装 kernel-devel ncurses-devel
 errno.h    EXIT_SUCCESS, EXIT_FAILED, perror
 limits.h    PIPE_BUF(  ),
 netdb.h    网络, struct hostent,
 time.h
 dirent.h    目录
 pwd.h
 grp.h
 pthread.h    线程
 semaphore.h    信号量
 signal.h
 string.h
 strings.h    strcasecmp, bzero
 syslog.h

 arpa/inet.h    网络

 sys/ioctl.h
 sys/ipc.h
 sys/msg.h    消息队列
 sys/select.h
 sys/sem.h    信号量
 sys/shm.h    共享内存
 sys/socket.h
 sys/stat.h
 sys/time.h    gettimeofday
 sys/types.h
 sys/wait.h

 自定义类型

 FILE
 DIR
 atomic_t    typedef struct { volatile int counter; } atomic_t;
 bool typedef _Bool bool;
 clockid_t typedef __kernel_clockid_t clockid_t;
 daddr_t    typedef __kernel_daddr_t daddr_t;
 dev_t    typedef __kernel_dev_t dev_t;
 gid16_t typedef __kernel_gid16_t gid16_t;
 gid_t typedef __kernel_gid32_t gid_t;
 id_t    可以涵盖任务 pid_t,uid_t 或者 gid_t 的整数类型,不能分割来使用
 ino_t    typedef __kernel_ino_t ino_t;
 in_addr_t
 in_port_t    typedef uint16_t in_port_t;
 key_t    typedef __kernel_key_t key_t;
 loff_t    typedef long long __kernel_loff_t; typedef __kernel_loff_t loff_t;
 mode_t    typedef unsigned int __kernel_mode_t; typedef __kernel_mode_t mode_t;
 mqd_t typedef __kernel_mqd_t mqd_t;
 nlink_t    typedef __kernel_nlink_t nlink_t;
 off_t    typedef __kernel_off_t off_t;
 old_gid_t typedef __kernel_old_gid_t old_gid_t;
 old_uid_t typedef __kernel_old_uid_t old_uid_t;
 pid_t    typedef __kernel_pid_t pid_t;
 sa_family_t    typedef unsigned short int sa_family_t;
 sem_t    typedef long sem_t;
 size_t typedef __kernel_size_t size_t;
 ssize_t typedef __kernel_ssize_t ssize_t;
 suseconds_t typedef long __kernel_suseconds_t; typedef __kernel_suseconds_t suseconds_t
 timer_t typedef __kernel_timer_t timer_t;
 time_t    typedef long time_t;
 uid16_t typedef __kernel_uid16_t uid16_t;
 uid_t typedef __kernel_uid32_t uid_t;
 uintptr_t typedef unsigned long uintptr_t;
 __kernel_clock_t typedef long __kernel_clock_t;
 __kernel_gid_t typedef unsigned short __kernel_gid_t;
 __kernel_ino_t typedef unsigned long __kernel_ino_t;
 __kernel_ipc_pid_t typedef unsigned short __kernel_ipc_pid_t;
 __kernel_mode_t typedef unsigned short __kernel_mode_t;
 __kernel_nlink_t typedef unsigned short __kernel_nlink_t;
 __kernel_off_t typedef long __kernel_off_t;
 __kernel_pid_t typedef int __kernel_pid_t;
 __kernel_ptrdiff_t typedef int __kernel_ptrdiff_t;
 __kernel_size_t typedef unsigned int __kernel_size_t;
 __kernel_ssize_t typedef int __kernel_ssize_t;
 __kernel_suseconds_t    typedef long __kernel_suseconds_t;
 __kernel_timer_t typedef int __kernel_timer_t;
 __kernel_time_t typedef long __kernel_time_t;
 __kernel_uid_t typedef unsigned short __kernel_uid_t;

 POSIX-Portable Operating System Interface for Unix,要求C语言库的 <.../types.h> 头文件为每个实现 POSIX 的机器定义一个一致的类型集。其中的每一个类型定义很容易与本地C语言区分开来,因为它们都以_t结尾。

 结构体

 struct timeval    //使用范围: gettimeofday,设置时间间隔,没有定义在 time.h 中
 {
 time_t tv_sec; //用 gettimeofday 创建结构体时得到到 Epoch 时的秒数
 suseconds_t tv_usec; //微秒数,六位;在实际中,该函数以及 Linux 内核返回的 timeval 类型的时间值, tv_usec 代表的是微秒精度(10的-6次方秒)
 };

 struct timezone {
 int tz_minuteswest; /* minutes west of Greenwich */
 int tz_dsttime; /* type of DST correction */
 };

 struct pollfd{
 int fd;    //文件描述符
 short events;    // requested events 用于输入
 short revents;    // returned events 用于输出,可以是 events 中指定已发生的事件,也可以是 POLLERR POLLHUP POLLNVAL 3 个错误中的一个
 }

 struct stat{
 dev_t st_dev;    //id of device containing file
 ino_t st_ino;    //inode number
 mode_t st_mode;    //protection
 nlink_t st_nlink;    //hard link number
 uid_t st_uid;
 gid_t st_gid;
 dev_t st_rdev;    //device id( if special device ) 主次设备号
 off_t st_size;    //total size, in bytes
 blksize_t st_blksize;    //blocksize for filesystem I/O
 blkcnt_t st_blocks;    //number of blocks allocated
 time_t st_atime;    //access
 time_t st_mtime;    //modification
 time_t st_ctime;    //status change
 }

 struct tm{
 int tm_sec;
 int tm_min;
 int tm_hour;
 int tm_mday;
 int tm_mon;
 int tm_year;
 int tm_wday;
 int tm_yday;
 int tm_isdst;
 }

 struct dirent{
 ino_t d_ino;    //inode number
 off_t d_off;    //offset to the next dirent
 unsigned short d_reclen;    //length of this record
 unsigned char d_type;    //type of file
 ];    //filename
 }

 struct passwd{
 char *pw_name;    //用户名
 char *pw_passwd;    //用户密码
 uid_t pw_uid;
 gid_t pw_gid;
 char *pw_gecos;    //用户真实姓名
 char *pw_dir;    //用户主目录
 char *pw_shell;    //用户主 shell 程序
 }

 struct sigaction{
 void ( *sa_handler )( int );    //信号处理程序,有一个 int 参数
 void ( *sa_sigaction )( int, siginfo_t *, void * );    //信号处理程序,第一个参数是信号,第二个参数是指向 siginfo_t 的指针,第三个参数是指向 ucontext_t 的指针
 sigset_t sa_mask;    //信号掩码集合,该集合中屏蔽的信号将在信号处理程序结束之后再被处理,默认屏蔽同类信号
 int sa_flags;    //信号处理程序行为标志,SA_SIGINFO 表示使用 sa_sigaction 代替 sa_handler; SA_NODEFER 表示不屏蔽同类信号,SA_NOCLDSTOP 若 signum 是 SIGCHLD,当一个子进程停止时,不产生此信号; SA_RESTART 由此信号中断的系统调用自动重启; SA_ONSTACK 若用 sigaltstack 已说明了一替换栈,则此信号递送给替换栈上的进程; SA_NOCLDWAIT 若 signum 是 SIGCHLD,则当调用进程的子进程终止时,不创建僵尸进程,若调用进程在后面调用 wait,则阻塞到它所有子进程都终止,此时返回 -1; SA_RESETHAND 对此信号的处理方式在此信号捕捉函数的入口处复原为 SIG_DFL
 void ( *sa_restorer )( void );    //不再使用
 };

 union semun{
 int val;    //SETVAL
 struct semid_ds *buf;    //IPC_STAT IPC_SET
 unsigned short *array;    //GETALL SETALL
 struct seminfo *__buf;    //IPC_INFO
 };

 struct sembuf{
 unsigned short sem_num;    // 操作信号在信号量集中的编号,第一个编号为 0
 short sem_op;    // 如果值为正数,加到现有信号量内含值中,常用于释放资源;为负数,其绝对值大于信号的现值,操作阻塞,直到信号值大于或等于 sem_op 的绝对值,常用于资源的使用权
 short sem_flg;    // 信号操作标志, IPC_NOWAIT 对信号的操作不能满足时 semop 不会阻塞,并立即返回,同时设定错误信息; C_UNDO 程序结束时,保证信号值被重设为 semop 调用前的值,避免程序异常情况下将资源锁定
 };

 struct hostent{
 char *h_name;    // 主机的正式名称
 char **h_aliases;    // 主机的别名
 int h_addrtype;    // 主机的地址类型 AF_INET
 int h_length;    // 主机的地址长度(对于 ip4 是 32 位)
 char **h_addr_list;    // 主机的 ip 地址列表
 };

 struct servent{
 char *s_name;    // 正式服务名
 char **s_aliases;    // 别名列表
 int s_port;    // 端口号
 char *s_proto;    // 使用的协议
 };

 struct sockaddr{    // /usr/include/sys/socket.h,一般的编程中并不直接对此数据结构进行操作,而使用另一个与之等价的数据结构sockaddr_in
 sa_family_t sa_family;    // 2字节的地址家族,如 AF_INET
 ];    // protocol address
 };

 struct sockaddr_un{    // 长度为 110B
 sa_family_t sun_family;
 ];
 };

 struct sockaddr_in{    // 长度为 16B
 sa_family_t sin_family;    // 在 socket 编程中只能是 AF_INET
 in_port_t sin_port;
 struct in_addr sin_addr;
 unsigned char sin_zero[sizeof(struct sockaddr) - (sizeof(unsigned short int)) - sizeof(in_port_t) - sizeof(struct in_addr)];    // 长度为 8B,暂时未用,应初始化为 0,为了让 sockaddr 与 sockaddr_in 两个数据结构保持大小相同而保留的空字节。
 };

 struct in_addr{    // <arpa/inet.h>
 in_addr_t s_addr;    // 点分十进制转换为的二进制数,32 位的 IPv4 地址
 };

 struct linger{    // /usr/include/sys/socket.h
 unsigned short l_onoff;
 unsigned short l_linger;
 };

 struct msghdr{
 void *msgname;
 int msg_name_len;
 struct iovec *msg_iov;
 int msg_iovlen;
 void *msg_control;
 int msg_controllen;
 int msg_flags;
 };

 struct iovec{
 void *iov_base;    // 缓冲区开始地址
 size_t iov_len;    // 缓冲区长度
 };

 struct file {
 /*
 * fu_list becomes invalid after file_free is called and queued via
 * fu_rcuhead for RCU freeing
 */
 union {
 struct list_head fu_list;
 struct rcu_head fu_rcuhead;
 } f_u;
 struct path f_path;
 #define f_dentry f_path.dentry
 #define f_vfsmnt f_path.mnt
 const struct file_operations *f_op;
 atomic_t f_count;
 unsigned int f_flags;
 mode_t f_mode;
 loff_t f_pos;
 struct fown_struct f_owner;
 unsigned int f_uid, f_gid;
 struct file_ra_state f_ra;
 unsigned long f_version;
 #ifdef CONFIG_SECURITY
 void *f_security;
 #endif
 /* needed for tty driver, and maybe others */
 void *private_data;
 #ifdef CONFIG_EPOLL
 /* Used by fs/eventpoll.c to link all the hooks to this file */
 struct list_head f_ep_links;
 spinlock_t f_ep_lock;
 #endif /* #ifdef CONFIG_EPOLL */
 struct address_space *f_mapping;
 };    //Linux 2.6.11内核,文件结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。

 基础

 文件描述符范围是 ~OPEN——MAX 早期为 (每个进程打开20个文件),现在多为256。

 POSIX 标只能是 Unix 中最流行的应用编程界面标准。

 文件结束符 ctrl d , EOF (int),不在任何头文件中定义,应该是 liunx 默认的宏。

 文件描述符本质是数组下标,如果子进程不打算使用父进程打开的文件,应该在调用 fork 后关闭该文件;如果父子进程同时打开一个文件,父进程读取文件后,子进程将读取同一文件的后续内容。而两个进程独立读取同一文件时,不会相互干扰。

 内核支持文件描述符的数据结构中,最右边的是 i 节点表,整个系统只有一张,可视为结构体数组,每个元素对应一个物理文件;中间的是文件表,整个系统一张,可视为结构体数组,元素中有  个重要的字段,指定文件被打开时采用的选项,文件当前读写位置,指向 i 节点表的指针(关联物理文件);左侧的表是文件描述符表,每个进程一张,可视为指针数组,指向文件表中的一个元素,记录打开的文件。

 extern char **environ;    指向系统环境变量的指针

 刷新 I/O 缓存条件:用户空间的 I/O 库缓存被填满;I/O 缓存库遇到换行符,并且目标是行缓冲设备(屏幕);I/O 流被关闭。调用系统调用(如 write )可以将 I/O 缓存库内容提交给内核。

 进程内存布局图:初始数据段data包含已初始化的全局变量和局部静态变量;bbs存放的是未初始化全局变量和未初始化的static局部变量,他们初始值都为0;stack存放的是动态局部变量,heap是malloc分配的空间;之所以子函数不能相互访问对方动态局部变量是因为 main 函数调用 A 函数后再调用 B 函数将覆盖 A 函数的动态局部变量存储空间。

 进程组、对话期、控制终端:对话期是一个或多个进程组的集合,建立与控制终端连接的对话期首进程叫作控制进程;如果对话期首进程调用 open 打开第一个尚未与一个对话期相关联的终端设备时没有指定 O_NOCTTY ,此终端设备则分配给此对话期,如打开 /dev/tty 。

 一般来说,收到 SIGCHLD 后,父进程会使用 wait 系统调用以取得子进程的退出状态,然后内核就可以从内存中释放已结束的子进程的 PCB;而如若父进程没有这么做的话,子进程的 PCB 就会一直驻留在内存中,也即成为僵尸进程。
 孤儿进程则是指父进程结束后仍在运行的子进程。在类UNIX系统中,孤儿进程一般会被 init 进程所“收养”,成为 init 的子进程。
 为避免产生僵尸进程,实际应用中一般采取的方式是:
 .将父进程中对 SIGCHLD 信号的处理函数设为 SIG_IGN (忽略信号);
 . fork 两次并杀死一级子进程,令二级子进程成为孤儿进程而被 init 所“收养”、清理。

 进程间通信包括信号、无名管道、有名管道、共享内存、信号量、消息队列。

 操作共享内存类似于操作字符指针,用下标来读写。

 信号量和互斥锁,信号量为  时就是互斥锁。

 每个进程都有一个信号掩码,用来定义被阻塞递送的信号集合,阻塞信号在关键代码执行完后才处理信号。

 gcc 编译线程时使用 -l pthread ,在 /usr/lib/libpthread.so 中。

 轻进程( LWP )即内核线程,CPU 时间片调度是面向轻进程的,位于系统层和用户层之间,系统通过轻进程实现对线程资源的分配、对线程的控制,一个轻进程控制一个或多个线程。

 网络中的  次握手和  分节终止序列。

 小端系统( little endian )中变量的高位存放在高地址,大端系统中变量的高位存放在低地址,网络中传送的是大端字节。

 流式套结字采用 TCP 协议,数据报套结字采用 UDP 协议,原始套结字允许对底层协议(如 ip 或 icmp )直接访问,常用于新的网络协议的测试等。

 socket 组成为:协议,本地地址,本地端口,远程地址,远程端口。

 TCP 网络编程模型
 服务器编程模型: socket -> bind -> listen -> accept -> read -> write -> close
 客户端编程模型: socket -> connet -> write -> read -> close
 服务器编程模型: socket 建立无任何网络连接的 socket ,返回值是一个文件描述符 -> bind 将 socket 和本机 ip 地址和端口号绑定(  元组) -> listen 将 socket 指定为一个监听套结字,用于监听客户端到达的网络连接请求 -> accept 使 socket 进入网络连接状态,服务器能接收客户端连接,没有连接则阻塞,其返回另一个 socket ,被称为连接套结字,是一个  元组 -> read 读客户端发送的数据,否则阻塞 -> write -> close
 客户端编程模型: socket -> connet 将服务器 IP 和端口号作为参数传入,本机选择一个未使用且大于  的端口号作为本地端口,发起连接,建立连接 -> write -> read -> close

 迭代服务器一次只能处理一个客户请求,并发服务器使用多个进程(线程)处理客户连接。并发服务器的一个问题是子进程结束了而父进程还在,会累积僵尸进程,解决方法是子进程结束后给父进程发送 SIGCHLD 信号,父进程在信号处理程序中调用 waitpid 销调子进程。

 UDP 编程模型
 服务器: socket -> bind -> recvfrom -> sendto -> close
 客户端: socket -> sendto -> recvfrom -> close

 实践

 判断条件时“);” 等价于 “);”,
 但是 ); is wrong.

 程序打开的文件的读写权限要基于文件本身的读写权限。

 time()函数的使用;