记录C/C++编程中遇到的一些小问题

1. printf

比如

char a = \x90;
printf("%02x", a);

想输出为90,没想到却是ffffff90,这个问题害我一个程序老是出错

最终发现只要改为

unsigned char a = \x90;

问题就解决了,其实还是正负数的问题

2. zlib

zlib unresolved external symbol _uncompress
inflate_fast崩溃
网上搜了一下,汇编版本的有坑
解决方法是编译zlib的时候用releasewithoutasm (Debug/Releasse那里选择)
这样生成的库是不崩溃的

3. socket TIME_WAIT

通信双方建立TCP连接后,主动关闭连接的一方会进入TIME_WAIT状态,一直占用端口号。设置socket属性可让其立即终止
Linux下

struct linger ling = {1, 0};
setsockopt(server_sockfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));

Windows下把上面参数都改为0就行了.

4. TCP长连接

对于TCP长连接保活是十分必要的,原因如下:

  1. 很多防火墙对一段时间内没有报文活动的socket会自动关闭。
  2. 对于非正常断开的连接系统并不能侦测到,比如防火墙关闭端口、网线被拔掉、电脑突然奔掉、未关闭应用程序直接关机(服务端无法释放资源)。(调用close(fd)为正常断开,连接对端可以侦测到)

TCP长连接保持的两种办法:

  1. 应用层面的心跳机制
    自定义心跳消息头,一般客户端主动发送到服务端,服务器接收后进行回应(也可以不回应),以便能够侦测连接是否异常断开。
  2. TCP协议自带的保活功能
    通过设置TCP keepalive的属性和发送底层心跳包的时间间隔。TCP keepalive是在底层定时发送心跳报文,服务器端接收到底层的心跳报文直接丢弃,不关心其内容。代码如下:
/*代码转自http://blog.csdn.net/embedded_sky/article/details/42077321*/
/*@author super bert 2014-12-16*/
/*socket TCP保持长连接函数*/
int socket_tcp_alive(int socket)
{
    int ret = 0;
 
    int keep_alive = 1;  
    ret = setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&keep_alive, sizeof(keep_alive));  
 
    if (ret == SOCKET_ERROR)  
    {
        printf("setsockopt failed: %d \n", WSAGetLastError());
        return -1;  
    }
 
    struct tcp_keepalive in_keep_alive = {0};
    unsigned long ul_in_len = sizeof(struct tcp_keepalive);
    struct tcp_keepalive out_keep_alive = {0};
    unsigned long ul_out_len = sizeof(struct tcp_keepalive);
    unsigned long ul_bytes_return = 0;
 
    in_keep_alive.onoff = 1; /*打开keepalive*/
    in_keep_alive.keepaliveinterval = 5000;	/*发送keepalive心跳时间间隔-单位为毫秒*/
    in_keep_alive.keepalivetime = 1000; /*多长时间没有报文开始发送keepalive心跳包-单位为毫秒*/
 
    ret = WSAIoctl(socket, SIO_KEEPALIVE_VALS, (LPVOID)&in_keep_alive, ul_in_len, 
                          (LPVOID)&out_keep_alive, ul_out_len, &ul_bytes_return, NULL, NULL);
 
    if (ret == SOCKET_ERROR)  
    {  
        printf("WSAIoctl failed: %d \n", WSAGetLastError());  
        return -1;  
    } 
 
 return 0;
}

5. getopt

处理命令行参数的一个函数
"a:b:cd::e",这就是一个选项字符串。对应到命令行就是-a ,-b ,-c ,-d, -e 。冒号又是什么呢? 冒号表示参数,一个冒号就表示这个选项后面必须带有参数(没有带参数会报错哦),但是这个参数可以和选项连在一起写,也可以用空格隔开,比如-a123 和-a 123(中间有空格) 都表示123是-a的参数;两个冒号的就表示这个选项的参数是可选的,即可以有参数,也可以没有参数,但要注意有参数时,参数与选项之间不能有空格(有空格会报错的哦),这一点和一个冒号时是有区别的。
大致处理代码如下:

 while ((opt = getopt(argc, argv, "+i:o:f:m:t:T:dnCB:S:M:x:Qv")) > 0)
    switch (opt) {
      case 'i': /* input dir */
        in_dir = optarg;
        break;
      case 'o': /* output dir */
        out_dir = optarg;
        break;      
      default:
        usage(argv[0]);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值