SOCKET筆記~

來源:互聯網
上載者:User

在WINDOWS環境下使用SOCKET前需要初始化windows socket庫,否則socket()會返回SOCKET_ERROR(-1)

  WSADATA     wsaData;
  WORD wVersionRequested;// Version
  wVersionRequested = MAKEWORD(1,1);//Version Info
  // Initialize Windows socket library
  WSAStartup(wVersionRequested, &wsaData);

總的來說網路程式是由兩個部分組成的--用戶端和伺服器端.它們的建立步驟一般是:

    伺服器端 socket-->bind-->listen—>accept

    用戶端 socket-->connect

SOCKET socket(int domain, int type,int protocol)

  • domain:說明我們網路程式所在的主機採用的通訊協族(AF_UNIX和AF_INET等). AF_UNIX只能夠用於單一的Unix系統處理序間通訊,而AF_INET是針對Internet的,因而可以允許在遠程主機之間通訊
  • type:我們網路程式所採用的通訊協議(SOCK_STREAM,SOCK_DGRAM等) SOCK_STREAM表明我們用的是TCP協議,這樣會提供按順序的,可靠,雙向,連線導向的位元流. SOCK_DGRAM 表明我們用的是UDP協議,這樣只會提供定長的,不可靠,不需連線的通訊.
  • protocol:由於我們指定了type,所以這個地方我們一般只要用0來代替就可以了 下面是from WINSOCK.H的協議定義

#define IPPROTO_IP              0               /* dummy for IP */

#define IPPROTO_ICMP            1               /* control message protocol */

#define IPPROTO_IGMP            2               /* internet group management protocol */

#define IPPROTO_GGP             3               /* gateway^2 (deprecated) */

#define IPPROTO_TCP             6               /* tcp */

#define IPPROTO_PUP             12              /* pup */

#define IPPROTO_UDP             17              /* user datagram protocol */

#define IPPROTO_IDP             22              /* xns idp */

#define IPPROTO_ND              77              /* UNOFFICIAL net disk proto */

#define IPPROTO_RAW             255             /* raw IP packet */

#define IPPROTO_MAX             256

e.g.

sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

成功返回SOCKET檔案描述符,失敗返回-1

int bind(int sockfd, struct sockaddr *my_addr, int addrlen)

  • sockfd:是由socket調用返回的檔案描述符.
  • addrlen:是sockaddr結構的長度.
  • my_addr:是一個指向sockaddr的指標. 在WINSOCK.H中有 sockaddr的定義 :
struct sockaddr {
        u_short sa_family;              /* address family */
        char    sa_data[14];            /* up to 14 bytes of direct address */
};

不過由於系統的相容性,我們一般不用這個標頭檔,而使用另外一個結構(struct sockaddr_in) 來代替.在WINSOCK.H中有sockaddr_in的定義 :

/*
 * Socket address, internet style.
 */
struct sockaddr_in {
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};

我們主要使用Internet所以sin_family一般為AF_INET,sin_addr設定為INADDR_ANY表示可以和任何的主機通訊,sin_port是我們要監聽的連接埠號碼.sin_zero[8]是用來填充的. bind將本地的連接埠同socket返回的檔案描述符捆綁在一起.成功是返回0,失敗返回-1。

sin_port 是網路位元組順序,sin_addr.s_addr 也是的。在處理自己的 IP 位址和/或連接埠的 時候,有些工作是可以自動處理的。

      my_addr.sin_port = 0; /* 隨機播放一個沒有使用的連接埠 */

my_addr.sin_addr.s_addr = INADDR_ANY; /* 使用自己的IP地址 */

通過將0賦給 my_addr.sin_port,你告訴 bind() 自己選擇合適的端 口。同樣,將 my_addr.sin_addr.s_addr 設定為 INADDR_ANY,你告訴 它自動填上它所啟動並執行機器的 IP 位址。

e.g.

localaddr.sin_addr.s_addr = inet_addr(ipaddr);
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(portNum);
bind(s_ , (struct sockaddr*)&localaddr , sizeof(localaddr)) ;

由於用戶端不需要固定的連接埠號碼,因此不必調用bind(),用戶端的連接埠號碼由核心自動分配。如果伺服器不調用bind(),核心會自動給伺服器分配監聽連接埠,每次啟動伺服器時連接埠號碼都不一樣,用戶端要串連伺服器就會遇到麻煩。

int listen (SOCKET s, int backlog);

  • s:bind後的SOCKET檔案描述符
  • backlog:佈建要求排隊的最大長度.當有多個用戶端程式和服務端相連時, 使用這個表示可以介紹的排隊長度.(允許監聽多少個TCP串連)
  • listen函數將bind的檔案描述符變為監聽通訊端.出錯返回-1

e.g.

listen(sListen, 3);

 

SOCKET accept (SOCKET s, struct sockaddr *addr,  int *addrlen);

  • s:是listen後的SOCKET檔案描述符
  • addr,addrlen是用來給用戶端的程式填寫的,伺服器端只要傳遞指標就可以了. bind,listen和accept是伺服器端用的函數,accept調用時,伺服器端的程式會一直阻塞到有一個客戶程式發出了串連. accept成功時返回最後的伺服器端的檔案描述符,這個時候伺服器端可以向該描述符寫資訊了. 失敗時返回-1

e.g.

sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);

 

int connect (SOCKET s, const struct sockaddr *name, int namelen);

  • s:socket返回的檔案描述符
  • name:儲存了伺服器端的串連資訊.其中name是服務端的地址
  • namelen: name的長度
  • connect函數是用戶端用來同服務端串連的.成功時返回0,sockfd是同服務端通訊的檔案描述符失敗時返回-1

e.g.

memset(&server, 0, sizeof(SOCKADDR_IN));
server.sin_family = AF_INET;
server.sin_addr.S_un.S_addr = inet_addr(SERVER_ADDRESS);
server.sin_port = htons(PORT);
connect(sClient, (struct sockaddr *)&server, sizeof(SOCKADDR_IN));

 

int send(SOCKET s, const char * buf, int len, int flags);

  • s: SOCKET檔案描述符
  • buf: 要發送的資料
  • len:發送的資料長度
  • flag:用來影響對端SOCKET的行為。一般設為0。(這裡和這裡有flag的討論)
  • 發送成功返回實際發送的長度,失敗返回-1(SOCKET_ERROR)

      send函數僅僅是把buf中的資料成功copy到s的發送緩衝區裡後它就返回了,但是此時這些資料並不一定馬上被傳到串連的另一端。注意並不是send把s的發送緩衝區中的資料傳到串連的另一端的,而是協議傳的,send僅僅是把buf中的資料copy到s的發送緩衝區的剩餘空間裡。傳輸中遇到的網路錯誤會在下一個socket函數中返回SOCKET_ERROR。

      注意:在Unix系統下,如果send在等待協議傳送資料時網路斷開的話,調用send的進程會接收到一個SIGPIPE訊號,進程對該訊號的預設處理是進程終止

 

int recv (SOCKET s, char * buf, int len, int flags);

  • s: SOCKET檔案描述符
  • buf: 讀取的資料存放的緩衝buf
  • len:緩衝buf的最大長度
  • flags: 同上
  • 返回實際讀入緩衝的資料的位元組數。或者在錯誤的時候返回-1

     當應用程式調用recv函數時,recv先等待s的發送緩衝 中的資料被協議傳送完畢,如果協議在傳送s的發送緩衝中的資料時出現網路錯誤,那麼recv函數返回SOCKET_ERROR,如果s的發送緩衝中沒有數 據或者資料被協議成功發送完畢後,recv先檢查通訊端s的接收緩衝區,如果s接收緩衝區中沒有資料或者協議正在接收資料,那麼recv就一直等待,只到 協議把資料接收完畢。當協議把資料接收完畢,recv函數就把s的接收緩衝中的資料copy到buf中(注意協議接收到的資料可能大於buf的長度,所以 在這種情況下要調用幾次recv函數才能把s的接收緩衝中的資料copy完。recv函數僅僅是copy資料,真正的接收資料是協議來完成的),recv函數返回其實際copy的位元組數。如果recv在copy時出錯,那麼它返回SOCKET_ERROR;如果recv函數在等待協議接收資料時網路中斷了,那麼它返回0

 

int sendto( SOCKET s, const char * buf, int len, int flags,const struct sockaddr * to, int tolen);

  • s: SOCKET檔案描述符
  • buf: 包含待發送資料的緩衝區
  • len:緩衝buf的最大長度
  • flags: 調用方式標誌位
  • to:(可選)指標,指向目的套介面的地址
  • tolen:to所指地址的長度

      sendto()函數主要用於SOCK_DGRAM類型套介面向to參數(目的地的 IP 位址和連接埠資訊)指定端的套介面發送資料報。對於SOCK_STREAM類型套介面,to和tolen參數被忽略;這種情況下sendto()等價於send()。

      對於資料報類套(SOCK_DGRAM)介面,必需注意發送資料長度不應超過通訊子網的IP包最大長度。IP包最大長度在WSAStartup()調用返回的WSAData的iMaxUdpDg元素中。如果資料太長無法自動通過下層協議,則返回WSAEMSGSIZE錯誤,資料不會被發送。

     若無錯誤發生,send()返回所發送資料的總數(請注意這個數字可能小於len中所規定的大小)。否則的話,返回SOCKET_ERROR錯誤,應用程式可通過WSAGetLastError()擷取相應錯誤碼

 

int recvfrom( SOCKET s, char * buf, int len, int flags,struct sockaddr * from, int * fromlen);

  • s: SOCKET檔案描述符
  • buf: 接收資料緩衝區
  • len:緩衝buf的最大長度
  • flags: 叫用作業方式
  • from:(可選)指標,指向裝有源地址的緩衝區
  • fromlen:(可選)指標,指向from緩衝區長度值

     對於SOCK_STREAM類型套介面,忽略from和fromlen參數。若from非零,且套介面為SOCK_DGRAM類型,則發送資料來源的地址被複製到相應的sockaddr結構中。fromlen所指向的值初始化時為這個結構的大小,當調用返回時按實際地址所佔的空間進行修改。

    如果沒有資料待讀,那麼除非是非阻塞模式,不然的話套介面將一直等待資料的到來,此時將返回SOCKET_ERROR錯誤,錯誤碼是WSAEWOULDBLOCK。用select()或WSAAsynSelect()可以獲知何時資料到達。

    若無錯誤發生,recvfrom()返回讀入的位元組數。如果串連已中止,返回0。否則的話,返回SOCKET_ERROR錯誤,應用程式可通過WSAGetLastError()擷取相應錯誤碼。

 

註:以上代碼全部使用的是WINSOCK.H中的定義,與WINSOCK2.H中的略有不同。二者是區別如下:

  • winsock.h 使用 wsock32.lib  傳說中的Berkeley socket,由Unix下的BSD Socket發展而來
  • winsock2.h 使用 with ws2_32.lib

       對於大多數windows應用程式,二者區別不大,WINSOCK2提供了新的函數針對新的協議,比如bluetooth。WINSOCK2還提供了LSP機制,The cool thing about this is that you can create your own layers which will in turn get called by the winsock implementation when any application calls the function you layered. Think of it as an easy way to hook any winsock function.

Winsock2是完全向後相容的,WINSOCK基本上只有在你準備在一個不支援WINSOCK2的平台上搞開發時才應該被考慮使用。

 

摘自Wiki:

Microsoft implementations
  • Microsoft did not supply an implementation of Winsock 1.0.
  • Version 1.1 of Winsock was supplied in an add-on package (called Wolverine) for Windows for Workgroups (code named Snowball). It was an integral component of Windows 95 and Windows NT from versions 3.5 and onwards (the initial commercially available version of Windows NT, version 3.1, included only a proprietary and quite incomplete implementation of TCP/IP based on the AT&T UNIX System V "Streams" API[citation needed]).
  • Version 2.1 of Winsock was supplied in an add-on package for Windows 95. It was an integral component of Windows 98, Windows NT 4.0, and all subsequent Windows releases. (Microsoft did not supply implementations of Winsock 2 for Windows 3.x or Windows NT 3.x.)
  • Recent versions of Winsock 2.x have been delivered with new Windows releases or as part of service packs.
  • Winsock 2 is extensible by a mechanism known as a Layered Service Provider (LSP). Winsock LSPs are available for a wide range of useful purposes, including Internet parental controls, web content filtering, QoS etc. The layering order of all providers is kept in the Winsock Catalog. In previous versions of Windows, removing a buggy LSP could result in corruption of the Winsock catalog in the registry, potentially resulting in a loss of all network connectivity. Winsock in Windows XP Service Pack 2, Windows Server 2003 Service Pack 1 and all later Windows operating systems has the ability to self-heal after a user uninstalls such an LSP.

 

Reference:

《網路socket編程指南》:這個文檔是一個指南,而不是參考書。如果你剛開始 socket 編程並想找一本入門書,那麼你是我的讀者。但這不是一本完全的 socket 編程書。

《Linux C編程一站式學->2. 基於TCP協議的網路程式->第 37 章 socket編程》:Mark一下以後詳細看

《UDP協議的兩個主要方法sendto和recvfrom詳解》

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.