C++ IPv4 und IPv6 Fragen

Magogan

Lieutenant
Registriert
Aug. 2013
Beiträge
606
Hi,

ich schreibe gerade einen Server und Client in C++, was bisher mit IPv4 wunderbar funktioniert, allerdings wollte ich auch IPv6 unterstützen und habe da ein paar Fragen:

1) Sollte ich auf dem Server jeweils für UDP und für TCP (ich benötige beides) einen IPv4 und einen IPv6 Socket erstellen? Kann ich den gleichen Port für IPv4 und IPv6 nutzen? Oder reicht jeweils ein Socket für UDP und TCP? Hängt das vom OS ab oder kann ich davon ausgehen, dass letzteres (ein Socket für IPv4 und IPv6) auf Windows (ab Vista) und Ubuntu (ab 12) funktioniert?

2) Wenn ich IPv6 auch im lokalen Netzwerk nutzen muss, kann ich dann irgendwie nach allen Servern im Netzwerk scannen? Mit IPv4 funktioniert das derzeit über Broadcasting problemlos, aber das soll es bei IPv6 ja nicht geben.

Grüße,
Magogan
 
Jeder IPv6 Port ist offensichtlich auch ein IPv4 Port. Das ist per Definition schon so.
2 weiß ich leider nicht. Ausprobieren :(
 
Ok, danke. Muss ich SO_BROADCAST trotzdem setzen? Oder geht das ohne?

Und erreiche ich mit FF02::1 nicht mehr den lokalen PC wie noch mit 255.255.255.255 bei IPv4? Wenn ja, dann sende ich einfach ein zusätzliches Paket an localhost.
 
Zuletzt bearbeitet:
Magogan schrieb:
Muss ich SO_BROADCAST trotzdem setzen?
Keine Ahnung, ich kenne mich mit C++-Sockets nicht aus. Spontan würde ich sagen nein, da es ja ein Multicast und kein Broadcast ist. Ich würde es einfach ausprobieren.

Magogan schrieb:
Und erreiche ich mit FF02::1 nicht mehr den lokalen PC wie noch mit 255.255.255.255 bei IPv4?
Eigentlich schon, da die lokalen Interfaces auch Teil der FF02::1 Multicast-Group sind.
 
TheCadillacMan schrieb:
Eigentlich schon, da die lokalen Interfaces auch Teil der FF02::1 Multicast-Group sind.
Klappt irgendwie nicht. Hab es ausprobiert. Wenn ich nicht zusätzlich ein Paket an localhost sende, dann kommt beim lokalen Server nichts an.

Code:
SOCKET UDPBroadcastSocket;

#define MAXBUF 65536

bool NetworkConnection::Initialize(){
	WSADATA wsaData;

	int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData) == 0;
	if (iResult == SOCKET_ERROR){
		return false;
	}
	
	
	sockaddr_in6 sock_in;
	BOOL yes = 1;
	
	int sinlen = sizeof(struct sockaddr_in6);
	memset(&sock_in, 0, sinlen);
	
	UDPBroadcastSocket = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);

	sock_in.sin6_addr = in6addr_any;
	sock_in.sin6_port = htons(0);
	sock_in.sin6_family = PF_INET6;
	
#ifdef IPV6_V6ONLY
	BOOL No = 0;
	setsockopt(UDPBroadcastSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&No, sizeof(BOOL));
#endif

	iResult = bind(UDPBroadcastSocket, (sockaddr*)&sock_in, sinlen);
	if (iResult == SOCKET_ERROR){
		return false;
	}
	
	if (!SetSocketBlocking(UDPBroadcastSocket, false)){
		return false;
	}

	

	return true;
	

	

}

void NetworkConnection::SearchForLocalServers(std::vector<ServerInfo_t>& ServerInfo){
	struct sockaddr_in6 sock_in;
	
	
	struct addrinfo *result = NULL;
	struct addrinfo hints;

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_INET6;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;
	hints.ai_flags = 0;

	getaddrinfo("FF02::1", "12346", &hints, &result);
	unsigned char buffer[MAXBUF];
	buffer[0] = 7;
	
	int sinlen = result->ai_addrlen;
	memcpy(&sock_in, result->ai_addr, result->ai_addrlen);
	
	freeaddrinfo(result);

	int SendStatus = sendto(UDPBroadcastSocket, (char*)buffer, 1, 0, (sockaddr *)&sock_in, sinlen);
	if (SendStatus == SOCKET_ERROR){
		return;
	}

	getaddrinfo("::1", "12346", &hints, &result);
	sinlen = result->ai_addrlen;
	memcpy(&sock_in, result->ai_addr, result->ai_addrlen);

	freeaddrinfo(result);

	SendStatus = sendto(UDPBroadcastSocket, (char*)buffer, 1, 0, (sockaddr *)&sock_in, sinlen);
	if (SendStatus == SOCKET_ERROR){
		return;
	}
	TIME StartTime = GetHighPrecisionTime();
	TIME CurrentTime = StartTime;
	ServerInfo.emplace_back();
	while ((CurrentTime - StartTime).GetTimeInMs() < 500){
		ServerInfo.back().AddressLength = sizeof(sockaddr_in6);
		int ReceiveStatus = recvfrom(UDPBroadcastSocket, (char*)buffer, MAXBUF, 0, (sockaddr*)&(ServerInfo.back().Address), &(ServerInfo.back().AddressLength));
		if (ReceiveStatus == SOCKET_ERROR){
			Sleep(1);
			CurrentTime = GetHighPrecisionTime();
			continue;
		}
		NetworkPacketHeader Header;
		if (ReceiveStatus > Header.GetSerializedSize()){
			Header.Deserialize(buffer);
			if (Header.PacketType == NP_SERVER_INFO){
				NetworkPacketServerInfo Packet;
				size_t PacketSize = Packet.GetSerializedSize();
				if (PacketSize + Header.GetSerializedSize() == ReceiveStatus){
					Packet.Deserialize(&(buffer[Header.GetSerializedSize()]));

					ServerInfo.back().TCP_Port = Packet.Port;
					ServerInfo.back().Flags = Packet.Flags;
					ServerInfo.back().CurrentNumPlayers = Packet.CurrentPlayers;
					ServerInfo.back().MaxNumPlayers = Packet.MaxPlayers;
					ServerInfo.emplace_back();
				}
			}

		}
		Sleep(1);
		CurrentTime = GetHighPrecisionTime();
	}
	ServerInfo.pop_back();
}
 
Zuletzt bearbeitet:
Evtl hilft es dir nicht weiter, aber könntest du QT verwenden? Das geht auch komplett ohne GUI und ich bin mir sicher, dass du weniger als die Hälfte von dem Quellcode brauchst.
Ich bin ziemlicher TCPIP noob aber nen single-connection-TCPServer hab ich damit ziemlich flott hinbekommen. IPv6 kann QT seit 4.8
 
Zuletzt bearbeitet:
So komplex ist das ja nun auch nicht, außerdem scheint es ja zu funktionieren, wieso also sollte ich das nochmal komplett umschreiben, nur um Qt zu nutzen?
 
Hab es jetzt mal bei mir im LAN getestet mit verschiedenen PCs. FF02::1 geht nicht oder zumindest nicht bei mir (liegt vielleicht am Router), stattdessen muss man bei IPV6_ADD_MEMBERSHIP eine Group ID angeben, also z.B. FF02::1234:5678, und dann die Pakete an diese Adresse senden.
 
Zurück
Oben