windows socket函數詳解

JK轉至:https://www.cnblogs.com/hgwang/p/6074038.htmlhtml

流程圖:node

0:函數庫頭文件

#include <WinSock2.h>
#pragma comment(lib,"Ws2_32.lib ")

 

1:WSAStartup   初始化Ws2_32.dll的函數

WSAStartup 函數用於初始化供進程調用的Winsock相關的dll。編程

1 int WSAStartup(
2   __in          WORD wVersionRequested,
3   __out         LPWSADATA lpWSAData
4 );

Parameters

  wVersionRequested

標識了用戶調用的Winsock的版本號。高字節指明輔版本編號,低字節指明主版本編號。一般使用MAKEWORD來生成一個版本號。 當前Winsock sockets的版本號爲2.2,用到的dll是 Ws2_32.dll。
服務器

  lpWSAData

指向WSADATA結構體的指針,lpWSAData返回了系統對Windows Sockets 的描述網絡

Return Value

若是調用成功,WSAStartup 函數返回0。不然,將返回五種錯誤代碼之一。但絕對不能使用WSAGetLastError獲取錯誤代碼。多線程

WSAData wsa;
    if (::WSAStartup(MAKEWORD(2,2),&wsa) != 0)
    {
        cout<<"WSAStartup error"<<endl;
        return 0;
    }

2:WSACleanup   釋放Ws2_32.dl的l函數

該函數釋放對Winsock連接庫的調用。less

int WSACleanup(void);

返回值0表示正常退出,返回值SOCKET_ERROR表示異常。返回值是SOCKET_ERROR,能夠調用 WSAGetLastError.查看錯誤代碼。須要注意的是,在多線程環境下,WSACleanup 函數將終止全部線程的socket操做。socket

3:socket   建立socket的函數

socket函數將建立指定傳輸服務的socket。ide

1 SOCKET WSAAPI socket(
2   __in          int af,
3   __in          int type,
4   __in          int protocol
5 );

Parameters

af   ( address family函數

  指明地址簇類型,經常使用的地址簇以下,其他地址簇在Winsock2.h中定義。

AF_UNSPEC(未指明)、

AF_INET(IPv4)、

AF_NETBIOS(NETBIOS地址簇)、

AF_INET6(IPv6)、

AF_IRDA(Infrared Data Association (IrDA)地址簇)、

AF_BTM(Bluetooth)。

type

  指明socket的類型,Windows Sockets 2常見類型以下:

SOCK_STREAM(流套接字,使用TCP協議)、

SOCK_DGRAM(數據報套接字,使用UDP協議)、

SOCK_RAW(原始套接字)、

SOCK_RDM(提供可靠的消息數據報文,reliable message datagram)、

SOCK_SEQPACKET(Provides a pseudo-stream packet based on datagrams,在UDP的基礎上提供了僞流數據包)。

protocol

指明數據傳輸協議,該參數取決於af和type參數的類型。protocol參數在Winsock2.h and Wsrm.h定義。一般使用以下3中協議:

IPPROTO_TCP(TCP協議,使用條件,af是AF_INET or AF_INET六、type是SOCK_STREAM )

IPPROTO_UDP(UDP協議,使用條件,af是AF_INET or AF_INET六、type是SOCK_DGRAM)

IPPROTO_RM(PGM(Pragmatic General Multicast,實際通用組播協議)協議,使用條件,af是AF_INET 、type是SOCK_RDM)

Return Value

If no error occurs, socket returns a descriptor referencing the new socket. Otherwise, a value of INVALID_SOCKET is returned, and a specific error code can be retrieved by calling WSAGetLastError.

若是不出錯,socket函數將返回socket的描述符(句柄),不然,將返回INVALID_SOCKET。 

1     SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
2     if (s == INVALID_SOCKET)
3     {
4         int er = WSAGetLastError();
5         return 0;
6     }     

4:bind    服務端將socket與地址關聯

bind函數將socket關聯一個本地地址。

1 int bind(
2   __in          SOCKET s,
3   __in          const struct sockaddr* name,
4   __in          int namelen
5 ); 

Parameters

s

指定一個未綁定的socket。

name

指向sockaddr地址的指針,該結構含有IP和PORT

namelen

參數name的字節數。

Return Value

If no error occurs, bind returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError.

無錯誤返回0,又錯誤返回SOCKET_ERROR。

 1 sockaddr_in service;
 2   service.sin_family = AF_INET;
 3   service.sin_addr.s_addr = inet_addr("127.0.0.1");
 4   service.sin_port = htons(27015);
 5 
 6   //----------------------
 7   // Bind the socket.
 8   if (bind( ListenSocket, (SOCKADDR*) &service,sizeof(service)) == SOCKET_ERROR) {
 9     closesocket(ListenSocket);
10     return;
11   }

sin_port和sin_addr都必須是網絡字節序(NBO),通常可視化的數字都是主機字節序(HBO)。

 

兩者長度同樣,都是16個字節,即佔用的內存大小是一致的,所以能夠互相轉化。兩者是並列結構,指向sockaddr_in結構的指針也能夠指向sockaddr。

sockaddr經常使用於bind、connect、recvfrom、sendto等函數的參數,指明地址信息,是一種通用的套接字地址。 
sockaddr_in 是internet環境下套接字的地址形式。因此在網絡編程中咱們會對sockaddr_in結構體進行操做,使用sockaddr_in來創建所需的信息,最後使用類型轉化就能夠了。通常先把sockaddr_in變量賦值後,強制類型轉換後傳入用sockaddr作參數的函數:sockaddr_in用於socket定義和賦值;sockaddr用於函數參數。

題外話,兩個函數 htons() 和 inet_addr()。

htons()做用是將端口號由主機字節序轉換爲網絡字節序的整數值。(host to net)

各個機器cpu對數據存儲和表示的方法不通,intel機器用littele-endian存數據,而IBM機器用big-endian存數據。網絡協議爲取消這種差別,一致採用big-endian方式。htons用於將unsigned short的數值從littele-endian轉換爲big-endian,因爲short只有2字節,經常使用語port數值的轉換。htons用於將unsigned long的數值從littele-endian轉換爲big-endian,long有4字節,經常使用於ipv4地址的轉換。

inet_addr()做用是將一個IP字符串轉化爲一個網絡字節序的整數值,用於sockaddr_in.sin_addr.s_addr。

inet_ntoa()做用是將一個sin_addr結構體輸出成IP字符串(network to ascii)。

printf("%s",inet_ntoa(mysock.sin_addr));

htonl()做用和htons()同樣,不過它針對的是32位的(long),而htons()針對的是兩個字節,16位的(short)。

與htonl()和htons()做用相反的兩個函數是:ntohl()和ntohs()。 

INADDR_ANY

數值爲0。不少帖子對這個值的理解不一。我查了一下CMU(卡耐基梅隆大學cs課程,深刻理解計算機系統做者是該校計算機學院院長)的資料,看到以下解釋:

源自:https://www.cs.cmu.edu/~srini/15-441/F01.full/www/assignments/P2/htmlsim_split/node18.html

用INADDR_ANY來配置IP地址,意味着不須要知道當前服務器的IP地址。對於多網卡的服務器,INADDR_ANY容許你的服務接收一個服務器上全部網卡發來的數據。下面例子也有寫,若是某個socket使用INADDR_ANY和8000端口,那麼它將接收該全部網卡傳來的數據。而其餘socket將沒法再使用8000端口。

 1     sockaddr_in service;
 2     ZeroMemory((char *)&service,sizeof(sockaddr_in));
 3     service.sin_family = AF_INET;
 4     //service.sin_addr.S_un.S_addr  =/*INADDR_ANY*/ inet_addr("127.0.0.1");
 5     service.sin_addr.s_addr  = INADDR_ANY;
 6     service.sin_port = htons(8278);
 7     if (bind(s,(sockaddr*)&service,sizeof(service)) == SOCKET_ERROR)
 8     {
 9         int er = WSAGetLastError();
10         closesocket(s);
11    

4:listen    服務端網絡監聽

 description:The listen function places a socket in a state in which it is listening for an incoming connection

int listen(
  __in          SOCKET s,
  __in          int backlog
);

Parameters

s
Descriptor identifying a bound, unconnected socket.
socket描述符,該socket是一個未鏈接狀態的socket
backlog
Maximum length of the queue of pending connections. If set to SOMAXCONN, the underlying service provider responsible for socket s will set the backlog to a maximum reasonable value. There is no standard provision to obtain the actual backlog value.
掛起鏈接的最大長度,若是該值設置爲SOMAXCONN,負責socket的底部服務提供商將設置該值爲最大合理值。並無該值的明確規定。
Return Value
  If no error occurs,  listen returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling  WSAGetLastError.
沒有錯誤發生將返回0,不然返回SOCKET_ERROR 
1   if (listen(s,SOMAXCONN ) == SOCKET_ERROR)
2      {
3          int er = WSAGetLastError();
4          closesocket(s);
5      }

5:accept   服務端connect接收

 description:The accept function permits an incoming connection attempt on a socket.

1 SOCKET accept(
2   __in          SOCKET s,
3   __out         struct sockaddr* addr,
4   __in_out      int* addrlen
5 );

 

Parameters

s

A descriptor that identifies a socket that has been placed in a listening state with the listen function. The connection is actually made with the socket that is returned by accept.

listen函數用到的socket。accept函數將建立鏈接。

addr

An optional pointer to a buffer that receives the address of the connecting entity, as known to the communications layer. The exact format of the addr parameter is determined by the address family that was established when the socket from the sockaddr structure was created.

指向通訊層鏈接實體地址的指針。addr 的格式取決於bind函數內地址簇的類型。

addrlen

An optional pointer to an integer that contains the length of structure pointed to by the addr parameter.

addr的長度。

Return Value

If no error occurs, accept returns a value of type SOCKET that is a descriptor for the new socket. This returned value is a handle for the socket on which the actual connection is made.

Otherwise, a value of INVALID_SOCKET is returned, and a specific error code can be retrieved by calling WSAGetLastError.

The integer referred to by addrlen initially contains the amount of space pointed to by addr. On return it will contain the actual length in bytes of the address returned.

若是不發生錯誤,accept將返回一個新的SOCKET描述符,即新建鏈接的socket句柄。不然,將返回INVALID_SOCKET。傳進去的addrlen應該是參數addr的長度,返回的addrlen是實際長度。

1     SOCKET ac = accept(s,NULL,NULL);
2     if (ac == INVALID_SOCKET)
3     {
4         int er = WSAGetLastError();
5         closesocket(s);
6     }    
複製代碼

 accept: https://blog.csdn.net/gqingmo/article/details/52231866

6:connect   客戶端請求服務端鏈接

Parameters

s

Descriptor identifying an unconnected socket.

name

Name of the socket in the sockaddr structure to which the connection should be established.

與bind函數的name參數相似,指明待鏈接的地址

namelen

Length of name, in bytes.

Return Value

If no error occurs, connect returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError.

On a blocking socket, the return value indicates success or failure of the connection attempt.

0表示正確,不然,將返回SOCKET_ERROR。若是是阻塞式的socket鏈接,返回值表明了鏈接正常與失敗。

1         sockaddr_in server;
2         server.sin_family = AF_INET;
3         server.sin_port = htons(8828);
4         server.sin_addr.s_addr = inet_addr("127.0.0.1");
5         if (connect(cnetsocket,(sockaddr*)&server,sizeof(server)) == SOCKET_ERROR)
6         {
7             break;
8         }    

 

7:send   發送數據

函數原型: int send(SOCKET S, const char *buf , int len, int flags)

例子:  

    char buf[1024] = {"abcdefghijklmnopqrstuvwxyz"};

    int sent = 0;//已發送

    int total_size = sizeof(buff);

    sent = send(sock, buff+sent, total_size - sent, 0);

返回值:

    (1),無錯:返回發送字節數, 可能小於len;

    (2)、出錯:返回SOCKET_ERROR,可經過WSAGetLastError獲取錯誤碼

 

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

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

Return Value

If no error occurs, send returns the total number of bytes sent, which can be less than the number requested to be sent in the len parameter. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.

send的返回值標識已發送數據的長度,這個值可能比參數len小,這也意味着數據緩衝區沒有所有發出去,要進行後續處理。返回SOCKET_ERROR標識send出錯。

If no error occurs, recv returns the number of bytes received. If the connection has been gracefully closed, the return value is zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.

recv的返回值標識已接收數據的長度。若是鏈接已關閉,返回值將是0。返回SOCKET_ERROR標識recv出錯。

若是接收緩衝區沒有數據可接收,則recv將阻塞直至有數據到達。

相關文章
相關標籤/搜索