从设计模式来说,就是简单的桥模式。
具体来说,系统提供了以下接口来封装:
#include <stdio.h>
FILE* fdopen(int fd, const char *mode);
调用好后,就可以通过FILE*接口来访问socket了。
问题的难点在关闭。
我们知道系统的fd是支持dup操作的。
对普通文件来说,由于有引用计数,多次关闭是没有问题的。
但对于socket来说,多次关闭就有冲突了。
如何解决?
书中的建议是从设计上来解决。
比如,我们可以创建2个流句柄,一个用来接收,一个用来发送。
s = socket(PF_INET, SOCK_STREAM, 0);
rx = fdopen(s, "r");
tx = fdopen(dup(s), "w");
对于关闭,可以以下处理:
接收:
shutdown(fileno(rx), SHUT_RD);
fclose(rx);
发送:
fflush(tx);
shutdown(fileno(tx), SHUT_WR);
fclose(tx);
小技巧:
对于errno 为EINTR,通常采用do-while来retry处理。
do {
clearerr(rx);
ch = fgetc(rx);
} while (ferror(rx) && errno == EINTR);
关于缓冲区大小设置,基本和文件I/O差不多,没啥好特别关注的。
接下来,介绍了一个常见工具函数
mkaddr
输入:host_name:service
输出:配置好相应IP与Port的socket_addr
函数实现用到了
strtok 这个函数主要目的是通过分隔符:来获取子字符串。
最后,书本举了一个RPN(逆波兰式计算公式的实现).
RPN在编译器语法分析中很重要。一个很常规的做法就是将
抽象语法树转化为后序表示法(等价于RPN),这样我们很简单
就可以用堆栈来模拟计算了。
比如: 3 + 5 * 2
假设对应的语法树为:
+
3 *
5 2
则其后缀表示为: 352 *+
操作数stack为 352
操作符stack为 *+
这样我们的处理算法就很简单了:(不考虑优先级)
while(1)
{
如果当前为操作符,并且不是"="
从stack里取相应操作数 (对于2目运算符+来说,就是取2个操作数)
将计算后的结果放入stack
如果当前为操作数
将操作数放入stack
如果为"="
将结果从stack中取出
如果stack非空,报错
退出循环
}
Linux Socket Programming by Example-第十章 标准I/O与Socket,布布扣,bubuko.com