Linux编程手册

19. 文件I/O

19.1 std::ifstream

打开


读取


19.2 std::ofstream



17. C++11


17.1 shared_ptr

gcc 4.4

头文件:#include <tr1/memory>

使用:std::tr1::shared_ptr<T> shp;

说明:头文件位于目录/usr/include/c++/4.4.7/tr1


gcc 4.8

头文件:#include <memory>

Makefile:CXXFLAGS=-std=c++11

使用:std::shared_ptr<T> shp;


17.2 function与bind

gcc 4.4

头文件:#include <tr1/functional>

使用:std::tr1::function<> fn;    std::tr1::bind(&Class::FnMem, &obj, std::tr1::placeholders::_1);

说明:头文件位于目录/usr/include/c++/4.4.7/tr1


gcc 4.8

头文件:#include<functional>

Makefile:CXXFLAGS=-std=c++11

使用:std::function<> fn; std::bind(&Class::FnMem, &obj, std::tr1::placeholders::_1);


17.3 auto

gcc 4.4

Makefile:CXXFLAGS=-std=c++0x

使用:auto pos = vector.begin();


gcc 4.8

Makefile:-std=c++11

使用:auto pos = vector.begin();



16. SIGPIPE

当一个进程向某个已收到RST的套接字执行写操作时,内核会向该进程发送一个SIGPIPE信号,该信号的默认行为是终止进程

不论进程是捕获了该信号并从其信号处理函数返回,还是简单地忽略该信号,写操作都将返回EPIPE错误


情景还原

现假设数据流向为A——>B

A和B位于两台主机,A发送数据,B给予应答,然后终止进程B


进程终止时,该进程打开的所有描述符都将被关闭,对于套接字描述符,即向对端发送FIN

FIN的作用是告知对端,我的数据已发送完成,你的recv函数可以停止了,但你有数据仍旧可以发送过来,我接着,此即TCP的半连接状态


B关闭套接字——向A发送FIN——A不知进程B已停止,继续向B发送数据——第一次send——数据拷入套接字发送缓冲区——send成功返回,返回值为数据长度——数据发往B所在主机——进程B已终止,连接已失效——B所在主机发送RST——假设A此刻没有对该套接字调用接收函数以感知RST的到来——A第二次send——内核已知此套接字收过RST——内核向A发送SIGPIPE信号


程序设计

为防止服务器异常终止,应按如下方法之一操作:

1. 程序初始化时,全局范围内忽略SIGPIPE信号:signal(SIGPIPE, SIG_IGN);

2. 使用MSG_NOSIGNAL标志调用send函数:send(s, buf, len, MSG_NOSIGNAL);


引申

是否需要心跳,综合考虑下述两点:

1. 服务器进程异常终止,服务器进程重启,服务器主机重启,此三种情况下,client通过send返回的EPIPE错误,均可及时发现连接异常

2. 服务器断网,服务器主机崩溃未重启,此两种情况下,源自Berkeley的内核重传12次、约9分钟后返回给发送进程一个错误



15. 单词简写

server : sev

device : dev

函数前缀 : fn

参数 : parm


14. make

格式:make -f filename

说明:若filename为Makefile或makefile,则-f filename可以省略


使用c++11特性,需向Makefile中加入

CXXFLAGS=-std=c++11


13. gdb


13.1 添加编译选项

编辑Makefile,增加

CXXFLAGS = -g

将所有的g++替换为

g++ $(CXXFLAGS)


向makefile的所有编译过程加-g选项make CXXFLAGS=-g

gdb调试,要求在所有文件编译过程中,加入-g选项。在文件数巨多的情况下,手动添加几乎不实际,特别是含有大量自动推导过程。

这时,无需修改makefile,直接运行make CXXFLAGS=-g,即可实现目的。


13.2 设置字符串显示长度

gdb打印字符串时,默认只显示部分数据,可通过如下命令进行修改:

set print elements 0

默认设置是200,设置为0表示没有限制



12. 查看信号

man 7 signal



11. 随机数




函数:void srand(unsigned int seed);

功能:设置随机数序列的种子

说明:种子相同,则调用rand()生成的随机数序列相同


函数:int rand();

功能:生成随机数


函数:time_t time(time_t *t);

功能:获取自Epoch经过的秒数

参数:存放返回结果,恒为NULL



10. 正则表达式

验证字符串格式:"yyyy-mm-dd hh:mm:ss"



函数:int regcomp(regex_t *prgx, const char *pattern, int flags);

功能:按照指定的模式创建正则表达式

参数:

        regex_t *prgx:出参,即结果

        const char *pattern:模式字符串

        int flags:控制标志

控制标志:

        REG_EXTENDED:使用POSIX扩展正则表达式,否则标准正则表达式。

        REG_ICASE:忽略大小写

        REG_NOSUB:不支持子串匹配

返回值:成功返回0,否则错误码


函数:int regexec(const regex_t *prgx, const char *obj_string, size_t nmatch, regmatch_t pmatch[], int flags);

功能:正则匹配

参数:

        const regex_t *prgx:使用的正则表达式,由regcomp生成

        const char *obj_string:待匹配字符串,目标字符串

        size_t nmatch:pmatch元素个数,暂为0

        regmatch_t pmatch[]:暂未使用,恒为NULL

        int flags:标志位,未使用,暂为0

返回值:匹配成功返回0,否则返回REG_NOMATCH


函数:size_t regerror(int errcode, const regex_t *prgx, char *buffer, size_t buffer_size);

功能:根据错误码获取对应的错误信息

参数:

        int errcode:错误码

        const regex_t *prgx:发生错误的正则表达式

        char *buffer:接收缓冲区

        size_t buffer_size:接受缓冲区大小

返回值:返回buffer的实际使用大小


函数:void regfree(regex_t *prgx);

功能:释放prgx占用的空间

参数:待释放的regex_t结构体指针



9. UUID



依赖:yum install libuuid-devel


函数: void uuid_generate(uuid_t  buuid);

功能:创建uuid,二进制格式uuid

参数:出参,uuid_t型变量,即结果

说明:函数生成uuid的方式,或者/dev/urandom,或者当前时间+主机MAC+伪随机数生成器

附加:typedef unsigned char uuid_t[16];


函数void uuid_unparse(uuid_t  buuid,  char  *cuuid);

功能: 把uuid从二进制格式转换成字符串格式

参数

        uuid_t  buuid:二进制型uuid,由uuid_generate生成

        char  *cuuid:结果字符串,出参,字符串型uuid



8. Linux平台数据类型

Linux平台特定数据类型定义文件:/usr/include/stdint.h

部分截图如下:



7. 线程

头文件:#include <pthread.h>

函数原型:

int pthread_create(

        pthread_t *thread, 

        const pthread_attr_t *attr,  

        void* (*func) (void *arg),  

        void *arg

);

功能:创建线程

返回值:成功返回0, 失败返回错误码

示例:




6. 计时器


clock_gettime

头文件:#include <time.h>

函数原型:int clock_gettime(clockid_t clk_id, struct timespec *tp);

功能:返回日历时间,精确到纳秒

返回值:成功返回0;失败返回-1,置错误码

依赖库:librt.so,编译加-lrt选项,否则报错“undefined reference to clock_gettime”


标准示例


本地测试结果:

clock_gettime一次耗时150ns,相当于

for(int i = 0; i != 50; ++i)

        ;

空转50次,故对系统性能影响较小。


gettimeofday

头文件:#include <sys/time.h>

函数原型:int gettimeofday(struct timeval *tv, struct timezone *tz);

功能:返回自Epoch经过的时间,精确到微秒

返回值:成功返回0,失败-1,置错误码

示例:




5. 互斥锁


函数:int pthread_mutexattr_init(pthread_mutexattr_t *attr);

功能:初始化属性对象

参数:pthread_mutexattr_t类型的属性对象

返回值:成功返回0,否则错误码


函数:int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);

功能:设置mutex类型

参数:

        pthread_mutexattr_t *attr:待设置的属性对象

        int type:mutex类型

返回值:成功返回0,否则错误码

类型:

        PTHREAD_MUTEX_NORMAL:重复加锁,将导致死锁;释放其它线程持有的锁,将导致未定义的行为;释放未加锁的锁,将导致未定义的行为。

        PTHREAD_MUTEX_ERRORCHECK:重复加锁,将返回错误;释放其它线程持有的锁,将返回错误;释放未加锁的锁,将返回错误。

        PTHREAD_MUTEX_RECURSIVE:重复加锁,没有问题,但需释放相同次数;释放别人的锁,将返回错误;释放未加锁的锁,将返回错误。

        PTHREAD_MUTEX_DEFAULT:重复加锁,未定义的行为;释放别人的锁,未定义的行为;释放未加锁的锁,未定义的行为。


函数:int pthread_mutex_init(pthread_mutex_t *mtx,  const pthread_mutexattr_t *attr);

功能:初始化mutex对象

参数:

        pthread_mutex_t *mtx:待初始化锁对象

        const pthread_mutexattr_t *attr:属性设置

返回值:成功返回0,否则错误码

说明:重复初始化,将导致未定义的行为


函数:int pthread_mutex_destroy(pthread_mutex_t *mtx);

功能:销毁锁对象

参数:待销毁的锁

返回值:成功返回0,否则错误码

说明:销毁后,二次引用锁对象,未定义的行为。销毁未加锁的锁,没有问题;销毁已加锁的锁,未定义的行为。


函数:int pthread_mutex_lock(pthread_mutex_t *mtx);

功能:上锁

参数:目标锁

返回值:成功返回0,否则错误码


函数:int pthread_mutex_unlock(pthread_mutex_t *mtx);

功能:释放锁

参数:目标锁

返回值:成功返回0,否则错误码



4. 获取socket对应的地址

头文件:#include <sys/socket.h>

函数原型:int getsockname(int s, sockaddr *addr, socklen_t *addrlen);

功能:返回socket s绑定的本地地址信息

返回值:成功返回0,失败-1,置错误码。

示例:



3. 头文件


3.2 规范

为防止头文件被多次引用,造成重定义错误,头文件开始处需有:

#program once 

#ifndef XXX      #define XXX      #endif


头文件中可以有枚举、宏定义、变量和函数的声明、完整的类定义,但是不可以出现变量和函数的定义,否则报重定义错误

解决方法:变量和函数前加static,定义成静态变量和函数

注:变量声明格式为extern T t;   而T t;即定义变量t


3.1 概览

#include <stdio.h> C标准库头文件,对应标准输入输出;

#include <string.h> C标准库头文件,对应字符串操作。

C++不赞成混用C函数库,故对C标准库进行封装,对应如下:

#include <cstdio>  C++对C库的封装,printf的头文件

#include <cstring> C++对C库的封装,strerror的头文件


另有

socket和sockaddr对应的头文件为

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>


错误码errno头文件

#include <errno.h>



2. 使用VS2010编辑linux代码

编写完成后需转换格式,防止文件放到linux下出现乱码和编译问题。

VS2010——文件——高级保存选项:

编码:Unicode(UTF-8 无签名)

行尾:Unix(LF)



1. 静态编译和动态编译


链接库类型决定编译类型

        使用.a静态库:实现静态编译,库代码直接加入到生成的可执行文件中,故可执行文件较大,但脱离对库文件的依赖

        使用.so动态库:实现动态编译,生成的可执行文件较小,运行时进行动态链接,可执行文件和库文件必须同时存在


静态编译方法:直接加库名,无参数

        g++  -o main  main.cpp  /path/libname.a

        假设静态库为/path/libevent.a,则编译命令如下:g++  -o  main  main.cpp /path/libevent.a  


动态编译方法:-L库路径 -l库简名

        g++ -o main  main.cpp -Lpath -lname 

        假设动态库为/path/libevent.so,则编译命令如下:g++  -o  main  main.cpp  -L/path/  -levent  


动态编译提示:

        a. 编译完成后,需将动态库文件,放入系统默认库目录,否则出现编译时链接成功运行时链接失败的结果。

        b. -L选项仅指定了编译时链接路径,库代码未嵌入到可执行文件。运行时链接,由系统自动搜索默认库文件路径完成。


附加:

头文件路径

参数-I/path/指定头文件路径

#include <file>:先搜索-I指定的目录,之后是系统默认头文件目录;

#include "file":先搜索当前目录,然后是-I目录,最后是系统默认目录。


原文地址:https://www.cnblogs.com/chaikefusibushiji/p/6775753.html