网络协议详解之 HTTP 协议

2016/11/20

概述

HTTP(HyperText Transfer Protocal)超文本传输协议, 是一个基于请求与响应模式的、无状态的应用层协议。它是 WEB 上应用最广泛的协议。它一般基于 TCP 的连接方式。其主要特点有:

  • 支持 C/S 通信模式
  • 简单快速。HTTP 协议简单,使得 HTTP 服务器的程序规模小,因而通信快。
  • 灵活。HTTP 协议允许客户端和服务端传输任意类型任意格式的数据。不同的类型由 Content-Tyoe 标记
  • 面向无连接。无连接是指每次建立的连接只处理一个文请求。
  • 无状态。无状态是指协议对于事务处理没有记忆能力。如果后续处理需要前面的信息,则它必须重传。这样可有导致每次连接传送的数据量增大。

HTTP URL

URL(Uniform Resource Locator) 统一资源定位符,它包含了查找某个资源的信息。其格式如下:

http 指定协议的名称,表示要通过 HTTP 协议来定位网络资源。 host 是一个合法的网络域名 或 IP 地址。 port 指定使用的网络端口,缺省值为 80 。 abs_path 指定请求的资源的 URI .如果 URL 中没有给出 URI, 则必须以 “/” 符号结束(这个工作通常由浏览器完成)。

连接

浏览器与服务器联系的最常用方法是与服务器的 80 端口建立 TCP 连接。使用 TCP 的意义在于,浏览器和服务器都不需要担心如何处理长消息、可靠性与拥塞控制,这些事将由 TCP 来处理。 在早期的 HTTP1.0 中,连接建立起来后会在一个请求和一个响应后立即释放。因为那时的 HTML 很简单,基本只有文本,使用这种模式就够了。但是随着时代的发展,HTML里包含了太多的东西,使用单独的 TCP 来传递每个资源代价太大。于是 HTTP1.1诞生了,它支持持续连接(persistent connection),它可以在一个 TCP 连接上进行多次请求响应,还可以发送流水线请求。这种做法减少建立多个 TCP 连接所用的时间,减少服务器的空闲时间,提高了性能。

HTTP 协议的请求

每个 HTTP Request (请求) 由一行或多行 ASCII 文本组成。其中第一行的第一个词为请求方法的名称,然后是请求资源的 URI,再后是协议的版本。这几个部分使用空格分开:

Method 为请求方法,必须为大写。 Request-URI 是一个统一资源标识符。  HTTP-Version 表示请求的 HTTP 协议版本。 CRLF 表示换行符。 例如:

常用的请求方法如下: 阅读全文…

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 755

树莓派(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 915

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 , 821

无效的 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,294