目录

  • 1. 辅助函数(common.h)
  • 2. CMakeLists.txt
  • 3. TCP
    • 3.1 服务器(tcp_server.cpp)
    • 3.2 客户端(tcp_client.cpp)
  • 4. UDP 单播
    • 4.1 服务器/(首次)接收端(udp_server.cpp)
    • 4.2 客户端/(首次)发送端(udp_client.cpp)
  • 5. 广播
    • 5.1 服务器/(首次)接收端(udp_server_boardcast.cpp)
    • 5.2 客户端/(首次)发送端(udp_client+bpardcast.cpp)
  • 6. 多/组播
    • 6.1 服务器/(首次)接收端(udp_server_multicast.cpp)
    • 6.1 客户端/(首次)发送端(udp_client_multicast.cpp)

1. 辅助函数(common.h)

#ifndef CPP_NETWORK_COMMUNICATION_COMMON_H
#define CPP_NETWORK_COMMUNICATION_COMMON_H#include <WinSock2.h>
#include <Ws2tcpip.h>
#include <cstdio>
#include <iostream>#pragma comment(lib, "ws2_32.lib")#define INTERFACE_ADDRESS "127.0.0.1"
#define MULTICAST_ADDRESS "239.127.3.5"
#define MULTICAST_PORT 7667
#define BUFFER_SIZE (1024)
#define TCP_SERVER_PORT (8000)
#define TCP_Client_PORT (8001)
#define UDP_SERVER_PORT (7667)
#define UDP_CLIENT_PORT (7668)
#define COUNT (5)#ifdef DEBUG
#define DEBUG_FUNCTION_NAME()                                                         \{                                                                                 \printf("================================================================\n"); \printf("%s\n", __func__);                                                     \}#define DEBUG_LOG(format, ...)                                                          \{                                                                                   \printf("LOG:[%s:%d->%s] " format, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \}
#else
#define DEBUG_FUNCTION_NAME()
#define DEBUG_LOG(format, ...)
#endifvoid show_error_code()
{int error_code = WSAGetLastError();switch (error_code){case 0:std::cout << "ERROR CODE (" << error_code << " ): SUCCESS" << std::endl;break;case WSA_INVALID_HANDLE:std::cout << "ERROR CODE (" << error_code << " ): WSA_INVALID_HANDLE" << std::endl;break;case WSA_NOT_ENOUGH_MEMORY:std::cout << "ERROR CODE (" << error_code << " ): WSA_NOT_ENOUGH_MEMORY" << std::endl;break;case WSA_INVALID_PARAMETER:std::cout << "ERROR CODE (" << error_code << " ): WSA_INVALID_PARAMETER" << std::endl;break;case WSA_OPERATION_ABORTED:std::cout << "ERROR CODE (" << error_code << " ): WSA_OPERATION_ABORTED" << std::endl;break;case WSA_IO_INCOMPLETE:std::cout << "ERROR CODE (" << error_code << " ): WSA_IO_INCOMPLETE" << std::endl;break;case WSA_IO_PENDING:std::cout << "ERROR CODE (" << error_code << " ): WSA_IO_PENDING" << std::endl;break;case WSAEINTR:std::cout << "ERROR CODE (" << error_code << " ): WSAEINTR" << std::endl;break;case WSAEBADF:std::cout << "ERROR CODE (" << error_code << " ): WSAEBADF" << std::endl;break;case WSAEACCES:std::cout << "ERROR CODE (" << error_code << " ): WSAEACCES" << std::endl;break;case WSAEFAULT:std::cout << "ERROR CODE (" << error_code << " ): WSAEFAULT" << std::endl;break;case WSAEINVAL:std::cout << "ERROR CODE (" << error_code << " ): WSAEINVAL" << std::endl;break;case WSAEMFILE:std::cout << "ERROR CODE (" << error_code << " ): WSAEMFILE" << std::endl;break;case WSAEWOULDBLOCK:std::cout << "ERROR CODE (" << error_code << " ): WSAEWOULDBLOCK" << std::endl;break;case WSAEINPROGRESS:std::cout << "ERROR CODE (" << error_code << " ): WSAEINPROGRESS" << std::endl;break;case WSAEALREADY:std::cout << "ERROR CODE (" << error_code << " ): WSAEALREADY" << std::endl;break;case WSAENOTSOCK:std::cout << "ERROR CODE (" << error_code << " ): WSAENOTSOCK" << std::endl;break;case WSAEDESTADDRREQ:std::cout << "ERROR CODE (" << error_code << " ): WSAEDESTADDRREQ" << std::endl;break;case WSAEMSGSIZE:std::cout << "ERROR CODE (" << error_code << " ): WSAEMSGSIZE" << std::endl;break;case WSAEPROTOTYPE:std::cout << "ERROR CODE (" << error_code << " ): WSAEPROTOTYPE" << std::endl;break;case WSAENOPROTOOPT:std::cout << "ERROR CODE (" << error_code << " ): WSAENOPROTOOPT" << std::endl;break;case WSAEPROTONOSUPPORT:std::cout << "ERROR CODE (" << error_code << " ): WSAEPROTONOSUPPORT" << std::endl;break;case WSAESOCKTNOSUPPORT:std::cout << "ERROR CODE (" << error_code << " ): WSAESOCKTNOSUPPORT" << std::endl;break;case WSAEOPNOTSUPP:std::cout << "ERROR CODE (" << error_code << " ): WSAEOPNOTSUPP" << std::endl;break;case WSAEADDRINUSE:std::cout << "ERROR CODE (" << error_code << " ): WSAEADDRINUSE" << std::endl;break;case WSAEADDRNOTAVAIL:std::cout << "ERROR CODE (" << error_code << " ): WSAEADDRNOTAVAIL" << std::endl;break;case WSAENETDOWN:std::cout << "ERROR CODE (" << error_code << " ): WSAENETDOWN" << std::endl;break;case WSAENETUNREACH:std::cout << "ERROR CODE (" << error_code << " ): WSAENETUNREACH" << std::endl;break;case WSAENETRESET:std::cout << "ERROR CODE (" << error_code << " ): WSAENETRESET" << std::endl;break;case WSAECONNABORTED:std::cout << "ERROR CODE (" << error_code << " ): WSAECONNABORTED" << std::endl;break;case WSAECONNRESET:std::cout << "ERROR CODE (" << error_code << " ): WSAECONNRESET" << std::endl;break;case WSAENOBUFS:std::cout << "ERROR CODE (" << error_code << " ): WSAENOBUFS" << std::endl;break;case WSAEISCONN:std::cout << "ERROR CODE (" << error_code << " ): WSAEISCONN" << std::endl;break;case WSAENOTCONN:std::cout << "ERROR CODE (" << error_code << " ): WSAENOTCONN" << std::endl;break;case WSAESHUTDOWN:std::cout << "ERROR CODE (" << error_code << " ): WSAESHUTDOWN" << std::endl;break;case WSAETOOMANYREFS:std::cout << "ERROR CODE (" << error_code << " ): WSAETOOMANYREFS" << std::endl;break;case WSAETIMEDOUT:std::cout << "ERROR CODE (" << error_code << " ): WSAETIMEDOUT" << std::endl;break;case WSAECONNREFUSED:std::cout << "ERROR CODE (" << error_code << " ): WSAECONNREFUSED" << std::endl;break;case WSAELOOP:std::cout << "ERROR CODE (" << error_code << " ): WSAELOOP" << std::endl;break;case WSAENAMETOOLONG:std::cout << "ERROR CODE (" << error_code << " ): WSAENAMETOOLONG" << std::endl;break;case WSAEHOSTDOWN:std::cout << "ERROR CODE (" << error_code << " ): WSAEHOSTDOWN" << std::endl;break;case WSAEHOSTUNREACH:std::cout << "ERROR CODE (" << error_code << " ): WSAEHOSTUNREACH" << std::endl;break;case WSAENOTEMPTY:std::cout << "ERROR CODE (" << error_code << " ): WSAENOTEMPTY" << std::endl;break;case WSAEPROCLIM:std::cout << "ERROR CODE (" << error_code << " ): WSAEPROCLIM" << std::endl;break;case WSAEUSERS:std::cout << "ERROR CODE (" << error_code << " ): WSAEUSERS" << std::endl;break;case WSAEDQUOT:std::cout << "ERROR CODE (" << error_code << " ): WSAEDQUOT" << std::endl;break;case WSAESTALE:std::cout << "ERROR CODE (" << error_code << " ): WSAESTALE" << std::endl;break;case WSAEREMOTE:std::cout << "ERROR CODE (" << error_code << " ): WSAEREMOTE" << std::endl;break;case WSASYSNOTREADY:std::cout << "ERROR CODE (" << error_code << " ): WSASYSNOTREADY" << std::endl;break;case WSAVERNOTSUPPORTED:std::cout << "ERROR CODE (" << error_code << " ): WSAVERNOTSUPPORTED" << std::endl;break;case WSANOTINITIALISED:std::cout << "ERROR CODE (" << error_code << " ): WSANOTINITIALISED" << std::endl;break;case WSAEDISCON:std::cout << "ERROR CODE (" << error_code << " ): WSAEDISCON" << std::endl;break;case WSAENOMORE:std::cout << "ERROR CODE (" << error_code << " ): WSAENOMORE" << std::endl;break;case WSAECANCELLED:std::cout << "ERROR CODE (" << error_code << " ): WSAECANCELLED" << std::endl;break;case WSAEINVALIDPROCTABLE:std::cout << "ERROR CODE (" << error_code << " ): WSAEINVALIDPROCTABLE" << std::endl;break;case WSAEINVALIDPROVIDER:std::cout << "ERROR CODE (" << error_code << " ): WSAEINVALIDPROVIDER" << std::endl;break;case WSAEPROVIDERFAILEDINIT:std::cout << "ERROR CODE (" << error_code << " ): WSAEPROVIDERFAILEDINIT" << std::endl;break;case WSASYSCALLFAILURE:std::cout << "ERROR CODE (" << error_code << " ): WSASYSCALLFAILURE" << std::endl;break;case WSASERVICE_NOT_FOUND:std::cout << "ERROR CODE (" << error_code << " ): WSASERVICE_NOT_FOUND" << std::endl;break;case WSATYPE_NOT_FOUND:std::cout << "ERROR CODE (" << error_code << " ): WSATYPE_NOT_FOUND" << std::endl;break;case WSA_E_NO_MORE:std::cout << "ERROR CODE (" << error_code << " ): WSA_E_NO_MORE" << std::endl;break;case WSA_E_CANCELLED:std::cout << "ERROR CODE (" << error_code << " ): WSA_E_CANCELLED" << std::endl;break;case WSAEREFUSED:std::cout << "ERROR CODE (" << error_code << " ): WSAEREFUSED" << std::endl;break;case WSAHOST_NOT_FOUND:std::cout << "ERROR CODE (" << error_code << " ): WSAHOST_NOT_FOUND" << std::endl;break;case WSATRY_AGAIN:std::cout << "ERROR CODE (" << error_code << " ): WSATRY_AGAIN" << std::endl;break;case WSANO_RECOVERY:std::cout << "ERROR CODE (" << error_code << " ): WSANO_RECOVERY" << std::endl;break;case WSANO_DATA:std::cout << "ERROR CODE (" << error_code << " ): WSANO_DATA" << std::endl;break;case WSA_QOS_RECEIVERS:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_RECEIVERS" << std::endl;break;case WSA_QOS_SENDERS:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_SENDERS" << std::endl;break;case WSA_QOS_NO_SENDERS:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_NO_SENDERS" << std::endl;break;case WSA_QOS_NO_RECEIVERS:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_NO_RECEIVERS" << std::endl;break;case WSA_QOS_REQUEST_CONFIRMED:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_REQUEST_CONFIRMED" << std::endl;break;case WSA_QOS_ADMISSION_FAILURE:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_ADMISSION_FAILURE" << std::endl;break;case WSA_QOS_POLICY_FAILURE:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_POLICY_FAILURE" << std::endl;break;case WSA_QOS_BAD_STYLE:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_BAD_STYLE" << std::endl;break;case WSA_QOS_BAD_OBJECT:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_BAD_OBJECT" << std::endl;break;case WSA_QOS_TRAFFIC_CTRL_ERROR:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_TRAFFIC_CTRL_ERROR" << std::endl;break;case WSA_QOS_GENERIC_ERROR:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_GENERIC_ERROR" << std::endl;break;case WSA_QOS_ESERVICETYPE:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_ESERVICETYPE" << std::endl;break;case WSA_QOS_EFLOWSPEC:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EFLOWSPEC" << std::endl;break;case WSA_QOS_EPROVSPECBUF:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EPROVSPECBUF" << std::endl;break;case WSA_QOS_EFILTERSTYLE:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EFILTERSTYLE" << std::endl;break;case WSA_QOS_EFILTERTYPE:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EFILTERTYPE" << std::endl;break;case WSA_QOS_EFILTERCOUNT:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EFILTERCOUNT" << std::endl;break;case WSA_QOS_EOBJLENGTH:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EOBJLENGTH" << std::endl;break;case WSA_QOS_EFLOWCOUNT:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EFLOWCOUNT" << std::endl;break;case WSA_QOS_EUNKOWNPSOBJ:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EUNKOWNPSOBJ" << std::endl;break;case WSA_QOS_EPOLICYOBJ:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EPOLICYOBJ" << std::endl;break;case WSA_QOS_EFLOWDESC:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EFLOWDESC" << std::endl;break;case WSA_QOS_EPSFLOWSPEC:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EPSFLOWSPEC" << std::endl;break;case WSA_QOS_EPSFILTERSPEC:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_EPSFILTERSPEC" << std::endl;break;case WSA_QOS_ESDMODEOBJ:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_ESDMODEOBJ" << std::endl;break;case WSA_QOS_ESHAPERATEOBJ:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_ESHAPERATEOBJ" << std::endl;break;case WSA_QOS_RESERVED_PETYPE:std::cout << "ERROR CODE (" << error_code << " ): WSA_QOS_RESERVED_PETYPE" << std::endl;break;default:std::cout << "ERROR CODE (" << error_code << " ): Undefined" << std::endl;break;}
}int release()
{DEBUG_FUNCTION_NAME()/// int WSACleanup();///     操作成功返回值为0;///     否则返回值为SOCKET_ERROR,可以通过调用WSAGetLastError获取错误代码//////     在一个多线程的环境下,WSACleanup()中止了Windows Sockets在所有线程上的操作if (WSACleanup()){show_error_code();return EXIT_FAILURE;}return EXIT_SUCCESS;
}int init(WSADATA &wsaData)
{DEBUG_FUNCTION_NAME()/// WSAStartup (WSA 是 Windows Sockets API 的缩写)/// 该函数必须是使用WSA时调用的第一个函数,用于初始化WSA////// int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );/// wVersionRequested///     指定调用者可使用的Windows Sockets标准的最高版本。高位字节指定小版本(修订本)号,低位字节指定主版本号/// lpWSAData///     指向WSADATA数据结构的指针,用来接收 Windows Sockets 实现的细节///     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];///     }///     wVersion:///         Ws2_32.dll库期望调用这使用的Windows Sockets标准的版本。高位字节指定小版本(修订本)号,低位字节指定主版本号///     wHighVersion:///         Ws2_32.dll库支持的Windows Sockets标准的最高版本///     iMaxSockets:///         可以打开SOCKET的最大数量。该参数在WinSock2及以后版本被忽略///     iMaxUdpDg:///         数据报文的最大长度。该参数在WinSock2及以后版本被忽略///     lpVendorInfo///         制造商信息指针。该参数在WinSock2及以后版本被忽略///     szDescription///         以NULL终结的ASCII字符串,指示Windows Sockets实现的描述信息。///     szSystemStatus:///         以NULL终结的ASCII字符串,指示Windows Sockets状态或配置信息auto wVersionRequested = MAKEWORD(2, 2);int major_version = LOBYTE(wVersionRequested);int minor_version = HIBYTE(wVersionRequested);std::cout << "Expected Major Version: " << major_version << std::endl;std::cout << "Expected Minor Version: " << minor_version << std::endl;int error_code = WSAStartup(wVersionRequested, &wsaData);if (error_code){printf("WSAStartup failed with error: %d\n", error_code);return EXIT_FAILURE;}else{major_version = LOBYTE(wsaData.wVersion);minor_version = HIBYTE(wsaData.wVersion);std::cout << "Used Major Version: " << major_version << std::endl;std::cout << "Used Minor Version: " << minor_version << std::endl;major_version = LOBYTE(wsaData.wHighVersion);minor_version = HIBYTE(wsaData.wHighVersion);std::cout << "High Major Version: " << major_version << std::endl;std::cout << "High Minor Version: " << minor_version << std::endl;if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){printf("Could not find a usable version of Winsock.dll\n");release();return EXIT_FAILURE;}printf("The Winsock 2.2 dll was found okay\n");}return EXIT_SUCCESS;
}int get_host_name()
{DEBUG_FUNCTION_NAME()/// int gethostname([out] char *name, [in]  int  namelen);///     获取主机名称。///     如果没有错误发生,返回0;///     否则返回SOCKET_ERROR,并且可通过WSAGetLastError获取一个特定的错误码。/// 注意:///     1. 返回的主机名称以null为终结符///     2. 主机名称字符串的长度必须小于等于256char host_name[256]{0};if (SOCKET_ERROR == gethostname(host_name, 256)){show_error_code();release();return EXIT_FAILURE;}else{std::cout << "host name: " << host_name << std::endl;}return EXIT_SUCCESS;
}int create_socket(SOCKET &local_socket, int type)
{DEBUG_FUNCTION_NAME()/// SOCKET WSAAPI socket([in] int af, [in] int type, [in] int protocol);///     根据给定的传输协议创建SOCKET/// 参数///     af: 地址族,常用的为AF_INET, AF_INET6///     type: SOCKET 类型:///         SOCK_STREAM     TCP///         SOCK_DGRAM      UDP///         SOCK_RAW        可实现其他协议///     protocol:///         当类型指定为 SOCK_STREAM 或 SOCK_DGRAM,该参数被忽略。当使用SOCK_RAW时,必须指定该参数。可能的值如下:///         IPPROTO_ICMP///         IPPROTO_IGMP///         BTHPROTO_RFCOMM///         IPPROTO_TCP///         IPPROTO_UDP///         IPPROTO_ICMPV6///         IPPROTO_RM/// 返回值///     无错误发生,返回一个SOCKET描述符。///     否则返回INVALID_SOCKET,可使用WSAGetLastError()获取特定的错误码。local_socket = socket(AF_INET, type, 0);if (!(local_socket == INVALID_SOCKET))return EXIT_SUCCESS;show_error_code();release();return EXIT_FAILURE;
}int bind_local(SOCKET &socket_server, ADDRESS_FAMILY family, ULONG in_addr, USHORT port)
{DEBUG_FUNCTION_NAME()/// int WSAAPI bind([in] SOCKET s, [in] const sockaddr *name, [in] int namelen);///     绑定本地信息到SOCKET描述符/// 参数///     s       SOCKET 描述符///     name    本地地址信息///             如果地址信息中的 name->sin_addr.s_addr 赋值为htonl(INADDR_ANY),则绑定当前主机的所有可用IP///             如果地址信息中的 name->sin_addr.s_addr inet_addr("127.0.0.1"),则只能接受指定IP地址发起的连接或发送的数据///     namelen 本地地址信息的长度/// 返回值///     无错误发生,返回0;///     否则,返回 SOCKET_ERROR,可使用WSAGetLastError()获取特定的错误码。/// u_long WSAAPI    htonl (u_long hostlong);/// u_short WSAAPI   ntohs (u_short netshort);///     将参数类型的值,由主机字节序转换成TCP/IP网络字节序SOCKADDR_IN local_addr;memset(&local_addr, 0, sizeof(local_addr));  // 二选一ZeroMemory(&local_addr, sizeof(local_addr)); // 二选一local_addr.sin_family = family;local_addr.sin_addr.s_addr = in_addr;local_addr.sin_port = htons(port);if (bind(socket_server, (SOCKADDR *)&local_addr, sizeof(local_addr))){show_error_code();release();return EXIT_FAILURE;}return EXIT_SUCCESS;
}int connect_to_server(SOCKET &socket_client, ADDRESS_FAMILY family, ULONG in_addr, USHORT port)
{DEBUG_FUNCTION_NAME()/// int WSAAPI connect([in] SOCKET s, [in] const sockaddr *name, [in] int namelen);///     本函数用于创建与指定的外部端口的连接。/// 参数///     s       待连接的 SOCKET 描述符///     name    待连接的远程地址信息,若该结构中地址域全为零的话,将返回WSAEADDENOTAVAIL///     namelen 地址信息的长度/// 注意///     如果在调用该函数之前,未进行本地地址绑定,则系统将自动关联一个本地唯一的地址信息,且设置 SOCKET 为已绑定状态。/// 返回值///     无错误发生,返回0///     否则返回 SOCKET_ERROR,一个特定的错误码,可通过WSAGetLastError()进行获取SOCKADDR_IN remote_addr;memset(&remote_addr, 0, sizeof(remote_addr));  // 二选一ZeroMemory(&remote_addr, sizeof(remote_addr)); // 二选一remote_addr.sin_family = family;remote_addr.sin_addr.s_addr = in_addr;remote_addr.sin_port = htons(port);if (connect(socket_client, (SOCKADDR *)&remote_addr, sizeof(remote_addr))){show_error_code();release();return EXIT_FAILURE;}return EXIT_SUCCESS;
}int start_listen(SOCKET &socket_server)
{DEBUG_FUNCTION_NAME()/// int WSAAPI listen([in] SOCKET s, [in] int backlog);///     开启监听/// 参数///     s           SOCKET 描述符///     backlog     待处理连接队列的最大长度。///                 如果设置为 SOMAXCONN,负责 socket 的底层服务提供者会将 backlog 设置为最大合理值。///                 如果设置为 SOMAXCONN_HINT(N)(其中 N 是一个数字),则backlog将为 N,调整到范围 (200, 65535)。///                 请注意,SOMAXCONN_HINT 可用于将 backlog 设置为比 SOMAXCONN 更大的值。///                 SOMAXCONN_HINT 仅受 Microsoft TCP/IP 服务提供商支持。没有获得backlog值的标准规定。/// 返回值///     无错误发生,返回0;///     否则,返回 SOCKET_ERROR,可使用WSAGetLastError()获取特定的错误码。if (listen(socket_server, 5)){show_error_code();release();return EXIT_FAILURE;}return EXIT_SUCCESS;
}int wait_connect(SOCKET &socket_server, SOCKET &socket_client)
{DEBUG_FUNCTION_NAME()/// SOCKET WSAAPI accept([in] SOCKET s, [out] sockaddr *addr, [in, out] int *addrlen);///     等待客户端连接/// 参数///     s           SOCKET 描述符///     addr        已连接的客户端地址信息    addrlen     已连接的客户端地址信息的长度/// 返回值///     无错误发生,返回已连接的客户端的SOCKET描述符,///     否则返回 INVALID_SOCKET,可使用WSAGetLastError()获取特定的错误码。SOCKADDR_IN client_addr{0};int len = sizeof(SOCKADDR);memset(&client_addr, 0, len);socket_client = accept(socket_server, (SOCKADDR *)&client_addr, &len);if (INVALID_SOCKET == socket_client){show_error_code();release();return EXIT_FAILURE;}return EXIT_SUCCESS;
}int recv_message(SOCKET &socket_client, char *buffer, int &recv_length)
{DEBUG_FUNCTION_NAME()/// 无错误,返回接收到的字符串长度。如果连接被正常关闭,返回0/// 有错误, 返回 SOCKET_ERROR,可使用WSAGetLastError()获取特定的错误码。recv_length = recv(socket_client, buffer, BUFFER_SIZE, 0);if (recv_length == 0){std::cout << "The client is disconnected." << std::endl;return EXIT_FAILURE;}else if (recv_length == SOCKET_ERROR){show_error_code();closesocket(socket_client);return EXIT_FAILURE;}else if (recv_length < 0 && recv_length > BUFFER_SIZE){std::cout << "recvieved length is not correct. length is " << recv_length << std::endl;return EXIT_FAILURE;}return EXIT_SUCCESS;
}int send_message(SOCKET &socket, char* buffer, int buffer_length)
{DEBUG_FUNCTION_NAME()/// int WSAAPI send([in] SOCKET s,[in] const char *buf, [in] int len,[in] int flags);///     向已连接的SOCKET上发送数据/// 参数///     s  已连接的SOCKET描述符///     buf 待发送数据的首地址///     len 待发送数据的长度///     flags 一组指定的调用标志,可通过位与的方式拼接///         MSG_DONTROUTE   指定数据不受制于路由///         MSG_OOB         发送ODB数据,仅针对流式服务,例如SOCK_STREAM/// 返回值///     无错误,返回已发送的字节数///     有错误,返回SOCKET_ERROR,并可通过WSAGetLastError()获取特定的错误码int length = send(socket, buffer, buffer_length, 0);if(SOCKET_ERROR == length){show_error_code();return EXIT_FAILURE;}std::cout << "Expected length is " << buffer_length << ", sent length is " << length << std::endl;return EXIT_SUCCESS;
}
#endif // CPP_NETWORK_COMMUNICATION_COMMON_H

2. CMakeLists.txt

# 指定最低的CMAKE版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.17 FATAL_ERROR)# 创建项目
PROJECT(cpp_network_communication)if (CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Debug"))add_compile_definitions(DEBUG)
endif()SET(CMAKE_INCLUDE_CURRENT_DIR ON)# 指定CPLUSPLUS标准
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_C_STANDARD 11)
SET(CMAKE_C_STANDARD_REQUIRED ON)ADD_EXECUTABLE(tcp_server tcp/tcp_server.cpp)
ADD_EXECUTABLE(tcp_client tcp/tcp_client.cpp)ADD_EXECUTABLE(udp_server                       udp/udp_server.cpp)
ADD_EXECUTABLE(udp_client                       udp/udp_client.cpp)
ADD_EXECUTABLE(udp_server_boardcast             udp/udp_server_boardcast.cpp)
ADD_EXECUTABLE(udp_client_boardcast             udp/udp_client_boardcast.cpp)
ADD_EXECUTABLE(udp_server_multicast             udp/udp_server_multicast.cpp)
ADD_EXECUTABLE(udp_client_multicast             udp/udp_client_multicast.cpp)
ADD_EXECUTABLE(udp_server_multicast_config      udp/udp_server_multicast_config.cpp)

3. TCP

3.1 服务器(tcp_server.cpp)

#include "common/common.h"int main()
{WSADATA wsaData;if (init(wsaData))return EXIT_FAILURE;SOCKET socket_server;if (create_socket(socket_server, SOCK_STREAM))return EXIT_FAILURE;if (bind_local(socket_server, AF_INET, htonl(INADDR_ANY), TCP_SERVER_PORT))return EXIT_FAILURE;if (start_listen(socket_server))return EXIT_FAILURE;// 单连接SOCKET socket_client;std::cout << "waiting for client ..." << std::endl;if (!wait_connect(socket_server, socket_client)){char buffer[BUFFER_SIZE + 1]{0};for (size_t i = 0; i < COUNT; i++){int length = 0;std::cout << "waiting for data ..." << std::endl;if (!recv_message(socket_client, buffer, length)){std::cout << "\trecv message: " << buffer << std::endl;char *message = "server send client.";send_message(socket_client, message, strlen(message) + 1);}std::cout << "\trecv message: index = " << i << std::endl;}closesocket(socket_client);}release();system("PAUSE");return EXIT_SUCCESS;
}

3.2 客户端(tcp_client.cpp)

#include "common/common.h"int main()
{WSADATA wsaData;if (init(wsaData))return EXIT_FAILURE;SOCKET socket_client;if (create_socket(socket_client, SOCK_STREAM))return EXIT_FAILURE;// 客户端一般不进行绑定// 如果未指定绑定,则在调用connect函数时,系统自动绑定一个本地唯一的端口与IP。此时,每次重新连接,端口号与IP可能不相同(尤其在多IP主机上)// 如果进行绑定,则客户端具有固定的IP地址与端口号if (bind_local(socket_client, AF_INET, inet_addr("127.0.0.1"), TCP_Client_PORT))return EXIT_FAILURE;if (connect_to_server(socket_client, AF_INET, inet_addr("127.0.0.1"), TCP_SERVER_PORT))return EXIT_FAILURE;for (int i = 0; i < COUNT; i++){char *message = "client send to server.";send_message(socket_client, message, strlen(message) + 1);char buffer[BUFFER_SIZE]{0};int recv_length;recv_message(socket_client, buffer, recv_length);std::cout << buffer << std::endl;Sleep(1000);}closesocket(socket_client);release();system("PAUSE");return EXIT_SUCCESS;
}

4. UDP 单播

4.1 服务器/(首次)接收端(udp_server.cpp)

#include "common/common.h"int main()
{WSADATA wsaData;if (init(wsaData))return EXIT_FAILURE;SOCKET socket_server;if (create_socket(socket_server, SOCK_DGRAM))return EXIT_FAILURE;// 首次执行接受数据的一方,必须执行绑定;否则,可选// 不执行绑定操作,则在第一次调用recvfrom时,系统绑定唯一的地址与端口// 执行绑定后,具有唯一的地址与端口if (bind_local(socket_server, AF_INET, htonl(INADDR_ANY), UDP_SERVER_PORT))return EXIT_FAILURE;for (size_t i = 0; i < COUNT; i++){SOCKADDR_IN client_addr;ZeroMemory(&client_addr, sizeof(SOCKADDR_IN));int length = sizeof(SOCKADDR);char buffer[BUFFER_SIZE + 1]{0};int recv_length = recvfrom(socket_server, buffer, BUFFER_SIZE, 0, (SOCKADDR *)&client_addr, &length);char addr[INET_ADDRSTRLEN];inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, addr, INET_ADDRSTRLEN);std::cout << "\tThe client addr is " << addr << std::endl;std::cout << "\tThe length of recieved data is " << recv_length << std::endl;std::cout << "\tThe recieved data is " << buffer << std::endl;char *message = "server send client.";sendto(socket_server, message, strlen(message) + 1, 0, (SOCKADDR *)&client_addr, length);}closesocket(socket_server);release();system("PAUSE");return 0;
}

4.2 客户端/(首次)发送端(udp_client.cpp)

#include "common/common.h"int main()
{WSADATA wsaData;if (init(wsaData))return EXIT_FAILURE;SOCKET socket_client;if (create_socket(socket_client, SOCK_DGRAM))return EXIT_FAILURE;// 首次执行接受数据的一方,必须执行绑定;否则,可选// 不执行绑定操作,则在第一次调用recvfrom时,系统绑定唯一的地址与端口// 执行绑定后,具有唯一的地址与端口if (bind_local(socket_client, AF_INET, inet_addr("127.0.0.1"), UDP_CLIENT_PORT))return EXIT_FAILURE;for (size_t i = 0; i < COUNT; i++){SOCKADDR_IN server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");server_addr.sin_family = AF_INET;server_addr.sin_port = htons(UDP_SERVER_PORT);char *message = "client send to server.";sendto(socket_client, message, strlen(message) + 1, 0, (SOCKADDR *)&server_addr, sizeof(SOCKADDR));int length = sizeof(SOCKADDR);char buffer[BUFFER_SIZE + 1]{0};int recv_length = recvfrom(socket_client, buffer, BUFFER_SIZE, 0, (SOCKADDR *)&server_addr, &length);char addr[INET_ADDRSTRLEN];inet_ntop(AF_INET, &server_addr.sin_addr.s_addr, addr, INET_ADDRSTRLEN);std::cout << "\tThe client addr is " << addr << std::endl;std::cout << "\tThe length of recieved data is " << recv_length << std::endl;std::cout << "\tThe recieved data is " << buffer << std::endl;Sleep(1000);}closesocket(socket_client);system("PAUSE");WSACleanup();return 0;
}

5. 广播

5.1 服务器/(首次)接收端(udp_server_boardcast.cpp)

#include "common/common.h"int main()
{WSADATA wsaData;if (init(wsaData))return EXIT_FAILURE;SOCKET socket_server;if (create_socket(socket_server, SOCK_DGRAM))return EXIT_FAILURE;bool bOpt = true;  setsockopt(socket_server, SOL_SOCKET, SO_BROADCAST, (char*)&bOpt, sizeof(bOpt)); // 首次执行接受数据的一方,必须执行绑定;否则,可选// 不执行绑定操作,则在第一次调用recvfrom时,系统绑定唯一的地址与端口// 执行绑定后,具有唯一的地址与端口if (bind_local(socket_server, AF_INET, htonl(INADDR_ANY), UDP_SERVER_PORT))return EXIT_FAILURE;for (size_t i = 0; i < COUNT; i++){SOCKADDR_IN client_addr;ZeroMemory(&client_addr, sizeof(SOCKADDR_IN));int length = sizeof(SOCKADDR);char buffer[BUFFER_SIZE + 1]{0};int recv_length = recvfrom(socket_server, buffer, BUFFER_SIZE, 0, (SOCKADDR *)&client_addr, &length);char addr[INET_ADDRSTRLEN];inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, addr, INET_ADDRSTRLEN);std::cout << "\tThe client addr is " << addr << std::endl;std::cout << "\tThe length of recieved data is " << recv_length << std::endl;std::cout << "\tThe recieved data is " << buffer << std::endl;char *message = "server send client.";sendto(socket_server, message, strlen(message) + 1, 0, (SOCKADDR *)&client_addr, length);}closesocket(socket_server);release();system("PAUSE");return 0;
}

5.2 客户端/(首次)发送端(udp_client+bpardcast.cpp)

#include "common/common.h"int main()
{WSADATA wsaData;if (init(wsaData))return EXIT_FAILURE;SOCKET socket_client;if (create_socket(socket_client, SOCK_DGRAM))return EXIT_FAILURE;// 首次执行接受数据的一方,必须执行绑定;否则,可选// 不执行绑定操作,则在第一次调用recvfrom时,系统绑定唯一的地址与端口// 执行绑定后,具有唯一的地址与端口if (bind_local(socket_client, AF_INET, inet_addr("127.0.0.1"), UDP_CLIENT_PORT))return EXIT_FAILURE;bool bOpt = true;setsockopt(socket_client, SOL_SOCKET, SO_BROADCAST, (char *)&bOpt, sizeof(bOpt));for (size_t i = 0; i < COUNT; i++){SOCKADDR_IN server_addr;memset(&server_addr, 0, sizeof(server_addr));// 255.255.255.255 受限广播地址,路由器不转发,仅能在本机// 主机号全为1,定向广播地址,仅能向当前子网发送server_addr.sin_family = AF_INET;server_addr.sin_port = htons(UDP_SERVER_PORT);server_addr.sin_addr.s_addr = inet_addr("255.255.255.255");char *message = "client send to server.";sendto(socket_client, message, strlen(message) + 1, 0, (SOCKADDR *)&server_addr, sizeof(SOCKADDR));int length = sizeof(SOCKADDR);char buffer[BUFFER_SIZE + 1]{0};int recv_length = recvfrom(socket_client, buffer, BUFFER_SIZE, 0, (SOCKADDR *)&server_addr, &length);char addr[INET_ADDRSTRLEN];inet_ntop(AF_INET, &server_addr.sin_addr.s_addr, addr, INET_ADDRSTRLEN);std::cout << "\tThe client addr is " << addr << std::endl;std::cout << "\tThe length of recieved data is " << recv_length << std::endl;std::cout << "\tThe recieved data is " << buffer << std::endl;Sleep(1000);}closesocket(socket_client);system("PAUSE");WSACleanup();return 0;
}

6. 多/组播

6.1 服务器/(首次)接收端(udp_server_multicast.cpp)

#include "common/common.h"int main()
{WSADATA wsaData;if (init(wsaData))return EXIT_FAILURE;SOCKET socket_server;if (create_socket(socket_server, SOCK_DGRAM))return EXIT_FAILURE;// 设置地址复用bool is_reuse_addr = true;if (setsockopt(socket_server, SOL_SOCKET, SO_REUSEADDR, (char *)&is_reuse_addr, sizeof(is_reuse_addr))){show_error_code();release();return EXIT_FAILURE;}// 首次执行接受数据的一方,必须执行绑定;否则,可选// 不执行绑定操作,则在第一次调用recvfrom时,系统绑定唯一的地址与端口// 执行绑定后,具有唯一的地址与端口if (bind_local(socket_server, AF_INET, htonl(INADDR_ANY), UDP_SERVER_PORT))return EXIT_FAILURE;// 加入组播struct ip_mreq imr;imr.imr_multiaddr.s_addr = inet_addr(MULTICAST_ADDRESS);imr.imr_interface.s_addr = htonl(INADDR_ANY); // 这种情况下,由接口地址由系统进行选择。在多网卡的环境中,可能会出问题// imr.imr_interface.s_addr  = inet_addr(INTERFACE_ADDRESS);   // 直接指定具体网卡// 加入多播组if (setsockopt(socket_server, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, sizeof(imr))){show_error_code();release();return EXIT_FAILURE;}for (size_t i = 0; i < COUNT; i++){SOCKADDR_IN client_addr;ZeroMemory(&client_addr, sizeof(SOCKADDR_IN));int length = sizeof(SOCKADDR);char buffer[BUFFER_SIZE + 1]{0};int recv_length = recvfrom(socket_server, buffer, BUFFER_SIZE, 0, (SOCKADDR *)&client_addr, &length);char addr[INET_ADDRSTRLEN];inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, addr, INET_ADDRSTRLEN);std::cout << "\tThe client addr is " << addr << std::endl;std::cout << "\tThe length of recieved data is " << recv_length << std::endl;std::cout << "\tThe recieved data is " << buffer << std::endl;char *message = "server send to client.";sendto(socket_server, message, strlen(message) + 1, 0, (SOCKADDR *)&client_addr, length);}closesocket(socket_server);release();system("PAUSE");return 0;
}

6.1 客户端/(首次)发送端(udp_client_multicast.cpp)

#include "common/common.h"int main()
{WSADATA wsaData;if (init(wsaData))return EXIT_FAILURE;SOCKET socket_client;if (create_socket(socket_client, SOCK_DGRAM))return EXIT_FAILURE;// 设置地址复用bool is_reuse_addr = true;if (setsockopt(socket_client, SOL_SOCKET, SO_REUSEADDR, (char *)&is_reuse_addr, sizeof(is_reuse_addr))){show_error_code();release();return EXIT_FAILURE;}// 首次执行接受数据的一方,必须执行绑定;否则,可选// 不执行绑定操作,则在第一次调用recvfrom时,系统绑定唯一的地址与端口// 执行绑定后,具有唯一的地址与端口if (bind_local(socket_client, AF_INET, htonl(INADDR_ANY), UDP_CLIENT_PORT))return EXIT_FAILURE;// 加入组播struct ip_mreq imr;imr.imr_multiaddr.s_addr = inet_addr(MULTICAST_ADDRESS);imr.imr_interface.s_addr = htonl(INADDR_ANY); // 这种情况下,由接口地址由系统进行选择。在多网卡的环境中,可能会出问题// imr.imr_interface.s_addr  = inet_addr(INTERFACE_ADDRESS);   // 直接指定具体网卡if (setsockopt(socket_client, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, sizeof(imr))){show_error_code();release();return EXIT_FAILURE;}for (size_t i = 0; i < COUNT; i++){SOCKADDR_IN server_addr;ZeroMemory(&server_addr, sizeof(SOCKADDR_IN));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(MULTICAST_PORT);server_addr.sin_addr.s_addr = inet_addr(MULTICAST_ADDRESS);int length = sizeof(SOCKADDR);char *message = "client send to server.";sendto(socket_client, message, strlen(message) + 1, 0, (SOCKADDR *)&server_addr, length);Sleep(1000);char buffer[BUFFER_SIZE + 1]{0};int recv_length = recvfrom(socket_client, buffer, BUFFER_SIZE, 0, (SOCKADDR *)&server_addr, &length);char addr[INET_ADDRSTRLEN];inet_ntop(AF_INET, &server_addr.sin_addr.s_addr, addr, INET_ADDRSTRLEN);std::cout << "\tThe client addr is " << addr << std::endl;std::cout << "\tThe length of recieved data is " << recv_length << std::endl;std::cout << "\tThe recieved data is " << buffer << std::endl;}closesocket(socket_client);release();system("PAUSE");return 0;
}

【WinSock】TCP UDP Boardcast Multicast相关推荐

  1. 【转】TCP、UDP数据包大小的限制

    [转]TCP.UDP数据包大小的限制 来自:https://blog.csdn.net/caoshangpa/article/details/51530685 1.概述 首先要看TCP/IP协议,涉及 ...

  2. 【转载】TCP拥塞控制算法 优缺点 适用环境 性能分析

    [摘要]对多种TCP拥塞控制算法进行简要说明,指出它们的优缺点.以及它们的适用环境. [关键字]TCP拥塞控制算法 优点    缺点   适用环境公平性 公平性 公平性是在发生拥塞时各源端(或同一源端 ...

  3. 【计算机网络】TCP为什么需要4次挥手

    计算机网络--TCP释放连接的4次挥手 TCP连接释放过程比较复杂. 数据传输结束后,通信的双方都可释放连接. TCP连接释放过程是四次挥手. TCP报文段首部 上篇[计算机网络]TCP为什么需要3次 ...

  4. 【漫画】TCP断开连接为什么是四次挥手,不是二次挥手/三次挥手?

    前情回顾:[漫画]TCP连接为什么是三次握手,而不是两次握手,也不是四次握手? 乔戈里和小萌一起去美食城吃了午饭 小萌:额...哦!这就是两次挥手,我这里就好比是服务端还有消息没发送完,乔哥你的客户端 ...

  5. 【面试】TCP、UDP、Socket、HTTP网络编程面试题

    文章目录 什么是网络编程 网络编程中两个主要的问题 网络协议是什么 为什么要对网络协议分层 计算机网络体系结构 1 TCP / UDP 1.1 什么是TCP/IP和UDP 1.2 TCP与UDP区别: ...

  6. 【详解】TCP/UDP模式下的MODBUS协议转换

    modbus测试 此功能主要用来实现设备通讯的兼容性.比如相距较远的两台设备,其中A设备使用Modbus RTU协议进行通讯,B设备使用Modbus TCP协议进行通讯. 如果不使用协议转换功能,那么 ...

  7. 【网络编程】TCP/UDP/HTTP的区别和联系

    一.参考资料 TCP/UDP/HTTP的区别和联系_唯爱丶卡卡西的博客-CSDN博客 HTTP.UDP.TCP区别 - 知乎

  8. 【Network】高性能 UDP 服务应该怎么搞?

    参考资料: Netty系列之Netty高性能之道C++高性能服务框架revover:rudp总体介绍(可靠UDP传输) - zerok的专栏 - 博客频道 - CSDN.NET高性能异步Socket服 ...

  9. 32通过tcp发送数组_【干货】TCP协议详解

    关注我,你的眼睛会怀孕 为什么会有TCP/IP协议 在世界上各地,各种各样的电脑运行着各自不同的操作系统为大家服务,这些电脑在表达同一种信息的时候所使用的方法是千差万别.就好像圣经中上帝打乱了各地人的 ...

最新文章

  1. 一文概览深度学习中的激活函数
  2. linux centos 网络 时间 日期 同步
  3. Nginx 代理转发阿里云OSS上传的实现代码
  4. [剑指offer]面试题17:合并两个排序的链表
  5. js 把线性的数据结构改成树形结构
  6. Pentium II Pentium III架构/微架构/流水线 (4) - P6详解 - 高速缓存/Store Buffers
  7. python字典初始化_python设置默认字典
  8. 如何使用一套键盘鼠标,同时控制多台电脑?
  9. windows10 输入法繁体
  10. php 获取服务器端口,PHP获取当前服务器详细信息
  11. 计算机音乐模式怎么设置,电脑开机时自启QQ音乐APP播放歌曲的功能在哪里设置...
  12. python实现携程网站爬取
  13. buff系统 游戏中_arpg游戏的技能系统和buff系统的一种实现
  14. 简述计算机无法开机时故障处理方法,主板出问题了怎么办?电脑主板常见问题与故障处理方法...
  15. [今日名人回顾]计算机之父—冯·诺依曼
  16. 计算机技术 在职,计算机技术在职研究生招生简章
  17. 企业中台最佳实践----阿里等商业巨头组织架构的战略变迁(四)
  18. java 天猫模拟登陆_爬虫登录 最好是天猫爬虫登录 有经验的大神请赐教
  19. 玩 High API 系列好文(一):智能客服、钉钉Ding功能、智能云相册、快速实现身份验证
  20. 柔性塑料漆的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告

热门文章

  1. 5700: 还钱问题
  2. 使用第三方sdk时问题
  3. 计算机一级c云大,云南大学网红C位易主!新晋流量霸主竟然是……
  4. Kafka学习笔记1
  5. 开源工具 | 手游自动化框架GAutomator,新增iOS系统和UE4引擎支
  6. .fasta文件的相关处理
  7. LeedCode 24:两两交换链表中的节点
  8. 关于Java的抽象类与接口
  9. 运维监控软件的选择对比----Zabbix vs Prometheus
  10. 华为RH2288 V3安装Windows server/Linux详细教程