跳至主要内容

博文

HTTP报文中的消息类状态码

HTTP状态码(status codes)是HTTP协议中,响应报文的起始行中包含的一种服务器用于向客户端说明操作状态的三位数字。例如在一个正常的GET请求完成后,服务器会向客户端返回
HTTP/1.0 200 OK 在这个例子中,状态码就是 200
状态码的第一位数字表示了响应状态的类型,其中

1xx 信息提示2xx 成功3xx 重定向4xx 客户端错误5xx 服务器错误 今天我们主要讨论1xx的状态码,即消息状态码。由于当前的HTTP版本只为每种类型的状态码定义了少数一部分,而HTTP协议具有可拓展性,随着协议的发展,状态码将不断完善,较老版本的HTTP应用就不能识别较新的状态码,而这个特性也就使得不同版本的HTTP应用在通讯时产生了一些问题。由于 HTTP/0.9 版本的响应报文只包含实体部分,没有状态码或原因短语的存在,故不做讨论。
1xx状态码是 HTTP/1.1 版本新定义的,用来表示请求被正常接受,会进行进一步处理。这些状态码相对较新,并且 HTTP/1.0 版本无法识别,所以原则上不应该向HTTP/1.0版本的客户端发送任何1xx状态码。 100 Continue 该状态码说明服务器收到了请求的初始部分,并且请客户端继续发送。在服务器发送了 100 Continue 状态码之后,如果收到客户端的请求,则必须进行响应。
这个状态码实际上是对如下场景的一种优化:客户端有一个较大的文件需要上传并保存,但是客户端不知道服务器是否愿意接受这个文件,所以希望在消耗网络资源进行传输之前,先询问一下服务器的意愿。实际操作为客户端发送一条特殊的请求报文,报文的头部应包含
Expect: 100-continue 此时,如果服务器愿意接受,就会返回 100 Continue 状态码,反之则返回 417 Expectation Failed 状态码。对于客户端而言,如果客户端没有发送实际请求的打算,则不应该发送包含 100 Continue Expect 的报文,因为这样会让服务器误以为客户端将要发送一个请求。

之前提到过,并不是所有的HTTP应用都支持 100 Continue 这个状态码(例如HTTP/1.0及之前的版本的代理或服务器)所以客户端不应该在发送 100 Continue Expect 后一直等待服务器的响应,在一定时间后,客户端应当直接发送计划发送的内容。

最新博文

C语言中赋值表达式的返回值是什么?

我们或多或少都有过,或者见过将赋值表达式参与运算的情况。这通常会伴随着一些意想不到的问题。今天我就见到了一段奇怪的代码:
#include<stdio.h> int main() { int a =5; int b = (a=2)+(a=3); printf("%d %d\n",a,b); return 0; } 乍一看,似乎答案很明朗,按照顺序运算之后,a的值是3,b的值是5.有经验的程序员肯定会一眼看出,这里的计算过程是一个未定义行为(Undefined behavior).在这里简单来说就是:无法确定哪一个括号里的表达式会先执行。
括号只能改变运算符的结合律,不能改变表达式的求值顺序。这个顺序是取决于编译器的。所以a的值是2还是3是不能确定的。
这段代码在gcc(Ubuntu)下得到的结果是
3 6 而在clang(Mac)下运行的结果是
3 5为什么会这样呢? 这是怎么一回事呢?
查看它们生成的汇编代码gcc ... movl $5, -8(%rbp) // a=5 movl $2, -8(%rbp) // a = 2 movl $3, -8(%rbp) //a = 3 movl -8(%rbp), %eax // eax = a addl %eax, %eax //eax = eax + eax movl %eax, -4(%rbp) // b = eax ...
clang ... movl $5, -8(%rbp) movl $2, -8(%rbp) // a = 2 movl $3, -8(%rbp) // a = 3 movl $5, -12(%rbp) // b = 5 ...
在gcc的理解中a = (b=c) //会被改写成 b=c a=b //所以对于 a = (b=c)+(d=e) //会被改写成 b = c d = e a = b+d //当b和d为同一个值的时候,变量空间被复用了, 在clang的理解中a = (b=c)+(d=e) //被改写成了 i=b=c j=d=e a=i+j //所以直接得到了赋值符号右边表达式值之和 由此得出结论:赋值表达式的返回值为赋值符号右边的值。
但在某些特殊情况下,使用某些编译器可能无法得到想要的结果。所以我们应当尽量…

C语言中while语句里使用scanf的技巧

今天友人和我讨论了一段代码,是HDU的OJ上一道题目的解,代码如下
#include<stdio.h> { int a,b; while(~scanf("%d%d",&a,&b)) { printf("%d\n",a+b); } return 0; } 起初,我以为代码中while语句里的按位取反运算符写错了,应该是逻辑非运算符。
这时我在Quora上找到了类似的问题,我对其中一篇答案做了修改和翻译:
查阅scanf函数的man手册,关于返回值的说明如下
函数返回按照格式成功匹配并读入的输入项数量,并且可能会返回一个小于输入项总数的数字,而在匹配失败的情况下,甚至可能返回0。 如果在第一次成功读入或者发生匹配错误之前收到输入结束信号,将会返回EOF。在遇到读入错误的时候,也会返回EOF。 在上面的代码里,scanf的返回值可能是0,1,2或者EOF。
对0,1,2进行按位取反得到的都是非零值,此时while循环会继续执行。
在大多数环境里,EOF被定义为值为-1的常量,进行按位取反后得到的值为0.此时while循环将会结束。
综上所述,这个while语句可以不断从输入流读入数据,直到输入流结束,循环也就结束。
值得一提的是,这种用法仅仅在EOF被定义为-1的环境下有效,而且可读性很差。所以应该尽量避免使用它。
在Linux和OS X里,你可以通过Ctrl+D来发送一个输入结束信号,在Windows里你需要使用Ctrl+Z。

参考资料:
Quora上的回答
scanf(3)

对整型变量存储溢出的一些思考

今天看到阮一峰先生的一篇文章,介绍了一个因为错误使用整型变量而产生的bug。
文中有一小段我未能理解:
很显然,大量程序员考虑不周,使用4个字节的整数保存电话号码。当用户输入的号码大于2147483647时,就会自动转成这个数字。 我发现评论里有许多人和我有类似的疑问:为什么输入一个很大的数字之后,会自动转换成2147483647,而不是报错或者变成其他奇怪的值。
经过和网友的讨论,我做了一些实验,来测试当试图存入一个会溢出的数字时,会发生什么?

测试用代码:
int a = (int) 0xAABBCCDDEEFF1122LL;//若不使用强制类型转换,编译器会报错 printf("%d %X",a,a); 运行后的结果:
-285273822 EEFF1122 我发现,这个超长的整数在赋值之前被截断了,而并非像文章中所描述的那样取了整型范围内的最大值。
这时有人指出,在操作MySQL数据库时,如果插入的整数值超过其最大范围,会取范围内允许的最大值。同时附上了截图

至此,我的困惑才得以解答。原来是在数据库存储时,使用了错误的数据类型,才导致了这个bug出现。

在查阅资料的过程中,我在维基百科上发现了一则类似的事件
2014年12月,谷歌宣称因Youtube上播放次数最多的视频,PSY的《江南Style》音乐视频的播放次数超过了播放计数器的最大值(32位正负整型,即2147483647),导致Youtube不得不将播放计数器升级至64位整型。 后来谷歌承认这是一个玩笑。

测试博文

这是我的第一篇博文。