翻译自 Beej’s Guide to Network Programming

译文会尽量的保持原文风趣的风格。

自己加了点表情包哈哈,灵感来自《HEAD FIRST》系列的书

1. 前言

Hi 小老弟,socket 编程是不是让你很难受呀~ 要想在 man 文档上搞明白这东西可难了吧。你要想炫酷地完成网络编程,但当你打算调用 Socket API 时,是不是被各种莫名其妙看起来又差不多的 struct 给烦死了。

我已经把那些磨人的小妖精给搞明白了,现在非常激动得想着要分享给你们呢,你们算是找对地方了,这个文章就是打算给中等水平的 C 程序员一个大概提纲,让他(她)们能上手开始撸 Socket。

并且我可是跟上了时代的哦,这篇文章还有关于 IPv6 的指导呢,撒花~

1.1 受众

这篇文章是一个教程向的文章,不是一个详尽的参考手册,所以是比较适合那些想要找个文章指导自己上手 socket 编程的读者。这绝对不是一个大而全的的 socket 编程指导,这点要搞清楚哈。

1.2 平台和编译器

这个文章里面的代码是在用 GNU 的 gcc 编译器,在一个使用 Linux 系统的 PC 上编译的。照理来说,应该能够在所以使用 gcc 的平台上构建,显然这里面不包括 Windows,如果你是在 Windows 上编程,请参考 在 Windows 上编程 这一节。

1.3 官网与书籍的购买

这篇文章官方的网址是:http://beej.us/guide/bgnet/ 。在那里你可以找到示例代码,以及其它语言的翻译版本。

如果想要买一份文字清晰装帧精美的印刷版(也就是“纸质书”),请访问 http://beej.us/guide/url/bgbuy 。我会非常感谢各位金主惠顾的,因为这样我就可以一直靠写文档来维持生活这样子。(打工是不可能打工的——窃·格瓦拉)

1.4 Solaris/SunOS 的程序员要注意的事项

在 Solaris/SunOS 上编译时,你需要指定一些额外的命令行参数来确保能够链接到正确的库,具体来说,应该在编译命令的后面添加 -lnsl -lsocket -lresolv 这仨参数。例如:

$ cc -o server server.c -lnsl -lsocket -lresolv

如果你还是报错的话,你可以试着再加个 -lxnet 在命令后面,我不知道这是干嘛用的,不过似乎有些读者表示需要加上它。

还有一个问题就是:你在调用 setsocketopt() 的时候,这个函数的原型可能跟我在 Linux 下的原型不一样,所以,你可能需要:

char yes='1';

而不是像我这样:

int yes=1;

因为我没有 Sun 的机器,以上的信息我都没有确认过——都是道听途说 热心读者通过邮件告诉我的。

1.5 Windows 程序员要注意的事项

以前这份指南里面,我基本都不理 Windows 的,单纯是因为我并不十分喜欢 Windows。但是讲道理,Windows 的市场份额非常的大,而且显然也是一个非常完善的操作系统了。

人们说距离产生美,在某些情况下,我是同意的,这十多年来我远离了 Windows 的系统,我的生活真是越过越美了(:confused:那句话好像不是这么理解的吧)。因为我现在很幸福,所以可以很心平气和地跟你说:”没问题呀~放开膀子去使用 Windows 系统吧~“ …好吧,说出这种话还是会让我觉得有点恶心的。

所以我依然还是鼓励你去使用 Linux, BSD,或者其它某些类 Unix 的操作系统。

但是萝卜青菜各有所爱嘛,你们这些 Windows 党应该会庆幸:我这篇文章的大部分内容,在 Windows 系统下也适用,只是某些代码稍微要做些改动。

有个非常酷的东西叫 Cygwin,它是一些可以在 Windows 下运行的 Unix 工具集。我听说坊间传闻说安装它可以让你不做任何更改就成功编译本文章的代码。

但是你们之中肯定有某些幺蛾子想用纯 Windows 的方式来编程。警告你们不要欺人太甚啊!你们这种人,唯一的解决方案就是:赶紧把系统换成 Linux!不,不不不,开玩笑的各位老板,我应该要给 Windows 用户更多的包容与关爱。

你们要做的是(如果你用 Cygwin 就不用这么做):第一步,忽略掉我在文章中引用的各种系统头文件,你们唯一需要引用的是:

#include <winsock.h>

等等!你们在调用任何 socket 库的函数之前,还得要调用 WSAStartup(),代码大概是这样子的:

#include <winsock.h>

{
    WSADATA wsaData;   // if this doesn't work
    //WSAData wsaData; // then try this instead

    // MAKEWORD(1,1) for Winsock 1.1, MAKEWORD(2,0) for Winsock 2.0:

    if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
        fprintf(stderr, "WSAStartup failed.\n");
        exit(1);
    }

你还得告诉你的编译器要链接 Winsock 库,通常它们叫 wsock32.lib 或者 winsock32.lib 或者——如果你是使用 Winsock 2.0 版本的话—— ws2_32.lib。在 VC++ 里面,你可以通过 “Project” 菜单 - “settings…” 选项,点击 “Link” 标签,找到内容为 “Object/library modules” 的输入框,添加 “wsock32.lib” (或者随便一个其它的,你喜欢就好)。

反正别人是这么跟我说的。

最后,当你不再需要调用 socket 库里面的函数时,你要调用 WSACleanup(),欲知详情,自己查文档。

一旦你把这些事情都做到了以后,剩下的文章里面的代码应该都能在 Windows 上适用了。除了几个例外:你不能使用 close() 来关闭 socket,你需要用 closesocket() 函数。并且,select() 也只能用在 socket 描述符上,不能用在文件描述符(比如代表标准输入stdin

的文件描述符 0)。

还有一个 socket 的类你可以用,CSocket,翻翻看你的编译器的帮助文档,来获取相关信息。

要想了解更多 Winsock 的信息,请阅读这个 Winsock FAQ

最后,我听说 Windows 没有 fork 函数,这个抱歉了兄弟,很不巧地我的示例代码中用到了。也许你可以链接一个 POSIX 的库来让它能用。或者用 CreateProcess() 来代替 fork()fork() 函数是不用传参数的,而 CreateProcess() 大概要传五百万个参数。如果你不太喜欢它,CreateThread() 要的参数可能少些。不过这篇文章不打算讨论多线程这个话题,所以我只能说这么多了,你懂得。

1.6 邮件规则

通常情况下我可以通过电子邮件回答你们的问题,所以不要客气尽管发邮件给我,但是我不能保证会回复哈。你知道我很忙的,有时候我确实是没法回到你的问题,这种情况下我通常都是直接把它给删掉。这不是在针对你哦,我只是没时间那么深入去回答你的问题了。

一般来说,你问的问题越复杂,我回复的可能性越小。如果你在发邮件前可以把问题的范围缩小一点,并且确保附上了所有相关的信息(比如平台、编译器、收到的错误信息或者任何你觉得能帮助我定位问题的信息),你会更有希望能够收到我的回复哦。更多提问题的建议,可以去看看 ESR 的文章:How To Ask Questions The Smart Way。(译注:这文章非常的出名,流传甚广,在网上能找到很多中文译文)

1.7 制作镜像网站

不管你是打算私有地还是公开地建立本网站的镜像网站,我都非常欢迎你这么做。如果你是制作一个公开的镜像网站,并且希望我在主页上把你的网站加上,请把你的网址发给我 beej@beej.us

1.8 翻译者的注意事项

如果你打算把本指南翻译成其他语言,请把你的网址发给我 beej@beej.us,我会把你的翻译添加到主页中去。不用客气,你可以随意地在译文上加上你的名字和联系方式哈。

请留意一下下面 版权与出版 小节里面的许可限制。

如果你想自己来搭建网站来展示译文,跟我说就好了,我会把你的网站添加进来的。不管怎样,你开心就好。

1.9 版权与出版

(译注:因为涉及到法律条文,我看不懂为了保持严谨,我就不翻译了)

Beej’s Guide to Network Programming is Copyright © 2012 Brian “Beej Jorgensen” Hall.

With specific exceptions for source code and translations, below, this work is licensed under the Creative Commons Attribution- Noncommercial- No Derivative Works 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/3.0/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.

One specific exception to the “No Derivative Works” portion of the license is as follows: this guide may be freely translated into any language, provided the translation is accurate, and the guide is reprinted in its entirety. The same license restrictions apply to the translation as to the original guide. The translation may also include the name and contact information for the translator.

The C source code presented in this document is hereby granted to the public domain, and is completely free of any license restriction. Educators are freely encouraged to recommend or supply copies of this guide to their students. Contact beej@beej.us for more information.