1. 程式人生 > >udp客戶端和伺服器程式碼,支援ipv6。

udp客戶端和伺服器程式碼,支援ipv6。

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;
}