socket通信流程

image.png

tcp

server side:
socket()->bind()->listen()->accept()->send()/recv()->closesocket()

client:
socket()->connet()->send()/recv()->closesocket()

udp

server:
socket()->bind()->sendto()/recvfrom()->closesocket()

client:
socket()->sendto()/recvfrom()/closesocket()

winsock

库文件

tcp server

  1. #ifndef WIN32_LEAN_AND_MEAN
  2. #define WIN32_LEAN_AND_MEAN //此宏用于预防 winsock.h 和winsock2.h 冲突
  3. #endif
  4. #include <winsock2.h>
  5. #include <ws2tcpip.h>
  6. #include <stdio.h>
  7. #pragma comment(lib, "Ws2_32.lib")

tcpclient

  1. #define WIN32_LEAN_AND_MEAN
  2. #include <windows.h>
  3. #include <winsock2.h>
  4. #include <ws2tcpip.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. // Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
  8. #pragma comment (lib, "Ws2_32.lib")
  9. #pragma comment (lib, "Mswsock.lib")
  10. #pragma comment (lib, "AdvApi32.lib")

初始化winsock

使用winsock 编程前需要对winsock初始化,使用完毕后需要释放。

winsock初始化函数

  1. int WSAStartup(WORD wVersionRequire,LPWSADATA lpWSAData);
  2. /*
  3. wVersionRequire 是winsock 初始换版本号 ,winsock有多个版本 常用 2.2
  4. lpWSAData 是一个指向WSAdata 的结构体指针
  5. 函数返回值 0 成功 ,其他值 失败
  6. */

winsock 释放函数

  1. int WSACleanup(void);

示例代码

  1. int iResult;
  2. //创建WSADATA 对象
  3. WSADATA wsaData;
  4. //...
  5. // 初始化winsock
  6. iResult = WSAStartup(MAKEWORD(2,2),&wsaData);
  7. if(iResult != 0){
  8. printf("WSAStart failed : %d",iResult);
  9. return 1;
  10. }

TCP

server

创建addrinfo
示例代码

  1. #define DEFAULT_PORT "27015"
  2. struct addrinfo *result = NULL, *ptr = NULL, hints;
  3. ZeroMemory(&hints, sizeof (hints));
  4. hints.ai_family = AF_INET;
  5. hints.ai_socktype = SOCK_STREAM;
  6. hints.ai_protocol = IPPROTO_TCP;
  7. hints.ai_flags = AI_PASSIVE;
  8. // Resolve the local address and port to be used by the server
  9. iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
  10. if (iResult != 0) {
  11. printf("getaddrinfo failed: %d\n", iResult);
  12. WSACleanup();
  13. return 1;
  14. }

socket创建与关闭

scoket(),closesocket()

  1. SOCKET socket(int af,int type,int protocol);
  2. // af代表地址簇,
  3. //type 为套接字类型 stream , dgram,raw 代表流套接字,数据包套接字,原始协议接口
  4. //protocol 协议类型 tcp,udp,icmp ,etc
  5. int closesocket(SOCKET s);

示例代码

  1. SOCKET ListenSocket = INVALID_SOCKET;
  2. // Create a SOCKET for the server to listen for client connections
  3. ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
  4. //检查是否有错
  5. if (ListenSocket == INVALID_SOCKET) {
  6. printf("Error at socket(): %ld\n", WSAGetLastError());
  7. freeaddrinfo(result);
  8. WSACleanup();
  9. return 1;
  10. }

绑定socket

  1. // Setup the TCP listening socket
  2. iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
  3. if (iResult == SOCKET_ERROR) {
  4. printf("bind failed with error: %d\n", WSAGetLastError());
  5. freeaddrinfo(result);
  6. closesocket(ListenSocket);
  7. WSACleanup();
  8. return 1;
  9. }

侦听套接字

  1. if ( listen( ListenSocket, SOMAXCONN ) == SOCKET_ERROR ) { //SOMAXCONN 最大连接数
  2. printf( "Listen failed with error: %ld\n", WSAGetLastError() );
  3. freeaddrinfo(result);
  4. closesocket(ListenSocket);
  5. WSACleanup();
  6. return 1;
  7. }

接受连接

创建ClientSocket 临时socket对象,接受客户端的连接

有几种不同的编程技术使用 Winsock,可用于侦听多个客户端连接。 一种编程方法是创建一个连续循环,该循环使用 侦听 函数检查连接请求 (请参阅 在套接字) 上进行侦听 。 如果出现连接请求,应用程序将调用 acceptAcceptExWSAAccept 函数,并将工作传递到另一个线程来处理请求。

  1. SOCKET ClientSocket;
  2. ClientSocket = INVALID_SOCKET;
  3. CleintSocket = accept(ListenSocket,NULL,NULL);
  4. if(ClientSocket == INVALID_SOCKET){
  5. printf("accept failed %d\n",WSAGetLastError());
  6. WSACleanup();
  7. return 1;
  8. }

当客户端连接被接受后,服务器应用程序通常会将接受的客户端套接字传递 (上述示例代码中的 ClientSocket 变量) 到工作线程或 i/o 完成端口,并继续接受其他连接。
还有许多其他编程技术可用于侦听和接受多个连接。 其中包括使用 select 函数或 WSAPoll 函数。

收发数据

  1. #define DEFAULT_BUFLEN 512
  2. char recvbuf[DEFAULT_BUFLEN];
  3. int iResult, iSendResult;
  4. int recvbuflen = DEFAULT_BUFLEN;
  5. // Receive until the peer shuts down the connection
  6. do {
  7. iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
  8. if (iResult > 0) {
  9. printf("Bytes received: %d\n", iResult);
  10. // Echo the buffer back to the sender
  11. iSendResult = send(ClientSocket, recvbuf, iResult, 0);
  12. if (iSendResult == SOCKET_ERROR) {
  13. printf("send failed: %d\n", WSAGetLastError());
  14. closesocket(ClientSocket);
  15. WSACleanup();
  16. return 1;
  17. }
  18. printf("Bytes sent: %d\n", iSendResult);
  19. } else if (iResult == 0)
  20. printf("Connection closing...\n");
  21. else {
  22. printf("recv failed: %d\n", WSAGetLastError());
  23. closesocket(ClientSocket);
  24. WSACleanup();
  25. return 1;
  26. }
  27. } while (iResult > 0);

send 和 recv函数都分别返回发送或接收的字节数的整数值或错误。 每个函数也采用相同的参数:活动套接字、 字符 缓冲区、要发送或接收的字节数以及使用的任何标志。

关闭套接字

当服务器将数据发送到客户端时,可以调用 shutdown 函数以指定 SD _ SEND 来关闭套接字的发送端。 这允许客户端释放此套接字的某些资源。 服务器应用程序仍然可以在套接字上接收数据。

  1. // shutdown the send half of the connection since no more data will be sent
  2. iResult = shutdown(ClientSocket, SD_SEND);
  3. if (iResult == SOCKET_ERROR) {
  4. printf("shutdown failed: %d\n", WSAGetLastError());
  5. closesocket(ClientSocket);
  6. WSACleanup();
  7. return 1;
  8. }

完整代码

  1. #undef UNICODE
  2. #define WIN32_LEAN_AND_MEAN
  3. #include <windows.h>
  4. #include <winsock2.h>
  5. #include <ws2tcpip.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. // Need to link with Ws2_32.lib
  9. #pragma comment (lib, "Ws2_32.lib")
  10. // #pragma comment (lib, "Mswsock.lib")
  11. #define DEFAULT_BUFLEN 512
  12. #define DEFAULT_PORT "27015"
  13. int __cdecl main(void)
  14. {
  15. WSADATA wsaData;
  16. int iResult;
  17. SOCKET ListenSocket = INVALID_SOCKET;
  18. SOCKET ClientSocket = INVALID_SOCKET;
  19. struct addrinfo *result = NULL;
  20. struct addrinfo hints;
  21. int iSendResult;
  22. char recvbuf[DEFAULT_BUFLEN];
  23. int recvbuflen = DEFAULT_BUFLEN;
  24. // Initialize Winsock
  25. iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
  26. if (iResult != 0) {
  27. printf("WSAStartup failed with error: %d\n", iResult);
  28. return 1;
  29. }
  30. ZeroMemory(&hints, sizeof(hints));
  31. hints.ai_family = AF_INET;
  32. hints.ai_socktype = SOCK_STREAM;
  33. hints.ai_protocol = IPPROTO_TCP;
  34. hints.ai_flags = AI_PASSIVE;
  35. // Resolve the server address and port
  36. iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
  37. if ( iResult != 0 ) {
  38. printf("getaddrinfo failed with error: %d\n", iResult);
  39. WSACleanup();
  40. return 1;
  41. }
  42. // Create a SOCKET for connecting to server
  43. ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
  44. if (ListenSocket == INVALID_SOCKET) {
  45. printf("socket failed with error: %ld\n", WSAGetLastError());
  46. freeaddrinfo(result);
  47. WSACleanup();
  48. return 1;
  49. }
  50. // Setup the TCP listening socket
  51. iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
  52. if (iResult == SOCKET_ERROR) {
  53. printf("bind failed with error: %d\n", WSAGetLastError());
  54. freeaddrinfo(result);
  55. closesocket(ListenSocket);
  56. WSACleanup();
  57. return 1;
  58. }
  59. freeaddrinfo(result);
  60. iResult = listen(ListenSocket, SOMAXCONN);
  61. if (iResult == SOCKET_ERROR) {
  62. printf("listen failed with error: %d\n", WSAGetLastError());
  63. closesocket(ListenSocket);
  64. WSACleanup();
  65. return 1;
  66. }
  67. // Accept a client socket
  68. ClientSocket = accept(ListenSocket, NULL, NULL);
  69. if (ClientSocket == INVALID_SOCKET) {
  70. printf("accept failed with error: %d\n", WSAGetLastError());
  71. closesocket(ListenSocket);
  72. WSACleanup();
  73. return 1;
  74. }
  75. // No longer need server socket
  76. closesocket(ListenSocket);
  77. // Receive until the peer shuts down the connection
  78. do {
  79. iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
  80. if (iResult > 0) {
  81. printf("Bytes received: %d\n", iResult);
  82. // Echo the buffer back to the sender
  83. iSendResult = send( ClientSocket, recvbuf, iResult, 0 );
  84. if (iSendResult == SOCKET_ERROR) {
  85. printf("send failed with error: %d\n", WSAGetLastError());
  86. closesocket(ClientSocket);
  87. WSACleanup();
  88. return 1;
  89. }
  90. printf("Bytes sent: %d\n", iSendResult);
  91. }
  92. else if (iResult == 0)
  93. printf("Connection closing...\n");
  94. else {
  95. printf("recv failed with error: %d\n", WSAGetLastError());
  96. closesocket(ClientSocket);
  97. WSACleanup();
  98. return 1;
  99. }
  100. } while (iResult > 0);
  101. // shutdown the connection since we're done
  102. iResult = shutdown(ClientSocket, SD_SEND);
  103. if (iResult == SOCKET_ERROR) {
  104. printf("shutdown failed with error: %d\n", WSAGetLastError());
  105. closesocket(ClientSocket);
  106. WSACleanup();
  107. return 1;
  108. }
  109. // cleanup
  110. closesocket(ClientSocket);
  111. WSACleanup();
  112. return 0;
  113. }

client

创建socket

声明一个包含 sockaddr结构的 addrinfo对象并初始化这些值

  1. struct addrinfo *result = NULL,*ptr = NULL, hints;
  2. ZeroMemory(&hints,sizeof(hints));
  3. hints.ai_family = AF_UNSPEC;
  4. hints.ai_socktype = SOCK_STREAM;
  5. hints.ai_protocol = IPPROTO_TCP;

调用 getaddrinfo 函数,请求在命令行上传递的服务器名称的 IP 地址。 在此示例中,客户端将连接到的服务器上的 TCP 端口被默认 _ 端口定义为27015。 Getaddrinfo 函数以检查是否有错误的整数的形式返回其值

  1. #define DEFAULT_PORT "27015"
  2. // Resolve the server address and port
  3. iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
  4. if (iResult != 0) {
  5. printf("getaddrinfo failed: %d\n", iResult);
  6. WSACleanup();
  7. return 1;
  8. }

创建ConnectSocket

  1. // Attempt to connect to the first address returned by
  2. // the call to getaddrinfo
  3. ptr=result;
  4. // Create a SOCKET for connecting to server
  5. ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
  6. ptr->ai_protocol);

检查错误

  1. if (ConnectSocket == INVALID_SOCKET) {
  2. printf("Error at socket(): %ld\n", WSAGetLastError());
  3. freeaddrinfo(result);
  4. WSACleanup();
  5. return 1;
  6. }

连接socket

调用 connect 函数,将创建的套接字和 sockaddr 结构作为参数传递。 检查常规错误。

  1. // Connect to server.
  2. iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
  3. if (iResult == SOCKET_ERROR) {
  4. closesocket(ConnectSocket);
  5. ConnectSocket = INVALID_SOCKET;
  6. }
  7. // Should really try the next address returned by getaddrinfo
  8. // if the connect call failed
  9. // But for this simple example we just free the resources
  10. // returned by getaddrinfo and print an error message
  11. freeaddrinfo(result);
  12. if (ConnectSocket == INVALID_SOCKET) {
  13. printf("Unable to connect to server!\n");
  14. WSACleanup();
  15. return 1;
  16. }

getaddrinfo函数用于确定 sockaddr 结构中的值。 本示例使用 getaddrinfo 函数返回的第一个 IP 地址来指定 传递给连接的 sockaddr 结构。 如果 一个 IP 地址的连接调用失败,请尝试从 getaddrinfo 函数返回的链接列表中的下一个 addrinfo结构

收发数据

  1. #define DEFAULT_BUFLEN 512
  2. int recvbuflen = DEFAULT_BUFLEN;
  3. const char *sendbuf = "this is a test";
  4. char recvbuf[DEFAULT_BUFLEN];
  5. int iResult;
  6. // Send an initial buffer
  7. iResult = send(ConnectSocket, sendbuf, (int) strlen(sendbuf), 0);
  8. if (iResult == SOCKET_ERROR) {
  9. printf("send failed: %d\n", WSAGetLastError());
  10. closesocket(ConnectSocket);
  11. WSACleanup();
  12. return 1;
  13. }
  14. printf("Bytes Sent: %ld\n", iResult);
  15. // shutdown the connection for sending since no more data will be sent
  16. // the client can still use the ConnectSocket for receiving data
  17. iResult = shutdown(ConnectSocket, SD_SEND);
  18. if (iResult == SOCKET_ERROR) {
  19. printf("shutdown failed: %d\n", WSAGetLastError());
  20. closesocket(ConnectSocket);
  21. WSACleanup();
  22. return 1;
  23. }
  24. // Receive data until the server closes the connection
  25. do {
  26. iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
  27. if (iResult > 0)
  28. printf("Bytes received: %d\n", iResult);
  29. else if (iResult == 0)
  30. printf("Connection closed\n");
  31. else
  32. printf("recv failed: %d\n", WSAGetLastError());
  33. } while (iResult > 0);

send 和 recv函数都分别返回发送或接收的字节数的整数值或错误。 每个函数也采用相同的参数:活动套接字、 字符 缓冲区、要发送或接收的字节数以及使用的任何标志。

断开连接

客户端完成向服务器发送数据后,可以调用 shutdown 函数,指定 SD SEND 以关闭套接字 _ 的发送端。 这允许服务器释放此套接字的一些资源。 客户端应用程序仍可接收套接字上的数据

  1. // shutdown the send half of the connection since no more data will be sent
  2. iResult = shutdown(ConnectSocket, SD_SEND);
  3. if (iResult == SOCKET_ERROR) {
  4. printf("shutdown failed: %d\n", WSAGetLastError());
  5. closesocket(ConnectSocket);
  6. WSACleanup();
  7. return 1;
  8. }

客户端应用程序收到数据后,将调用 closesocket 函数来关闭套接字。
使用套接字 DLL 完成客户端Windows,将调用 WSACleanup函数以释放资源

  1. // cleanup
  2. closesocket(ConnectSocket);
  3. WSACleanup();
  4. return 0;

完整代码

  1. #define WIN32_LEAN_AND_MEAN
  2. #include <windows.h>
  3. #include <winsock2.h>
  4. #include <ws2tcpip.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. // Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
  8. #pragma comment (lib, "Ws2_32.lib")
  9. #pragma comment (lib, "Mswsock.lib")
  10. #pragma comment (lib, "AdvApi32.lib")
  11. #define DEFAULT_BUFLEN 512
  12. #define DEFAULT_PORT "27015"
  13. int __cdecl main(int argc, char **argv)
  14. {
  15. WSADATA wsaData;
  16. SOCKET ConnectSocket = INVALID_SOCKET;
  17. struct addrinfo *result = NULL,
  18. *ptr = NULL,
  19. hints;
  20. const char *sendbuf = "this is a test";
  21. char recvbuf[DEFAULT_BUFLEN];
  22. int iResult;
  23. int recvbuflen = DEFAULT_BUFLEN;
  24. // Validate the parameters
  25. if (argc != 2) {
  26. printf("usage: %s server-name\n", argv[0]);
  27. return 1;
  28. }
  29. // Initialize Winsock
  30. iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
  31. if (iResult != 0) {
  32. printf("WSAStartup failed with error: %d\n", iResult);
  33. return 1;
  34. }
  35. ZeroMemory( &hints, sizeof(hints) );
  36. hints.ai_family = AF_UNSPEC;
  37. hints.ai_socktype = SOCK_STREAM;
  38. hints.ai_protocol = IPPROTO_TCP;
  39. // Resolve the server address and port
  40. iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
  41. if ( iResult != 0 ) {
  42. printf("getaddrinfo failed with error: %d\n", iResult);
  43. WSACleanup();
  44. return 1;
  45. }
  46. // Attempt to connect to an address until one succeeds
  47. for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
  48. // Create a SOCKET for connecting to server
  49. ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
  50. ptr->ai_protocol);
  51. if (ConnectSocket == INVALID_SOCKET) {
  52. printf("socket failed with error: %ld\n", WSAGetLastError());
  53. WSACleanup();
  54. return 1;
  55. }
  56. // Connect to server.
  57. iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
  58. if (iResult == SOCKET_ERROR) {
  59. closesocket(ConnectSocket);
  60. ConnectSocket = INVALID_SOCKET;
  61. continue;
  62. }
  63. break;
  64. }
  65. freeaddrinfo(result);
  66. if (ConnectSocket == INVALID_SOCKET) {
  67. printf("Unable to connect to server!\n");
  68. WSACleanup();
  69. return 1;
  70. }
  71. // Send an initial buffer
  72. iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
  73. if (iResult == SOCKET_ERROR) {
  74. printf("send failed with error: %d\n", WSAGetLastError());
  75. closesocket(ConnectSocket);
  76. WSACleanup();
  77. return 1;
  78. }
  79. printf("Bytes Sent: %ld\n", iResult);
  80. // shutdown the connection since no more data will be sent
  81. iResult = shutdown(ConnectSocket, SD_SEND);
  82. if (iResult == SOCKET_ERROR) {
  83. printf("shutdown failed with error: %d\n", WSAGetLastError());
  84. closesocket(ConnectSocket);
  85. WSACleanup();
  86. return 1;
  87. }
  88. // Receive until the peer closes the connection
  89. do {
  90. iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
  91. if ( iResult > 0 )
  92. printf("Bytes received: %d\n", iResult);
  93. else if ( iResult == 0 )
  94. printf("Connection closed\n");
  95. else
  96. printf("recv failed with error: %d\n", WSAGetLastError());
  97. } while( iResult > 0 );
  98. // cleanup
  99. closesocket(ConnectSocket);
  100. WSACleanup();
  101. return 0;
  102. }

udp

server

  1. #include <winsock2.h>
  2. #include<iostream>
  3. #pragma comment(lib,"ws2_32.lib")
  4. using namespace std;
  5. int main()
  6. {
  7. WORD wVersion;
  8. WSADATA wsaData;
  9. int er;
  10. //1.初始化版本信息
  11. wVersion = MAKEWORD(1, 1);
  12. //加载套接字库
  13. er = WSAStartup(wVersion, &wsaData);
  14. if (er != 0)
  15. {
  16. return -1;
  17. }
  18. //检测套接字版本信息
  19. if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
  20. {
  21. WSACleanup();
  22. return -2;
  23. }
  24. //2.创建服务器端套接字
  25. SOCKET sockSer = socket(AF_INET, SOCK_DGRAM, 0);
  26. SOCKADDR_IN addr_in;
  27. addr_in.sin_family = AF_INET;//地址族
  28. addr_in.sin_port = htons(7000);//端口
  29. addr_in.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//IP
  30. bind(sockSer, (sockaddr*)&addr_in, sizeof(addr_in));
  31. SOCKADDR_IN client_addr;
  32. int len = sizeof(sockaddr_in);
  33. char recvBuf[1024];
  34. recvfrom(sockSer, recvBuf, sizeof(recvBuf), 0, (sockaddr*)&client_addr, &len);
  35. cout << "接受到的数据:" << recvBuf << endl;
  36. //向客户端发送数据
  37. sendto(sockSer, recvBuf, sizeof(recvBuf), 0, (sockaddr*)&client_addr, len);
  38. closesocket(sockSer);
  39. WSACleanup();
  40. system("pause");
  41. return 0;
  42. }

client

  1. #include "stdafx.h"
  2. #include <winsock2.h>
  3. #include<iostream>
  4. #pragma comment(lib,"ws2_32.lib")
  5. using namespace std;
  6. int main()
  7. {
  8. WORD wVersion;
  9. WSADATA wsaData;
  10. int er;
  11. //1.初始化版本信息
  12. wVersion = MAKEWORD(1, 1);
  13. //加载套接字库
  14. er = WSAStartup(wVersion, &wsaData);
  15. if (er != 0)
  16. {
  17. return -1;
  18. }
  19. //检测套接字版本信息
  20. if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
  21. {
  22. WSACleanup();
  23. return -2;
  24. }
  25. //2.创建服务器端套接字
  26. SOCKET sockSer = socket(AF_INET, SOCK_DGRAM, 0);
  27. SOCKADDR_IN addr_in;
  28. addr_in.sin_family = AF_INET;//地址族
  29. addr_in.sin_port = htons(7000);//端口
  30. addr_in.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
  31. bind(sockSer, (sockaddr*)&addr_in, sizeof(addr_in));
  32. SOCKADDR_IN addr;
  33. int len = sizeof(addr);
  34. //向服务器发送数据
  35. char sendBuf[1024];
  36. sendto(sockSer, sendBuf, sizeof(sendBuf), 0, (sockaddr*)&addr, len);
  37. //接受数据
  38. char recvBuf[1024];
  39. recvfrom(sockSer, recvBuf, sizeof(recvBuf), 0, (sockaddr*)&addr, &len);
  40. cout << "接受到服务器端的数据:" << recvBuf << endl;
  41. closesocket();
  42. WSACleanup();
  43. system("pause");
  44. return 0;
  45. }