windows socket函數詳解


windows socket函數詳解

  近期一直用第三方庫寫網絡編程,反倒是遺忘了網絡編程最底層的知識。因而產生了整理Winsock函數庫的想法。以下知識點均來源於MSDN,本人只做翻譯工作。雖然很多前輩都做已了此類工作,但親力親為總記得清楚點。

 

0:函數庫頭文件

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

 

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

description:The WSAStartup function initiates use of the Winsock DLL by a process.

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

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

Parameters

  wVersionRequested

The highest version of Windows Sockets specification that the caller can use. The high-order byte specifies the minor version number; the low-order byte specifies the major version number.

The current version of the Windows Sockets specification is version 2.2. The current Winsock DLL, Ws2_32.dll, supports applications that request any of the following versions of Windows Sockets specification,1.0、1.1、2.0、2.1、2.2。

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

  lpWSAData

A pointer to the WSADATA data structure that is to receive details of the Windows Sockets implementation.

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

Return Value

If successful, the WSAStartup function returns zero. Otherwise, it returns one of the error codes listed below.

WSAVERNOTSUPPORTED、WSAVERNOTSUPPORTED、WSAEINPROGRESS、WSAEPROCLIM、WSAEFAULT。

The WSAStartup function directly returns the extended error code in the return value for this function. A call to the WSAGetLastError function is not needed and should not be used

如果調用成功,WSAStartup 函數返回0。否則,將返回五種錯誤代碼之一。但絕對不能使用WSAGetLastError獲取錯誤代碼。

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

 

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

description:The WSACleanup function terminates use of the Winsock 2 DLL (Ws2_32.dll).

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

int WSACleanup(void);

Return Value

The return value is zero if the operation was successful. Otherwise, the value SOCKET_ERROR is returned, and a specific error number can be retrieved by calling WSAGetLastError.

In a multithreaded environment, WSACleanup terminates Windows Sockets operations for all threads.

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

 

3:socket   創建socket的函數

description:The socket function creates a socket that is bound to a specific transport service provider。

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

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

 

Parameters

af   ( address family

The address family specification. Possible values for the address family are defined in the Winsock2.h header file。 The table below lists common values for address family although many other values are possible。

  指明地址簇類型,常用的地址簇如下,其余地址簇在Winsock2.h中定義。

AF_UNSPEC(未指明)、AF_INET(IPv4)、AF_NETBIOS(NETBIOS地址簇)、AF_INET6(IPv6)、AF_IRDA(Infrared Data Association (IrDA)地址簇)、AF_BTM(Bluetooth)。

type

The type specification for the new socket. Possible values for the socket type are defined in the Winsock2.h header file.The following table lists the possible values for the type parameter supported for Windows Sockets 2:

  指明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

The protocol to be used. The possible options for the protocol parameter are specific to the address family and socket type specified. Possible values for the protocol are defined are defined in the Winsock2.h and Wsrm.h header files. 

指明數據傳輸協議,該參數取決於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與地址關聯

description:The bind function associates a local address with a socket.

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

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

Parameters

s

Descriptor identifying an unbound socket.指定一個未綁定的socket。

name

Address to assign to the socket from the sockaddr structure.

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

namelen

Length of the value in the name parameter, in bytes。

參數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   }

 

附注:地址轉換與賦值的相關操作

sockaddr結構體如下

View Code

 sockaddr內部使用數組來參數,賦值不方便,一般使用格式化后的結構體SOCKADDR_IN來賦值。

SOCKADDR_IN結構體

View Code

 SOCKADDR_IN里面又包含了in_addr 結構體

View Code

 htons(host to unsigned short)和htonl(host to unsigned long)

各個機器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地址的轉換。

1 u_short htons( __in     u_short hostshort);
2 u_long htonl(__in      u_long hostlong);

 

inet_addr和inet_ntoa

inet_addr用於將ipv4格式的字符串轉換為unsigned long的數值。inet_ntoa用於將struct in_addr的地址轉換為ipv4格式的字符串。

1 unsigned long inet_addr(  __in    const char* cp);
2 char* FAR inet_ntoa(  __in     struct   in_addr in);

 

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將返回一個新的SOCKET描述符,即新建連接的socket句柄。否則,將返回INVALID_SOCKET。傳進去的addrlen應該是參數addr的長度,返回的addrlen是實際長度

 

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

 description:The connect function establishes a connection to a specified socket

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

 

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、recv   發送接收數據

 description:The send function sends data on a connected socket。The recv function receives data from a connected or bound socket.

1 int send(
2   __in          SOCKET s,
3   __in          const char* buf,
4   __in          int len,
5   __in          int flags
6 );
1 int recv(
2   __in          SOCKET s,
3   __out         char* buf,
4   __in          int len,
5   __in          int flags
6 );

 

Parameters

s

A descriptor identifying a connected socket.

buf

A pointer to a buffer containing the data to be transmitted.

數據buffer

len

The length, in bytes, of the data in buffer pointed to by the buf parameter.

待發送(接受)數據長度

flags

A set of flags that specify the way in which the call is made. This parameter is constructed by using the bitwise OR operator with any of the following values.

send(recv)函數的發送(接收)數據方式。MSDN給了以下幾種發送方式:

1:MSG_DONTROUTE(Specifies that the data should not be subject to routing. A Windows Sockets service provider can choose to ignore this flag.)

2:MSG_OOB(Sends OOB data (stream-style socket such as SOCK_STREAM only)

3:0

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出錯。

客戶端例子:

 

 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         }
 9         str += "windows socket test!";
10         while (1)
11         {
12             int len = send(cnetsocket,str.c_str(),str.length(),0);
13             cout<<"send data:"<<str.c_str()<<" ,length = "<<str.length()<<endl;
14             if (len < str.length())
15             {
16                 cout<<"data send uncompleted"<<endl;
17                 str = str.substr(len+1,str.length());
18                 len = send(cnetsocket,str.c_str(),str.length(),0);
19                 cout<<"send data uncomplete,send remaining data :"<<str.c_str()<<" ,length = "<<str.length()<<endl;
20             }
21             else if (len == SOCKET_ERROR)
22             {
23                 break;
24             }
25             Sleep(1);
26         }

 

 

 

服務端例子:

 

 1         SOCKET acp = accept(listensocket,NULL,NULL);
 2         if (acp == INVALID_SOCKET)
 3         {
 4             cout<<"accept error,error code "<<WSAGetLastError()<<endl;
 5             break;
 6         }
 7         while (1)
 8         {
 9             char buf[1024];
10             int len = recv(acp,buf,1024,0);
11             if (len == 0)
12             {
13                 cout<<"connection has been closed "<<endl;
14                 break;
15             }
16             else if (len == SOCKET_ERROR)
17             {
18                 cout<<"recv error,error code "<<WSAGetLastError()<<endl;
19                 break;
20             }
21             else
22             {
23                 char* outbuf = new char[len+1];
24                 memcpy(outbuf,buf,len);
25                 outbuf[len] = 0;
26                 cout<<"recv data,"<<outbuf<<endl;
27                 delete outbuf;
28             }
29         }    

8:closesocket   關閉socket

 description:The closesocket function closes an existing socket.

1 int closesocket(
2   __in          SOCKET s
3 );

 

Parameters

s

A descriptor identifying the socket to close.

Return Value

If no error occurs, closesocket returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.

如果無錯誤發生,函數返回0。否則,返回SOCKET_ERROR。

9:shutdown   禁止在socket收發數據

 description:The shutdown function disables sends or receives on a socket.

1 int shutdown(
2   __in          SOCKET s,
3   __in          int how
4 );

 

Parameters

s

Descriptor identifying a socket.

how

Flag that describes what types of operation will no longer be allowed.

how有幾類取值:

1:SD_RECEIVE,不允許在socket上recv數據。

2:SD_RECEIVE,不允許在socket上send數據。

3:SD_RECEIVE,不允許在socket上recv和send數據。

Return Value

If no error occurs, shutdown returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.

  shutdown並不關閉socket,只是禁止掉socket的recv或send行為。為保證數據收發完整性,在關閉socket之前應調用shutdown。

10 :getsockname  獲取本地IP和PORT

Description:The getsockname function retrieves the local name for a socket.

1 int getsockname(
2   __in          SOCKET s,
3   __out         struct sockaddr* name,
4   __in_out      int* namelen
5 );

Parameters

s

Descriptor identifying a socket.

name

Pointer to a SOCKADDR structure that receives the address (name) of the socket.

namelen

Size of the name buffer, in bytes.

Return Value

If no error occurs, getsockname returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.

11 :getpeername  獲取對端IP和PORT

1 int getpeername(
2   __in          SOCKET s,
3   __out         struct sockaddr* name,
4   __in_out      int* namelen
5 );

 

  Getpeername和getsockname參數一樣。

 


免責聲明!

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



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