工作碰上的技术问题及处理经验(二)

续上一篇随笔: https://www.cnblogs.com/kingstarer/p/8469016.html 《工作碰上的技术问题及处理经验》

 

由于内容有很多空格,如果直接在正文粘贴,发表后空格会消失,导致版本看起来比较难看。

所以我把主要内容做为代码发表。

我觉得每天把工作碰上的问题做一个简单的笔记挺不错的,一来可以锻炼自己的表达能力,二来也方便自己以后复查,因为以后工作很可能再碰上同样的问题。

由于我每次记录笔记时,可能只是记录了关键字,而要发出来做为共享随笔,只有这些关键字肯定是不行的,大家看了一头雾水。

所以发表前需要二次整理,目前只整理到了20180424,还有一年多的笔记,后面会继续整理,陆续发表出来。

希望能对大家有所帮助。

20171226:
    socket被子进程close父进程还能用,但是被shutdown父进程则无法用。
    shutdown后还需要close。close计数为0时会自动shutdown。

    recv函数参数含义:
    msg_peek recv 只读数据 不取出
    msg_waitall recv 等到所有数据读取完毕才返回
    msg_confirm send 等到对方收到数据才返回
    MSG_NOSIGNAL send 对方关闭socket时不发送sigpipe信号(还是会返回出错)
    TCP_NODELAY,出现40ms延时最大的可能就是由于没有设置TCP_NODELAY 在长连接的交互中,有些时候一个发送的数据包非常的小,
    加上一个数据包的头部就会导致浪费,而且由于传输的数据多了,就可能会造成网络拥塞的情况, 在系统底层默认采用了Nagle算法,可以把连续发送的多个小包组装为一个更大的数据包然后再进行发送. 但是对于我们交互性的应用程序意义就不大了,在这种情况下我们发送一个小数据包的请求,就会立刻进行等待,不会还有后面的数据包一起发送
    下一个数据包,这个时候服务端出现了延时返回的问题.对于这个问题可以通过设置server端TCP_QUICKACK选项来解决. TCP_QUICKACK可以让服务端尽快的响应这个ack包.  
    采用writev方式发送多个小数据包
    一台机器上的端口是有限,最多65535(一个unsigned char)个,在系统文件/proc/sys/net/ipv4/ip_local_port_range  中我们一般可以看到32768 61000 的结果,这里表示这台机器可以使用的端口范围是32768到61000,
     小提示: 一般的服务模式都是服务端一个端口,客户端使用不同的端口进行连接,但是其实我们也是可以把这个过程倒过来,我们客户端只用一个端但是服务端确是不同的端口,客户端做下面的修改原有的方式 socket分配句柄-> connect 分配的句柄 改为 socket分配句柄 ->对socket设置SO_REUSEADDR选项->像服务端一样bind某个端口->connect 就可以实现  
    不过这种应用相对比较少,对于像网络爬虫这种情况可能相对会比较适用,只不过6w连接已经够多了,继续增加的意义不一定那么大就是了.  
    这个要根据情况来看, 一般情况connect一个不存在的ip地址,发起连接的服务需要等待ack的返回,由于ip地址不存在,不会有返回,这个时候会一直等到超时才返回。如果连接的是一个存在的ip,但是相应的端口没有服务,这个时候会马上得到返回,收到一个ECONNREFUSED(Connection refused)的结果。  
    但是在我们的网络会存在一些有限制的路由器,比如我们一些机器不允许访问外网,这个时候如果访问的ip是一个外网ip(无论是否存在),这个时候也会马上返回得到一个Network is unreachable的错误,不需要等待。


20180108:
    g_trash_stack_push会破坏存到栈里面的内容


20180110:
    经验:多磁盘系统可能出现热点磁盘,可以考虑使用条带化使得文件系统均匀分布

20180112:
    Linux堆栈是向下扩展的,所以如果出现数组写越界,破坏数组变量之前定义的一个变量的内容。(但是同一个结构体里面则是按声明顺序从小到大分配空间)



20180115:
    网络编程时,服务器接收数据需要防止客户端发送数据不完整。最好让客户端在发送数据前先发送包长度。

20180116:
    linux下,select函数超时后会修改入参struct timeval参数,需要重置成需要的超时时间

    读取文件尾部: if (0 > (fd = open(strLogFile, O_APPEND | O_WRONLY | O_CREAT | O_TEXT, 0644)))


20180201:
    如果出现退格键不能删除字符,终端显示不全等问题,一般可以观察是否stty参数设置异常:stty -a


20180228:
    最近定位了系统传输给P9的数据出现入库失败的问题。
    先说一下背景:
    我们数据库字符编码是GBK,P9数据库编码是UTF8。每天我们系统有一些数据需要导出成文件,传给他们系统入库。
    我们做法是先导出GBK编码的文件再通过iconv转换成UTF8格式文件传给他们。
    约定文件列分隔符是"|@|"
    出现的问题:
    由于某个库表有个字段长度不足,我们入库时需要先substr再入库,导致有些数据出现半个中文问题。
    这种数据导出到文件再用iconv转换成utf8格式时会把后面的竖线与半个中文合并成一个新的中文。
    结果会导致转换后的数据缺失一列,对方系统入库失败。
    解决方法:
    字段导出时就转换成UTF8格式,如果碰上转换异常的字符忽略。

20180301:
    今天一个网友系统短信验证码被刷了,虽然控制了ip和手机号码发送频率,但是还是被人用n多肉鸡攻击。
    当初项目上线为了用户体验,没有先验证图文验证码就直接发短信造成的祸端。


20180310:
    everything默认不搜索c盘,需要强制它搜索。工具->选项->索引->文件夹新增需要搜索的用户目录。

20180312:
    sqlplus的set term off可以不显示sql执行结果() 脚本

20180316:
    vim打开混合编码的文件,容易出现中文乱码的情况。可以强制vim把文件当成utf8格式打开:e ++enc=utf-8



20180318:
    今天编译代码时报错,提示error C2065: “HANDLE_TIMEOUT”: 未声明的标识符。
但我明明在前面有定义HANDLE_TIMEOUT宏:#define HANDLE_TIMEOUT()  
    原以为是编译器有bug,后来发现原来要用宏函数的写法才对:HANDLE_TIMEOUT(),我原来直接写了HANDLE_TIMEOUT

20180318:
    今天用plsql同时执行多条insert语句时报错:ora-0091  无效字符
后来我把语句前后厍上BEGIN和END;就可以了


20180319:
    select返回可读,但recv返回0,这种情况一般是因为对方关闭socket


20180322:
    sourceinsight在括号前双击可以快速跳转到对应的另一个括号位置。


20180408:
    release版本 gdb看不出来 加上-g重新编译

20180410:
    今天发现一个命令ss,据说比netstat快很多。netstat -anp <=> ss -tanp

    ue高亮单词的方法: shift + 双击单词

20180411:
    今天有同事说突然登录不了oracle,使用sqlplus user/pwd@dbname报错:“ora-12154: tns:could not resolve the connect identifier specified”,让我帮他看一下。
    我过去他机器执行tnsping dbname,提示"tns-12533: tns:illegal address parameters",感觉是tns没配置好。但是查看tns配置${ORACLE_HOME}/network/admin/tnsnames.ora,里面的配置没问题。
    后来才发现昨天有人在.profile设置了TNS_ADMIN,把tns配置指向了另一个目录,那里面tns配置错了。我之前没检查这个变量,查看了默认目录${ORACLE_HOME}/network/admin/,所以没找出原因。


20180412:
    今天用sftp上传文件时报错"fail to upload failure",以为是文件有问题,查了半天没发现。后来发现原来是目标机器硬盘空间满了。

    今天有gdb调试程序,学习了几个技巧: 1 调试机器源码目录与编译机器源码目录不同,可以用set substitutes-path /xxa /xxb指示gdb到指定目录找源码文件。
    .gdbinit set auto-load safe-path /
     print命令可以修改变量值,用法: print x=4
    使用watch命令可以让gdb在变量被修改时自动断点:watch *(char *)addr2line

20180413:
    今天发现有同事在.h里面修改了结构体定义,但没有相应的编译所有.c。导致运行时出现内存越界。
把程序make clean后重新编译就好了。
    这个问题确实比较难解决,因为写makefile时不好确定每个.c依赖于哪些.h

    今天写了一个将/proc下面程序环境变量文件转成export语句的脚本
    cat environ | tr '\0' '\n' | awk -F '=' '{
    printf("export %s=%c%s%c\n", $1, 39, $2, 39); 
}' #39是单引号的asscii码


20180414:
    后来发现原来delete * from tab;也会造成高水位。之前以为只是有条件的delete会造成高水位。
oracle对于每个数据段(可以简单理解为每个表)都有一个高水位(hwm)标记使用空间上限。hwm默认情况只会增大,不会减少。
所以如果出现插入大量数据,然后又删除大量数据的表,会出现高水位远超过实际数据占用空间的情况。
而数据库做全表扫描时会扫描高水位下面所有数据,这就会导致有时表的数据很少,但查询起来仍然很慢的情况。


20180416:
    http常见标准错误400  由于语法格式有误,服务器无法理解此请求。404 Web 服务器找不到您所请求的文件或脚本。

20180417:
    今天使用windows上的awk程序输出中文到屏幕时发现问题:
    1 使用print输出字符串时,如果字符串有中文,会报错fatal: print to "standard output" failed (Invalid argument)
    2 使用printf输出字符串时,如果字符串有中文,会报错fatal: printf to "standard output" failed (Bad file descriptor)
    解决方法是不直接把awk运行结果输出到屏幕,使用重定向输出到txt文本,就不会报错了。

20180419:
    vs2015编译有utf8的源码时,需要在文件头添加BOM,否则会报错


20180424:
    C语言某些宏在宏里面写死了变量名,导致无法使用不同名称的变量调用该宏
例如下面这个宏,强制要求使用变量名称txnJnl,如果想使用变量名txnJnl_realName则会调用失败
#define XML_TO_JNL(IDX) \
do { \
    nRc = XmlIpc2St(&txnJnl, X2S(IDX));\
    if (nRc) return nRc;\
} while(0)
    对于这种情况c++可以使用引用改变变量名,在c则可以使用下面的编码技巧曲线救国
#define  txnJnl txnJnl_realName 
    REQ_XML_TO_JNL(X2S_REVERSALAUTHREQ2ONLJNL);
#undef txnJnl
    但最好还是推荐在写宏时参数带上变量名
#define REQ_XML_TO_JNL(txnJnl,IDX) \
do { \
    nRc = XmlIpc2St(&txnJnl, X2S(IDX));\
    if (nRc) return nRc;\
} while(0)
    这样才符合高内聚低耦合的设计原则。

 

posted @ 2019-06-16 12:12  皇家救星  阅读(...)  评论(... 编辑 收藏