1. 導讀

嘿!Socket 程式設計讓你感到挫折嗎?這份教材是不是只摘錄了 man 手冊,會很難嗎?你想要寫很酷的網路程式,可是你沒有時間能費力讀大量的資料結構,而且還得知道在呼叫 connect() 之前一定要先呼叫 bind() 的順序等。

好,猜到了嗎!其實我已經完成了這件痛苦的事情,我正要與你們分享這些資訊,所以你來對地方了。本文的目的是提供一份網路程式設計簡介,給想要了解網路程式的 C 程式設計師。

在這邊做個小結,我在這份文件裡已經放上了最新的資訊[其實還好啦],而且增加了對 IPv6 的介紹!好好享用它吧!

1.1 本書的讀者

本文件是一份導覽(tutorial),不是全方位的參考書。這份文件其實沒什麼了不起,不僅不夠全面,也沒有完整到足以做為 socket 程式設計的大全。

不過期盼本文能讓大家不要害怕 man 手冊 … :-)

1.2 平台與編譯器

本文談到的程式碼是在 Linux PC 上,使用 GNU 的 gcc 編譯器所編譯的。然而,它應該在任何有 gcc 的平台上都能編譯。不過實際上,如果你在 Windows 上寫程式,這可能會有點不太一樣,請參考下列關於 Windows 程式設計的章節。

1.3 官方網頁與書本

本文件的官方位置是 http://beej.us/guide/bgnet/。在這裡你也能找到程式碼的範例,以及各種語言的譯本。

如果需要購買價格比較好的複本[有人稱為"書"],請到 http://beej.us/guide/url/bgbuy。我很感謝您的購買,因為這可以幫忙我繼續依靠寫文件吃飯!

1.4 Solaris/SunOS 程式設計師要注意的事情

當編譯 Solaris 或 SunOS 平台的程式時,你需要指定一些額外的命令列參數,以連結(link)正確的函式庫(library)。為了達到這個目的,可以在編譯指令後面簡單加上"-lnsl -lsocket -lresolv",類似這樣:

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

如果還是有錯誤訊息,你可以再加上一個"-lnext"到命令列的尾端。我不太清楚這樣做了什麼事,不過有些人是會這樣用。

你可能會遇到的另一個問題是呼叫 setsockopt()。這個原型與在我 Linux 系統上的不一樣,所以可以這樣取代:

int yes=1;

輸入這行:

char yes='1';

因為我沒有 Sun 系統,所以我無法測試上面的資訊,這只是有人用 email 跟我說的。

1.5 Windows 程式設計師要注意的事情

本文以前只討論一點 Windows,純粹是我很不喜歡。不過我應該要客觀的說 Windows 其實提供很多基本安裝,所以顯然是個完備的作業系統。

人家說:小別勝新婚,這裡我相信這句話是對的[或許是年紀的關係]。不過我只能說,我已經十幾年沒有用 Microsoft 的作業系統來做自己的工作了,這樣我很開心!

其實我可以打出安全牌,只告訴你:"沒問題阿,你儘量去用 Windows 吧!"… 沒錯,其實我是咬著牙根說這些話的。

所以我還是在拉攏你來試試 Linux [1]、BSD [2],或一些 Unix 風格的系統。

不過人們各有所好,而 Windows 的使用者也樂於知道這份文件的內容能用在 Windows,只是需要改變一點程式碼而已。

你可以安裝一個酷玩意兒- Cygwin [3],這是讓 Windows 平台使用的 Unix 工具集。我曾在秘密情報網聽過,這個能讓全部的程式不經過修改就能編譯。

不過有些人可能想要用純 Windows 的方法來做。只能說你很有勇氣,而你所要做的事就是:立刻去弄個 Unix!喔,不是,我開玩笑的。這些日子以來,大家一直認為我對 Windows 是很友善的。

你所要做的事情就是[除非你安裝了 Cygwin!]:首先要忽略我這邊提過的很多系統 header(標頭檔),而你唯一需要 include (引用)的是:

#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 函式庫,在 Winsock 2.0 通常稱為 wsock32.lib 或 winsock32.lib 或 ws2_32.lib。在 VC++ 底下,可以透過專案(Project)選單,在設定(Settings)底下 …。按下 Link 標籤,並找到"Object/library modules"的標題。新增"wsock32.lib"(或者你想要用的函式庫)到清單中。

最後,當你用好 socket 函式庫時,你需要呼叫 WSACleanup(),細節請參考線上手冊。

只要你做好這些工作,本文後面的範例應該都能順利編譯,只有少部分例外。

還有一件事情,你不能用 close() 關閉 socket,你要用 closesocket() 來取代。而且 select() 只能用在 socket descriptors 上,不能用在 file descriptors(像 stdin 就是 0)。

還有一種你能用的 socket 類型,CSocket,細節請查詢你的編譯器使用手冊。

要取得更多關於 Winsock 的訊息可以先閱讀 Winsock FAQ [4]。

最後,我聽說 Windows 沒有 fork() 系統呼叫,我在一些範例中會用到。你可能需要連結到 POSIX 函式庫或要讓程式能動的一些函式庫,或許你也可以用 CreateProcess() 來取代。fork() 不需要參數,但是 CreateProcess() 卻需要大約 480 億個參數。如果你不想用,CreateThread() 會稍微比較容易理解 … 不過多執行緒(multithreading)的討論則不在本文件的範疇中。我只能盡量提到而已,你明白的!

譯註:作者說 480 億個參數只是想表達 CreateProcess() 需要的參數很多。

1.6 來信原則

通常我很樂意幫助解決來信的問題,所以請儘管寫信來,不過,我不一定會回信,我很忙,而且還有三次沒有回答你們的問題。在這種情況下,我通常只會把訊息刪掉,這並沒有針對任何人;我只是沒空可以詳細答覆問題。

同樣的原則,越複雜的問題我就越不想回答。如果你很想要收到答覆,你可以在寄信之前先簡化你的問題,並確定你引述了相關的資訊[比如平台、編譯器、得到的錯誤訊息,以及任何你想的到可以協助我找出問題的資訊]。對於更多的要點,請閱讀 ESR 的文件,提問的智慧(How To Ask Questions The Smart Way)[5]。

若你沒有收到答覆,請自行多多 hack(研究),試著找出答案,如果真的還是無法解決,那麼再寫信給我,並提供你找到的資訊,期盼會有足夠資訊可以讓我幫忙解決。

現在我一直纏著你說要怎麼寫信給我,以及哪些情況千萬不要寫信給我,我只想讓你知道,我誠心的感謝這幾年本文件所收到的讚美。它真的是個輕薄短小的文章,而且讓我很高興聽到大家說它非常實用!:-) 感謝您!

1.7 鏡射站台(Mirroring)

歡迎鏡射本站,無論公開或私人的。若你公開鏡射本站,並想要我從官網連結,請送個訊息到 beej@beej.us


1.8 譯者該注意的

如果你想要將本指南翻譯為其它語言,請寄信到 beej@beej.us,我會從官方主頁連結你的譯本,請隨意加上你的名字與聯絡資訊到譯本中。

請注意下列[版權與散佈]一節所列的授權限制,如果你想要我放譯本,跟我說就好了;若你想要自己架站,我會連結到你所提供的網址,任何方式都行。


1.9 版權與散佈(Copyright and Distribution)

Beej 的網路程式設計指南(Beej's Guide to Network Programming)版權是屬於 Copyright © 2012 Brian “Beej Jorgensen” Hall。對於特定的程式碼與譯本,在下面會另外說明,本作品基於 Creative Commons Attribution- Noncommercial- No Derivative Works 3.0 License 授權。欲檢視該授權的複本請參考 http://creativecommons.org/licenses/by-nc-nd/3.0/,Creative Commons,或者寫封信到這個住址:171 Second Street, Suite 300, San Francisco, California, 94105, USA. 該授權對於 “No Derivative Works” 這部分的例外如下:這份文件可以自由翻譯成任何語言,提供的譯本要正確,而重新列印時需要保持本文件的完整性。原本的文件授權規範亦會套用於譯本上。譯本可以包含譯者的名字與聯絡資訊。本文件所介紹的 C 原始程式碼在此公開釋出(public domain),並完全免於任何授權限制。歡迎老師們免費推薦或提供本文件的複本給你們的學生使用。

需要更多訊息請聯繫 beej@beej.us

譯註:中文讀者可來信給(Aaron Liao)aaron@netdpi.net

以下是 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.

參考資料
[1] http://www.linux.com/
[2] http://www.bsd.org/
[3] http://www.cygwin.com/
[4] http://tangentsoft.net/wskfaq/
[5] http://www.catb.org/~esr/faqs/smart-questions.html