windows socket函數詳解


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

流程圖:

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鏈接庫的調用。

int WSACleanup(void);

返回值0表示正常退出,返回值SOCKET_ERROR表示異常。返回值是SOCKET_ERROR,可以調用 WSAGetLastError.查看錯誤代碼。需要注意的是,在多線程環境下,WSACleanup 函數將終止所有線程的socket操作。

3:socket   創建socket的函數

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

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_INET6、type是SOCK_STREAM )

IPPROTO_UDP(UDP協議,使用條件,af是AF_INET or AF_INET6、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將阻塞直至有數據到達。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM