• Linux编程手册


    21. 转码 


    21.1 iconv_open

    函数:iconv_t iconv_open(const char *tocode, const char *fromcode);

    功能:分配一个转换描述符,用于将字节序列从fromcode编码转换到tocode编码

    头文件:#include <iconv.h>

    参数:系统支持的fromcode和tocode的合法值及其组合,全部罗列于iconv --list的输出中

    返回值:成功则返回转换描述符;失败则返回-1,并置错误码

    说明:

    ① 一个转换描述符iconv_t不可同时用于多个线程

    ② 转换描述符iconv_t用完后,需调用关闭函数iconv_close()


    21.2 iconv

    函数:size_t iconv(iconv_t cd,
                        char **inbuf, size_t *inbytesleft,
                        char **outbuf, size_t *outbytesleft);

    功能:执行字符集转换

    头文件:#include <iconv.h>

    参数:

    cd 转换描述符

    inbuf 指向输入缓冲区首地址的指针

    inbytesleft 表示输入缓冲区等待转换的字节个数

    outbuf 指向输出缓冲区首地址的指针

    outbytesleft 表示输出缓冲区中可用空间大小,字节个数

    返回值:成功则返回转换的字符数;失败则返回-1,并置错误码

    描述:

    ① 该函数从*inbuf读取多字节序列,将其转换成目标格式的多字节序列,并将结果存放在*outbuf

    ② *inbuf中至多*inbytesleft个字节将被读取,至多*outbytesleft个字节将被写入*outbuf

    ③ 一次转换一个字符,然后根据已转换的输入字节数,递增*inbuf,递减*inbytesleft;根据已转换的输出字节数,递增*outbuf,递减*outbytesleft


    21.3 示例


    说明:

    ① 因为iconv会递增*inbuf和*outbuf,因此需要使用临时变量

    char *inbuf = (char*)ch;

    char *outbuf = buf;

    以保证原输入/输出缓冲区指针不变,即ch和buf值不改变。

    ② 函数执行结束后,inbuf和outbuf的值已改变,不再指向缓冲区首地址,所以获取转换结果,应使用buf,而不是outbuf

    ③ 转换过程,不会影响输入缓冲区中的原始内容,即ch中的内容不改变



    20. 文件I/O


    20.1 std::ifstream

    打开


    读取



    20.2 std::ofstream

    打开


    写入


    说明

    ① std::ofstream::app指定文件打开方式为追加,即从原文件内容的末尾开始写入;默认打开方式为截断,即删除原文件内容

    ② 文件路径可为绝对路径或相对路径,但不能使用「~」



    19. C++11


    19.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;


    19.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);


    19.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();



    18. 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分钟后返回给发送进程一个错误



    17. 单词简写

    server : sev

    device : dev

    函数前缀 : fn

    参数 : parm


    16. make

    格式:make -f filename

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


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

    CXXFLAGS=-std=c++11


    15. gdb


    15.1 添加编译选项

    编辑Makefile,增加

    CXXFLAGS = -g

    将所有的g++替换为

    g++ $(CXXFLAGS)


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

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

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


    15.2 设置字符串显示长度

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

    set print elements 0

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



    14. 查看信号

    man 7 signal




    13. 随机数


    13.2 /dev/urandom

    说明:字符文件,真随机数生成器

    示例:


    ◇ 相同的srand()参数,会导致rand()函数产生相同的随机数序列

    ◇ 同一时刻,两个线程或进程同时读取/dev/urandom,随机数序列不同

    ◇ /dev/random为真随机数生成器,/dev/urandom是它的副本,是很真的伪随机,u为unblock,非阻塞之意,即在Linux中熵用完的情况下,读取/dev/random会发生阻塞,而/dev/urandom则会重复使用熵池中的数据,以产生伪随机数


    注意:

     /dev/urandom的开销(耗时)是rand()函数的几十倍,故应只在需要产生强密码的环境下使用/dev/urandom,甚至是/dev/random,普通情况下还是应该使用rand()函数


    标准方式:

    ①使用/dev/urandom初始化srand()的种子    然后使用rand()生成随机数




    13.1 random函数



    函数:void srand(unsigned int seed);

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

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


    函数:int rand();

    功能:生成随机数


    函数:time_t time(time_t *t);

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

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



    12. 正则表达式

    验证字符串格式:"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结构体指针



    11. 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



    10. Linux平台数据类型

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

    部分截图如下:



    9. 线程

    头文件:#include <pthread.h>

    函数原型:

    int pthread_create(

            pthread_t *thread, 

            const pthread_attr_t *attr,  

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

            void *arg

    );

    功能:创建线程

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

    示例:




    8. 计时器


    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,置错误码

    示例:




    7. 互斥锁


    函数: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,否则错误码



    6. 获取socket对应的地址

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

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

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

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

    示例:



    5. 头文件


    5.2 规范

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

    #program once 

    #ifndef XXX      #define XXX      #endif


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

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

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


    5.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>



    4. 使用VS2010编辑linux代码

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

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

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

    行尾:Unix(LF)



    3. 头文件路径

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

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

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



    2. 动态库

    生成的可执行文件较小,运行时进行动态链接,库文件必须存在


    2.1 生成

    命令:g++ -fPIC -shared -o「libxxx.so「source.cpp


    2.2 使用

    △ 编译期

    ① g++ -L/path -lname

    ② g++ /path/libname.so

    两种方法都可以为编译期指定动态库路径,目的也都是为了编译能够通过。差别在于:

    ◇ 方法一生成的可执行文件,运行期,会遵照动态库默认搜索顺序,查找动态库,依次是编译期添加的路径、LD_LIBRARY_PATH、/etc/ld.so.cache、/usr/lib与/usr/lib64;

    ◇ 方法二生成的可执行文件,运行期,只从/path/目录下找寻动态库。因此,动态库位置一旦改变,可执行文件即不可运行


    g++ libname.so,即动态库位于当前编译目录时,该法可用,且效果等同于① 


    △ 运行期

    若可执行文件以g++ /path/libname.so的方式生成,则去到/path/目录下查找动态库;

    否则遵照动态库默认搜索顺序,依次查找对应目录,使用找到的第一个库文件


    2.3 说明

            a. 编译时添加运行期动态库搜索路径的方法是:gcc -Wl,-rpath=.:..:lib,路径之间以":"分隔。

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

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


    2.4 示例

    库的头文件和源文件,及程序代码文件,参考静态库的示例

    编译




    1. 静态库

    库里面的代码直接嵌入到可执行文件中,故可执行文件较大,同时脱离对库文件的依赖


    1.1 生成

    步骤:

    ① 将源文件编译成目标文件;

    ② 将目标文件打包到静态库中


    命令:

    g++ -o「obj.o」-c「source.cpp

    ② ar rcs「libxxx.a「obj.o


    1.2 使用

    命令:g++ -o「exe「SourceFiles「/path/libxxx.a

    说明:编译完成后,可执行文件与库文件脱离关系,即:

        ◇ 无论库文件「libxxx.a」仍否存在

        ◇ 无论库文件「libxxx.a位置是否变动

        ◇ 无论可执行文件「exe」位置是否变动

    可执行文件「exe」均能正常运行


    1.3 示例

    头文件

                                 

    源文件


    编译

    使用,注意包含头文件


    执行及结果


  • 相关阅读:
    vue学习笔记(四)---- 品牌管理案例
    vue学习笔记(三)---- vue-resource
    vue学习笔记(二) ---- vue实例的生命周期
    vue学习笔记(一) ---- vue指令(总体大纲)
    vue学习笔记(一)---- vue指令(在vue中使用样式的方式)
    【问题记录】—.NetCore 编译问题
    Docker学习—概念及基本应用
    Consul 学习笔记-服务注册
    认证授权:IdentityServer4
    认证授权:IdentityServer4
  • 原文地址:https://www.cnblogs.com/chaikefusibushiji/p/7475596.html
Copyright © 2020-2023  润新知