udp客戶端和伺服器程式碼,支援ipv6。
阿新 • • 發佈:2019-01-26
getaddrinfo這個函式隱藏了ipv4和ipv6的具體細節,強烈推薦使用。設定hints.ai_family = AF_UNSPEC後,getaddrinfo可以根據ip地址自動判斷是ipv4還是ipv6。當然也可以使用hints.ai_family = AF_INET6直接指定為ipv6。
同時getnameinfo也是同時支援ipv4和ipv6的函式,建議使用。
伺服器程式碼:
#include "stdafx.h" #include <winsock2.h> #include <iostream> #include <Ws2tcpip.h> #pragma comment(lib, "ws2_32.lib") int main() { WSADATA wd{}; auto err = WSAStartup(MAKEWORD(2, 2), &wd); if (0 != err) { return 0; } addrinfo *result = nullptr; addrinfo hints = {}; hints.ai_socktype = SOCK_DGRAM; //資料報 hints.ai_protocol = IPPROTO_UDP; //udp hints.ai_family = AF_UNSPEC; //協議無關 hints.ai_flags = AI_PASSIVE; //用於服務端bind,用於bind這個引數必須設定 //第一個引數為nullptr或0.0.0.0,表示監聽本地所有網絡卡資料,0.0.0.0表示只能為ipv4。 //或者hints.ai_family = AF_INET;也表示使用ipv4 auto dwRetval = getaddrinfo("0.0.0.0" /*本地所有網絡卡,ipv4*/, "3000"/*埠號為3000*/, &hints, &result); if (0 != dwRetval) { return 0; } auto s = socket(result->ai_family, result->ai_socktype, result->ai_protocol); if (INVALID_SOCKET == s) { return 0; } err = bind(s, result->ai_addr, result->ai_addrlen); if (0 != err) { return 0; } int nSendSize = result->ai_addrlen; sockaddr *remoteAddr = reinterpret_cast<sockaddr *>(new char[nSendSize]); char buffer[1000] = {}; while (true) { int nSendSizeTemp = nSendSize; auto ret = recvfrom(s, buffer, sizeof(buffer), 0, remoteAddr, &nSendSizeTemp); //接收來自客戶端的資料 if (0 == ret || SOCKET_ERROR == ret) { break; } ret = sendto(s, buffer, ret, 0, remoteAddr, nSendSizeTemp); //發往客戶端 if (0 == ret || SOCKET_ERROR == ret) { break; } char szIp[200] = {}; char szPort[200] = {}; ret = getnameinfo(result->ai_addr, result->ai_addrlen, szIp, sizeof(szIp), szPort, sizeof(szPort), NI_NUMERICSERV | NI_NUMERICHOST); if (0 != ret) { return 0; } std::cout << szIp << ":" << szPort << "," << buffer << std::endl; } delete[] reinterpret_cast<char*>(remoteAddr); closesocket(s); WSACleanup(); return 0; }
客戶端程式碼
#include "stdafx.h" #include <winsock2.h> #include <Ws2tcpip.h> #pragma comment(lib, "ws2_32.lib") #include <iostream> int main() { bool bConnect = true; //使用upd的兩種方式 WSADATA wd{}; auto err = WSAStartup(MAKEWORD(2, 2), &wd); if (0 != err) { return 0; } addrinfo *result = nullptr; addrinfo hints = {}; hints.ai_socktype = SOCK_DGRAM; //資料報 hints.ai_protocol = IPPROTO_UDP; //udp hints.ai_family = AF_UNSPEC; //協議無關 auto dwRetval = getaddrinfo("127.0.0.1","3000",&hints,&result); //127.0.0.1 為伺服器ip,並且表明是ipv4。3000 為伺服器埠號 if (0 != dwRetval) { return 0; } auto s = socket(result->ai_family, result->ai_socktype, result->ai_protocol); if (INVALID_SOCKET == s) { return 0; } char buffer[] = "你好啊呵呵"; char bufferRecv[1024] = {}; //udp兩種方式 if (bConnect) //第一種,使用connect { auto ret = connect(s, result->ai_addr, result->ai_addrlen); if (0 != ret) { return 0; } for (int i = 0; i != 10 ; i++) { ret = send(s, buffer, sizeof(buffer), 0); if (SOCKET_ERROR == ret) { return 0; } ret = recv(s, bufferRecv, sizeof(bufferRecv), 0); if (SOCKET_ERROR == ret) { return 0; } char szIp[200] = {}; char szPort[200] = {}; ret = getnameinfo(result->ai_addr, result->ai_addrlen,szIp, sizeof(szIp), szPort, sizeof(szPort), NI_NUMERICSERV | NI_NUMERICHOST); if (0 != ret) { return 0; } std::cout << szIp << ":" << szPort << "," << bufferRecv << std::endl; } } else //第二種,不使用connect { for (int i = 0; i != 10; i++) { auto ret = sendto(s, buffer, sizeof(buffer), 0, result->ai_addr, result->ai_addrlen); if (SOCKET_ERROR == ret) { return 0; } int nSendSize = result->ai_addrlen; sockaddr *remoteAddr2 = reinterpret_cast<sockaddr *>(new char[nSendSize]); ret = recvfrom(s, bufferRecv, sizeof(bufferRecv), 0, remoteAddr2, &nSendSize); if (SOCKET_ERROR == ret) { return 0; } char szIp[200] = {}; char szPort[200] = {}; ret = getnameinfo(remoteAddr2, nSendSize, szIp, sizeof(szIp), szPort, sizeof(szPort), NI_NUMERICSERV | NI_NUMERICHOST); if (0 != ret) { return 0; } std::cout << szIp << ":" << szPort << "," << bufferRecv << std::endl; delete[] reinterpret_cast<char*>(remoteAddr2); } } getchar(); closesocket(s); WSACleanup(); return 0; }