1. 程式人生 > >winsock WSAData SOCKET sockaddr_in sendto recvfrom

winsock WSAData SOCKET sockaddr_in sendto recvfrom

winsock

Winsock是Windows下的網路程式設計介面,它是由Unix下的BSD Socket發展而來,是一個與網路協議無關的程式設計介面。

構建程式設計環境

Winsock在常見的Windows平臺上有兩個主要的版本,即Winsock1和Winsock2。

  • 使用WINSOCK.H標頭檔案時,同時需要庫檔案WSOCK32.LIB,
  • 使用WINSOCK2.H時,則需要WS2_32.LIB,
  • 如果使用MSWSOCK.H中的擴充套件API,則需要MSWSOCK.LIB。

正確引用了標頭檔案,並連結了對應的庫檔案,你就構建起編寫WINSOCK網路程式的環境了。

#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib") 

初始化Winsock

每個Winsock程式必須使用WSAStartup載入合適的Winsock動態連結庫,如果載入失敗,WSAStartup將返回SOCKET_ERROR,這個錯誤就是WSANOTINITIALISED,WSAStartup的定義如下:

int WSAStartup(
    WORD wVersionRequested,
    LPWSADATA lpWSAData
);
wVersionRequested指定了你想載入的Winsock版本,其高位元組指定了次版本號,而低位元組指定了主版本號。
lpWSAData是一個指向WSAData結構的指標,WSAStartup會向該結構中填充其載入的Winsock動態鏈庫的資訊。

WSAData (Windows Sockets API)

這個結構被用來儲存 被WSAStartup函式呼叫後返回的 Windows Sockets資料。它包含Winsock.dll執行的資料。

typedef struct WSAData {
        WORD                    wVersion;
        WORD                    wHighVersion;
        unsigned short          iMaxSockets;
        unsigned short          iMaxUdpDg;
        char
FAR * lpVendorInfo; char szDescription[WSADESCRIPTION_LEN+1]; char szSystemStatus[WSASYS_STATUS_LEN+1]; } WSADATA, FAR * LPWSADATA;
wVersion為你將使用的Winsock版本號,wHighVersion為載入的Winsock動態庫支援的最高版本,注意,它們的高位元組代表次版本,低位元組代表主版本。
szDescription與szSystemStatus由特定版本的Winsock設定,實際上沒有太大用處。
iMaxSockets表示最大數量的併發Sockets,其值依賴於可使用的硬體資源。
iMaxUdpDg表示資料報的最大長度;然而,獲取資料報的最大長度,你需要使用WSAEnumProtocols對協議進行查詢。最大數量的併發Sockets並不是什麼神奇的數字,它是由可用的物理資源來決定的.
lpVendorInfo是為Winsock實現而保留的製造商資訊,這個在Windows平臺上並沒有什麼用處.

套接字型別

SOCKET sockListener=socket(AF_INET, SOCK_DGRAM, 0);
int socket(int domain, int type, int protocol);
domain引數:
PF_INET, AF_INET: Ipv4網路協議;
PF_INET6, AF_INET6: Ipv6網路協議。
type:
SOCK_DGRAM:  如果你傳輸的是視訊音訊等資料,丟幾個包也無所謂的,可以採用UDP
SOCK_STREAM:  如果需要傳輸的資料是準確的,建議採用TCP,也就是SOCK_STREAM 
引數protocol:
用來指定socket所使用的傳輸協議編號。這一引數通常不具體設定,一般設定為0即可。

sockaddr_in

用來處理網路通訊的地址。
sockaddr和sockaddr_in包含的資料都是一樣的,但他們在使用上有區別:

程式設計師不應操作sockaddr,sockaddr是給作業系統用的
一般的用法為:

程式設計師把型別、ip地址、埠填充sockaddr_in結構體,然後強制轉換成sockaddr,作為引數傳遞給系統呼叫函式

typedef struct sockaddr_in {
  ADDRESS_FAMILY sin_family;
  USHORT         sin_port;
  IN_ADDR        sin_addr;
  CHAR           sin_zero[8];
} SOCKADDR_IN, *PSOCKADDR_IN;

Members
sin_family
The address family for the transport address. This member should always be set to AF_INET.

sin_port
A transport protocol port number.

sin_addr
An IN_ADDR structure that contains an IPv4 transport address.

sin_zero
Reserved for system use. A WSK application should set the contents of this array to zero.

Remarks
All of the data in the SOCKADDR_IN structure, except for the address family, must be specified in network-byte-order (big-endian).

bind()

int bind(int sockfd, struct sockaddr * my_addr, int addrlen);
函式說明:bind()用來設定給引數sockfd 的socket 一個名稱. 此名稱由引數my_addr 指向一sockaddr 結構,對於不同的socket domain 定義了一個通用的資料結構

sendto()

int sendto (int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);
sendto(),是把UDP資料報發給指定地址;

recvfrom()

int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
recvfrom()是從指定地址接收UDP資料報
引數

  • s: socket描述符。
  • buf: UDP資料報快取地址。
  • len: UDP資料報長度。
  • flags: 該引數一般為0。
  • to: sendto()函式引數,struct sockaddr_in型別,指明UDP資料發往哪裡報。
  • tolen: 對方地址長度,一般為:sizeof(struct sockaddr_in)。
  • fromlen:recvfrom()函式引數,struct sockaddr_in型別,指明從哪裡接收UDP資料報。

對於sendto()函式,成功則返回實際傳送出去的字元數,失敗返回-1,錯誤原因存於errno 中。