libcurl 使用笔记

2016/11/17

libcurl 是一个免费开源的 客户端 的网络传输库,它支持多种协议,包括
DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP等,还支持 SSL 认证。它简单好用,用它自己的话来说,就是 free, thread-safe, IPv6 compatible, feature rich, well supported, fast, thoroughly documented and is already used by many known, big and successful companies and
numerous applications。

1 基本流程

使用 libcurl 的一般流程:

  1. curl_global_init() 进行库的初始化
  2. curl_easy_init() 获取CURL* 指针
  3. curl_easy_setopt() 设置传输参数,包括回调等
  4. curl_easy_perform() 完成传输
  5. curl_easy_cleanup() 释放内存
  6. curl_global_cleanup() 释放库内存

我们需要着重关心的,是第 3 步。在这一步里,我们将指定 libcurl 如何将参数传递给服务端。

1.1 简单示例

2 curl_easy API 介绍

阅读全文…

lambda 表达式 (in Python)

2016/11/16

概述lambda

python 中的 lambda 比较简单,只是作为创建匿名函数来使用

  • lambda 只是一个表达式,而不是一个代码块。类似于 C++ 中的 define ,但比 define 要简单.Python 中的 lambda 只能封装有限的逻辑进去。
  • lambda 拥有自己的全名空间,且不能访问自有参数列表之外及全局的参数。

语法

labmda 函数的语法只包含一个语句:

lambda 可以传入多个参数,使用逗号 “,” 分隔。 exception 使用这些参数进行运算并将结果返回。这里的 exception 隐藏了 return 关键词。 示例:

以上输出:

在 python 中的使用

lambda 的使用比较灵活。例如可以在函数内部定义匿名函数,实现简单逻辑并在函数内部使用。另一个常见的应用场景则是作为匿名函数对象在迭代器中使用。比如:

  • map : 对迭代器招待 function 操作,并将操作后的 list 返回
  • filter : function 应该返回一个布尔值,对迭代器操作为 False 的,将从 List 里排除
  • reduce : 对迭代器进行累计操作,即将上一次操作的结果作为function 的第一个参数进行下一次操作。reduce 最后一个参数作为可选参数,将在首先参与运算。

这几个函数的一般用法如下:

可以看到,我们需要为每个函数再定义一个函数,作为参数传入。 如果我们使用 lambda, 可以简化这些工作:

上面两种写法都输出:

但是,显然使用lambda的写法更加优雅。

Coding 650

树莓派(Debian)配置 DNS 服务

2016/11/14

流程:

  1. 安装 bind9
  2. 配置 domain.zone
  3. 配置 named.conf
  4. 检查配置
  5. 启动服务

安装 bind9

非 root 用户请注意使用 sudo

配置domain.zone

选任意一个地方新建一个文件 ,文件名可以为  domain.zone  (如 wandoer.com.zone).该文件会被named.conf 引用 。由于 named.conf位于 /etc/bind/ 路径下,为了方便管理,这里在此路径下建立文件夹 zones/ 来管理zone 文件

这里给出 wandoer.com.zone  的示例:

 

配置 named.conf

在 /etc/bind/ 路径下有几个 named.conf.* 文件,这里选 named.conf.default-zones 文件进行配置.打开文件,在最后加入以下几行:

检查配置

如果配置无误,则会显示 OK .否则配置提示进行修正。

启动服务

bind 默认将日志放在 /var/log/syslog 中。如果服务启动失败,则可以查看该日志查找原因。

验证DNS

打开 /etc/resolv.conf ,在第一个 nameserver 前再添加一个 nameserver,指向树莓派本机IP:

然后 ping  wandoer.com  查看是否已经将此域名解析到指定的IP.

Note 820

TCP/IP中write/read的行为

2016/10/12

read/write 为什么会被阻塞

首先应该知道的是,当write成功返回时,只是将buf中的数据复制到了缓冲区,至于数据什么时候被发往网络,什么时候被对方主机接收,什么时候被对方进程读取,系统调用层面不会给予任何保证和通知。
当kernel的该socket的发送缓冲区已满时,write就会被阻塞。每个socket都拥有自己的send buffer和receive buffer,其大小由系统自动调节。

已经发送到网络的数据依然需会在send buffer中暂存,只有当收到对方的ack后,kernel才从buffer中将这一部分清除。接收端将收到的数据暂存在receive buffer中,自动进行确认。但如果socket所在的进程来不及时将数据从receive buffer中取出,最终导致receive buffer填满,由于TCP的滑动窗口和拥塞控制,接收端会阻止发送端向其发送数据。这些控制皆发生在TCP/IP栈中,对应用程序是透明的,应用程序继续发送数据,最终导致send buffer填满,write调用阻塞。
一般来说,由于接收端进程从socket读数据的速度跟不上发送端进程向socket写数据的速度,最终导致发送端write调用阻塞。
而read调用的行为则相对容易理解,从socket的receive buffer中拷贝数据到应用程序的buffer中。read调用阻塞,通常是发送端的数据没有到达。 阅读全文…

Note , 738

无效的 UTF-8 字符串在移动端引发的问题

2016/09/27

C++ 返回的 char* 字符串(utf-8)中,夹杂了一些无效的字符,在移动端引发了一些问题。表现为:在 Android 端,引发了 JNI 异常:

env->NewStringUTF(data):

JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal continuation byte 0xe6

而在 iOS 端,则为

[NSString stringWithUTF8String:data]

的返回值为 nil

在 Android 端,这个BUG有人向 google 提交了 issue,暂还没有得在解决。目前的解决办法是多做一步转换,先将 char* 转为 JByteArray,再转成jString:

而在 iOS端,则可以使用 libiconv  将 UTF-8 字符串转为 GBK,再转为 UTF-8 字符串,转换时,使用 “//IGNORE” 选项忽略无效的字符,即可。

Note 1,095

函数调用约定(stdcall cdecl thiscall fastcall)

2016/08/31

引子

一位朋友在使用函数指针时出现了一个错误:这个函数指针 FP 要求有 4 个参数,而他将一个只有 3 个参数的函数作为 FP 使用,编译和运行都没有报错,但这样造成的运行结果可能是不正确的。下面一个例子来重现这个问题:

如上例,这两个函数的签名不同。 FunPt 要求 4 个参数,而函数 add 只有 3 个参数。虽然在编译和运行时都没有报错,但毫无疑问,返回的结果是错误的。为什么会出现这样的错误呢,这要从函数的调用约定说起。

__cdecl 调用约定

从 C 语言时代开始就有了这个调用约定。它又称 C调用约定,是 C 程序默认的调用约定(现在也是 C++ 程序默认的调用约定)。在这种约定下,函数参数从右向左入栈,函数堆栈由调用者清理,所以它允许函数参数的个数不确定,且它生成的可执行文件大小 会比 __stdcall 函数大。
按C编译方式,_cdecl调用约定仅在输出函数名前面加下划线,形如_functionname。

__stacall 调用约定

它是 Pascal 程序的默认调用方式,所以又称 Pascal 调用约定。和 __decel 一样,参数是从右到左入栈的方式,不同的是堆栈将由被调用函数来清理。
按C编译方式,_stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数

__fastcall 调用约定

它通 CPU 寄存器传递参数,所以调用较快。这也是为什么叫 “fastcall” 的原因。
按C编译方式,_fastcall调用约定在输出函数名前面加“@”符号,后面加“@”符号和参数的字节数

__thiscall 调用约定

它是 C++ 成员函数是默认调用约定。由于成员函数调用还有一个this指针,因此必须特殊处理。如果参数个数确定,this指针通过ecx传递给被调用者,函数自身清理栈;如果参数个数不确定,this指针在所有参数压栈后被压入堆栈,由调用者清理栈。它的参数也是从右向左入栈的。

比较

下面来比较 cdecl 和 stdcall 两种方式的代码:

借助 Visual Studio ,我们查看汇编代码:

可以看出:main 在调用由 __cdecl 标记的 cAdd 函数后,清理了栈,而调用由 __stdcall标记的 sAdd 函数后,并没有清理栈。

Note 792