C++: Udp mit select() & Timeout



  • Dieser Thread wurde von Moderator/in nman aus dem Forum Linux/Unix in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • keiner der mir helfen kann?
    oder ist meine frage unklar?



  • Was gibt recvfrom denn zurück?



  • mit WSAStartup (MAKEWORD (2,2), &wsa):
    in der allerersten Schleife meldet select()korrekt einen Timeout, danach nicht mehr und recvfrom() liefert 4lachende Smileys gefolgt von "WinSock 2.0" (das mit den Smileys ist kein Witz ! 🙂

    mit WSAStartup (MAKEWORD (2,0), &wsa):
    Das gleiche Verhalten, allerdings nur ein einzelnes Smiley, sonst nix



  • Was gibt recvfrom denn zurück?



  • sry

    recvfrom: -1
    WSAGetLastError: 10054



  • moon12 schrieb:

    recvfrom: -1

    Also ein Fehler. Dann solltest du nichts ausgeben, da kann ja nur Quark kommen.

    moon12 schrieb:

    WSAGetLastError: 10054

    Doku sagt:

    WSAECONNRESET: On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.



  • das da mist rauskommt ist ja klar, mein programm hat ja auch nichts empfangen sondern nur selbst gesendet.
    Meine Frage war ja auch, warum select() zuvor keinen Timeout meldet, sondern eben eine 0, was überhaupt erst dazu führt, dass recvfrom() aufgerufen wird.

    und was das WSAECONNRESET betrifft:
    Was genau bedeutet das? nach meinem bisherigen verständnis ist doch udp verbindungslos, also wird eine nachricht einfach an einen Port gefeuert und danach sich nicht mehr drum gekümmert oder nicht? wie sollte das also mein select() beeinflussen?



  • Wsa gibt denn sendto zurück?



  • 56
    also die Anzahl an gesendeten Bytes
    WSAGETLASTERROR bei sendto: 0



  • Ok, ich kann es reproduzieren, aber erklären kann ich's nicht. 😕



  • hm immerhin ^^
    aber ist mein ansatz sonst (mit ausnahme, dass ich an localhost sende) in ordnung?
    oder würde man senden & empfangen in dem verbund generell anders realisieren?



  • Nutz beim Initialisieren mal Winsock 2.0
    Mach den ersten Parameter bei select zu 0 (der wird unter Windows nicht benötigt)

    Ist dein Puffer groß genug?

    Und dann mach mal ein kompilierbares Beispiel, ansonsten hab ich keine Lust mir das genauer anzuschauen...



  • frisch aufgesetzt:

    // Udp: senden->empfangen per select()
    
    # pragma comment(lib, "Ws2_32.lib")
    # include <string>
    # include <iostream>																			
    # include <WinSock2.h>																		
    # include <Windows.h>																		
    using namespace std;
    
    int main()
    {
    	//--Variablenliste
    	int iRemoteAddrLenght = sizeof(SOCKADDR_IN);
    	long rc;
    	SOCKET UdpSocket;	
    	char szBuffer[256] = {0};
    	SOCKADDR_IN RemoteAddr;	
    	SOCKADDR_IN OwnAddr;
    	fd_set Fds;
    	struct timeval Timeout;
    	Timeout.tv_sec = 2;
    	Timeout.tv_usec = 0;
    	string sSend = "Teststring";
    	string sRecv;
    
    	//--Winsock
    	WSADATA wsa;																	
    	rc =  WSAStartup (MAKEWORD (2,0), &wsa);
    	if (rc != 0)
    	{
    		cout << "Fehler: startWinsock, Fehlercode: " << rc << endl;
    	} //if
    	else
    	{
    		cout << "Winsock gestartet!" << endl;
    	} //else
    
    	//--Socket
    	UdpSocket = socket(AF_INET, SOCK_DGRAM, 0);
    	if (UdpSocket == INVALID_SOCKET)
    	{
    		cout << "Fehler: Socket konnte nicht erstellt werden, Fehlercode: " << WSAGetLastError() << endl;
    	} //if
    	else
    	{
    		cout << "Socket erstellt!" << endl;
    	} //else
    
    	//--SOCKADDR_IN
    	RemoteAddr.sin_family = AF_INET;																
    	RemoteAddr.sin_port = htons (2002);			
    	RemoteAddr.sin_addr.s_addr = inet_addr("127.0.0.1");	
    
    	OwnAddr.sin_family = AF_INET;
    	OwnAddr.sin_port = htons (2003);
    	OwnAddr.sin_addr.s_addr = ADDR_ANY;
    
    	//--bind: OwnAddr
    	rc = bind(UdpSocket, (SOCKADDR*) &OwnAddr, sizeof(OwnAddr));
    	if (rc == SOCKET_ERROR)
    	{
    		cout << "Fehler: bind, Fehlercode: " << WSAGetLastError() << endl;
    	} //if
    	else
    	{
    		cout << "Socket an Port " << htons(OwnAddr.sin_port) << " gebunden!" << endl;
    	} //else
    
    	//--Endlosschleife mit senden + empfangen
    	for(;;)
    	{
    		//--sendto
    		rc = sendto(UdpSocket, sSend.c_str(), strlen(sSend.c_str()), 0 , (SOCKADDR*) &RemoteAddr, sizeof(RemoteAddr));
    		cout << "return sendto: " << rc << endl;
    		if (rc == SOCKET_ERROR)
    		{
    			cout << "Fehler: sendto, Fehlercode: " << WSAGetLastError() << endl;
    		} //if
    		else
    		{
    			cout << "sendto, gesendet: " << sSend << endl;
    			cout << rc << " Bytes gesendet!" << endl;
    		} //else
    
    		//--select
    		FD_ZERO(&Fds);
    		FD_SET(UdpSocket,&Fds);
    		rc = select(0, &Fds, NULL,NULL, &Timeout);
    		cout << "return select: " << rc << endl;
    		if(rc == -1)
    		{
    			cout << "Fehler: select, Fehlercode: " << WSAGetLastError() << endl;
    		} //if
    		else if(rc == 0)
    		{
    			cout << "Fehler: select timeout" << endl;
    			cout << "select timeout Fehlercode: " << WSAGetLastError() << endl;
    		} //else if
    		else if(rc > 0)
    		{
    			if(FD_ISSET(UdpSocket, &Fds))
    			{
    				rc = recvfrom(UdpSocket, szBuffer, 256, 0, (SOCKADDR*) &RemoteAddr, &iRemoteAddrLenght); 
    				cout << "return recvfrom: " << rc << endl;
    				if (rc == SOCKET_ERROR)
    				{
    					cout << "Fehler: recvfrom, Fehlercode: " << WSAGetLastError() << endl;
    				} //if
    				else
    				{
    					sRecv = szBuffer;
    					cout << " Empfangen: " << sRecv << endl;
    					cout << rc << " Bytes empfangen!" << endl;
    				} //else				
    			} //if
    		} //else if
    
    		cout << endl << "----------------------------------------" << endl;
    
    	} //for
    
    	closesocket(UdpSocket);
    	WSACleanup();
    	return 0;
    
    } //main()
    

    Wobei ich rausgefunden habe, dass das Problem immer auftritt, wenn ich den Socket auf der Gegenseite nicht eingerichtet habe, egal bei welcher Ip im Netzwerk.



  • Lang ists her...

    Die Lösung ist:

    select() verändert die Einstellungen bei jedem Durchlauf.

    Man muss das
    Timeout.tv_sec = 2;
    Timeout.tv_usec = 0;

    innerhalb der Endlosschleife neu setzen.

    Dank, natürlich, an Stackoverflow.


Anmelden zum Antworten