socket 编程

C/C++ 的 socket 编程。开篇

  1. socket 编程貌似是从 *nix 到的 windows?
  2. socket 编程源于 C,但 C++ 似乎并没有原生的支持,依旧是 C 语言下的 socket 编程?
  3. C++ 的网络编程,包含哪些具体的内容?单单是 socket 吗? socket 编程不应该是更接近 C 语言吗?

socket 编程,入门学习非常推荐吴秦的 Linux Socket编程(不限Linux)。当做学习 socket 编程的第一篇完全足够,甩开网上其他的帖子一万八千里,强烈推荐。本意是整理 socket 的学习笔记,但有上述帖子完全足够,在此只记录一些“边边角角”的零碎知识。

手册推荐:Beej’s Guide to Network Programming

htonl() 函数、htons() 函数

在吴秦的博客里重点强调了主机字节序(host byte order)与网络字节序(network byte order)的,上述两个函数就是用来实现两者之间的转换的。参考 Beej’s Guide to Network Programming 我们能够找到以下函数原型:

1
2
3
4
5
6
#include <netinet/in.h>

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

不需要死记硬背,函数的命名通俗易懂。强调一下,转换 ip 地址使用长整型转换函数,转换 port 使用短整型转换函数。我在码代码学习时,误用 htonl(6666); 转换端口编译通过,运行时也不报错,启动多个服务程序也不报错 ps 正常情况重复启动服务程序时会报错“端口已经占用”。

INADDR_ANY

详细解释参考 understanding INADDR_ANY for socket programming - c。在此只强调一点,INADDR_ANY 表示的是一个服务器上所有的网卡。

inet_pton() 函数

IP地址转换函数,可以在将 IP 地址在“点分十进制”和“二进制整数”之间转换。在 Beej’s Guide to Network Programming 我们找到的描述以及函数原型:

Convert IP addresses to human-readable form and back.

1
2
3
4
5
6
#include <arpa/inet.h>

const char *inet_ntop(int af, const void *src,
char *dst, socklen_t size);

int inet_pton(int af, const char *src, void *dst);

强调一点,inet_pton() 同样支持 “localhost”。

inet_addr() 函数

Convert IP addresses from a dots-and-number string to a struct in_addr and back

1
2
3
4
5
6
7
8
9
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// ALL THESE ARE DEPRECATED! Use inet_pton() or inet_ntop() instead!!

char *inet_ntoa(struct in_addr in);
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);

我们可以看到其中的注释,这三个函数即将淘汰。

学习 libevent

疑问

  1. select() 函数第一个参数为什么要 maxfd+1?不理解 官方手册 中讲述 select() 低效的这段话:

    On the userspace side, …But on the kernel side,…

  2. 为什么在 Example: select()-based ROT13 server 中需要 make_nonblocking() ?为什么 Example: A low-level ROT13 server with Libevent 中需要 evutil_make_socket_nonblocking()

  3. setvbuf(stdout, NULL, _IONBF, 0); 的意义?

资源

最初步的认识,最简单的例子:使用libevent输出Hello

(niel)这里只提到了 strcut event_basestruct event。给出的简单示例代码里,有一处瑕疵: event_base_set() 函数属于过时的函数,在 2.0 之前的版本中配合 event_set() 使用,在 2.0 及其之后的版本中这两者被 event_new() 替代,所以作者混用 event_new() + event_base_set() 表明了作者并未多花时间学习。

接下来,我们可以学习一下:libevent入门教程:Echo Server based on libevent

(niel)这篇博客循序渐进,讲到了 strcut buffevent 及其相关操作。美中不足的是作者在介绍过程中穿插记录了自己的疑惑,新手读起来打破了学习的连贯性,本就在学习新知识,却也要困于作者的“泥潭”。只能说这真的只是作者的学习笔记,并未从读者的角度做考虑。总的来说,帖子很不错!初次学习时,这些问题的存在让人很难受,影响学习进度、学习动力;但熟悉作者讲的知识之后,这些问题反而才是“金子”,认真思考这些问题。

接下来推荐的学习资源就是官方手册了:Programming with Libevent

(niel)虽然是用英文写的,但阅读起来毫无障碍,很容易理解。marks C0、C1、R0 ~ R4、R8 认真阅读;R5、R6 重点关注了小部分函数,其余走马观花浏览了一下;R6a、R7、R9 三节没有看。开发过程中,查阅函数原型肯定是得翻这个手册的!

Libevent 官方文档学习笔记,这篇帖子可以看一看,和自己读英文手册理解的相互佐证。

Libevent学习笔记(一):基本使用,检验自己的学习成果。

总的来说,后面这两篇帖子并不适合用来学习。更多的定位于作者知识的整理,并不是面向新手的入门介绍。