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
#include
#include
#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(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(remoteAddr);
closesocket(s);
WSACleanup();
return 0;
}
客户端代码
#include "stdafx.h"
#include
#include
#pragma comment(lib, "ws2_32.lib")
#include
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(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(remoteAddr2);
}
}
getchar();
closesocket(s);
WSACleanup();
return 0;
}