TCP Chat



  • Hallo,
    habe folgendes Problem. Die Verbindung des Sockets funktioniert nur läuft das recv in einer Dauerschleife, empfängt aber nicht was ich beim sender eingebe. Ich würde gerne alles abbilden nur das geht leider nicht ich vermute, weil es dan zu lang ist.

    DWORD WINAPI ThreadProc( LPVOID lpParam ){
    
    SOCKET usocket = (SOCKET)lpParam;
    cout << "cast" << endl;
    while(true){
    
    nByte = recv(usocket,buffer,buffer_size,0);
    cout << "recv" << endl;
    
    	// Ausgaben wenn etwas empfangen wurde
    	if(nByte > 0){
    
    		// Am ende die Null anhängen, da sonst mist ausgegeben wird
    		// WICHTIG strlen missachtet die \0 !!!
    		//buffer[nByte] = 0;
    
    		// Textfarbe mit der Konsolenklasse auf rot setzen
    		con.setTextColor(FG_RED);
    		// Ausgabe der IP und Portnummer
    		cout << inet_ntoa(sender.sin_addr) << ":" << ntohs(sender.sin_port) << endl;
    		// Ausgabe der IP und Portnummer in eine datei
    		Datei << inet_ntoa(sender.sin_addr) << ":" << ntohs(sender.sin_port) << endl;
    		// Ausgabe der übertragennen Daten
    		cout << buffer << endl;
    		// Ausgabe der übertragennen Daten in eine datei
    		Datei << buffer << endl;
    	}
    // Wenn das Event gesetzt wird, verlasse die Schleife
    if (WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) break;
    }
    return 0;
    }
    


  • Hier der Versuch den rest des empfängers zu zeigen

    #include <fstream>
    #include <stdio.h>
    #include <winsock2.h>
    #include <iostream>
    #include <conio.h>
    #include <string>
    #include "ic.hpp"
    using namespace std;
    // Namespace der Konsolenklasse zugänglich machen
    using namespace ic;
    
    SOCKET hSock; // socket handle created
    SOCKADDR_IN sender; // socket address of sender
    int dwSenderSize; // size of socket address of sender
    SOCKADDR_IN local; // local address
    
    char buffer[1000]; // Empfangspuffer
    string buffer_senden;
    int buffer_size = 1000; // Grösse des Empfangspuffers
    // int buffer_size = 1000;
    int nRet; // Returncode
    int nByte; // Anzahl empfangener Bytes
    int bRet(0);
    // Handle für den Thread
    HANDLE hThread;
    DWORD dwThreadId;
    // Hande für das Event
    HANDLE hEvent;
    // Stream für die Dateiausgabe
    ofstream Datei;
    SOCKET hClSock; // client socket handle returned form accept()
    int sendersize = sizeof(sender);
    
    WSADATA stWSAData; // returned from WSAStartup
    WORD wVersionRequested; // requested WInsock Version
    
    DWORD WINAPI ThreadProc( LPVOID lpParam ){
    
    SOCKET usocket = (SOCKET)lpParam;
    cout << "cast" << endl;
    while(true){
    
    nByte = recv(usocket,buffer,buffer_size,0);
    cout << "recv" << endl;
    
    	// Ausgaben wenn etwas empfangen wurde
    	if(nByte > 0){
    
    		// Am ende die Null anhängen, da sonst mist ausgegeben wird
    		// WICHTIG strlen missachtet die \0 !!!
    		//buffer[nByte] = 0;
    
    		// Textfarbe mit der Konsolenklasse auf rot setzen
    		con.setTextColor(FG_RED);
    		// Ausgabe der IP und Portnummer
    		cout << inet_ntoa(sender.sin_addr) << ":" << ntohs(sender.sin_port) << endl;
    		// Ausgabe der IP und Portnummer in eine datei
    		Datei << inet_ntoa(sender.sin_addr) << ":" << ntohs(sender.sin_port) << endl;
    		// Ausgabe der übertragennen Daten
    		cout << buffer << endl;
    		// Ausgabe der übertragennen Daten in eine datei
    		Datei << buffer << endl;
    	}
    // Wenn das Event gesetzt wird, verlasse die Schleife
    if (WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) break;
    }
    return 0;
    }
    
    int main(){
    // --- Winsock initialisieren ---------
    wVersionRequested = MAKEWORD( 2, 0 ); // Version 2.0
    nRet = WSAStartup(wVersionRequested,&stWSAData);
    // Fehlerabfrage
    if(nRet < 0){
    	cout << "Fehler bei WSAStartup";
    }
    
    con.setTitle(TEXT("UDP Chat"));
    // --- Wer bin ich ? ------------------
    cout << "UDP Empfaenger ..." << endl << "Beenden durch Eingabe von exit" << endl;
    
    // --- Socket erzeugen ----------------
    hSock = socket(AF_INET,SOCK_STREAM,0);
    
    // --- Socket binden ------------------
    local.sin_family = PF_INET;
    local.sin_port = htons((short)4712); // meine Portnummer
    local.sin_addr.s_addr = htonl(INADDR_ANY); // IP Adresse des ersten Interfaces
    bRet = bind(hSock,(SOCKADDR *)&local,sizeof(local)) ;
    // Fehlerabfrage
    if(bRet == SOCKET_ERROR) cout << WSAGetLastError() ;
    
    // Datei angeben und mit rechten versehen
    Datei.open("Verlauf_empfaenger.txt", ios_base::out | ios::app);
    
    // Event erzeugen
    hEvent = CreateEvent( 
        0,         // default security attributes
        TRUE,         // manual-reset event
        0,         // initial state is non signaled
        0  // object name
        );
    
    //nRet = connect(hSock,(LPSOCKADDR)&sender,sizeof(sender));
    //if(SOCKET_ERROR == nRet) cout << ::WSAGetLastError();
    
    // ---- set listen mode ------------------------
    nRet = listen(hSock,SOMAXCONN);
    if(SOCKET_ERROR == nRet) cout << ::WSAGetLastError();
    cout << "listenmode" << endl;
    
    	// --- accept connection -----------------------
    hClSock = accept(hSock,(SOCKADDR *)&sender,&sendersize);
    if(SOCKET_ERROR == hClSock) cout << ::WSAGetLastError();
    cout << "accept" << endl;
    
    // Emfangs Thread erzeugen
    hThread = CreateThread( 
                NULL,              // default security attributes
                0,                 // use default stack size  
                ThreadProc,        // thread function 
                &hClSock,             // argument to thread function 
                0,                 // use default creation flags 
                &dwThreadId);   // returns the thread identifier
    
    // --- Verbindung schliessen ----------
    nRet = shutdown(hSock,SD_BOTH);
    
    // --- Socket schliessen --------------
    nRet = closesocket(hSock);
    
    // --- Winsock deinitialisieren -------
    nRet = WSACleanup();
    
    // Unendlich Warten bis der Thread ordnungsgemaes beendet wurde
    WaitForSingleObject(hThread, INFINITE);
    
    // Dateistream schließen
    Datei.close();
    _getch();
    return 0;
    }
    


  • Ich hab mir jetzt nicht alles detailliert durchgeschaut, aber dir ist schon klar, dass nach dem Senden von n Bytes dein recv nicht unbedingt wieder n Bytes zurückmeldet, sondern die Daten auch stückchenweise empfangen kann (ist oft so)?
    Guck mal hier im Forum nach anderen tcp-threads, das Problem gabs schon öfters 😉



  • Ja das das ganze gestückelt sein kann weis ich, deswegen hab ich es ja auch in eine while-Schleife gesetzt...
    Er erzeugt jetzt 100% CPU Auslastung mit der Empfangsschleife, irgendwas is da flasch 😃



  • [quote="Mitbewohner"Er erzeugt jetzt 100% CPU Auslastung mit der Empfangsschleife, irgendwas is da flasch :D[/quote]
    hehe, ich glaube mit der recv-Empfangsschleife hat jeder erstmal Probleme 😉 Guck mal hier, da dürfte das richtige zu finden sein 👍



  • Ich kenn mich mit UDP nicht so aus, aber evtl. arbeitet dein Socket im Non-Blocking-Modus, d.h. wenn nichts da ist, wird 0 zurückgegeben.

    Probier mal:

    if(nByte > 0){
    
    }
    else
      Sleep(1);
    


  • Dieser Thread wurde von Moderator/in Marc++us aus dem Forum C++ 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.



  • verrate mir mal WANN bei dir das break in deiner While(true) aufgerufen wird .... du hast das event zwar erzeugt aber es wird nie bedient ...

    mal abgesehen davon, dein recv liefert entweder anzahl bytes oder 0 wenn verbindung getrennt oder -1 wenn fehler .... du solltest mal ne fehlerkontrolle einbauen und nicht einfach davon ausgehen das die verbindung schon irgendwie hinhaut.

    könntest du eventuell auch ein paar auszuüge aus dem client servieren ? weil das scheint nur der server zu sein oder irre ich mich ?



  • Ceos schrieb:

    verrate mir mal WANN bei dir das break in deiner While(true) aufgerufen wird .... du hast das event zwar erzeugt aber es wird nie bedient ...

    mal abgesehen davon, dein recv liefert entweder anzahl bytes oder 0 wenn verbindung getrennt oder -1 wenn fehler .... du solltest mal ne fehlerkontrolle einbauen und nicht einfach davon ausgehen das die verbindung schon irgendwie hinhaut.

    könntest du eventuell auch ein paar auszuüge aus dem client servieren ? weil das scheint nur der server zu sein oder irre ich mich ?

    Ein chat hat ja die Eigenschaft in zwei Richtungen zu funktionieren, da es nicht geklappt hat, probiere ich jetzt erst mal die eine Richtung. Das event wird gesetzt wenn man exit eingibt. Eine Eingabe beim Empfänger gibt es aber halt noch nicht bzw. ich hab sie wieder raus genommen.
    Anbei der Sender, der auch das mit dem exit zeigt.

    sender

    #include <stdio.h>
    #include <winsock2.h>
    #include <iostream>
    #include <string>
    #include <conio.h>
    #include <fstream>
    #include "ic.hpp"
    using namespace std;
    // Namespace der Konsolenklasse zugänglich machen
    using namespace ic;
    
    // --- Initialisierungen --------------
    WSADATA stWSAData; // returned from WSAStartup
    WORD wVersionRequested; // requested WInsock Version
    SOCKET hSock; // socket handle created
    SOCKADDR_IN receiver; // socket address of receiver
    SOCKADDR_IN local; // local socket address
    int bRet(0);
    
    // char *buffer = "Hallo Welt"; // Testdata
    string buffer;
    // int buffer_size = strlen(buffer); // Size of Testdata
    int nRet; // Returncode
    HANDLE hThread;
    DWORD dwThreadId;
    char buffer_empfangen[1000]; // Empfangspuffer
    int buffer_size = 1000; // Grösse des Empfangspuffers
    int dwSenderSize; // size of socket address of sender
    int nByte; // Anzahl empfangener Bytes
    // CRITICAL_SECTION CS;
    // Hande für das Event
    HANDLE hEvent;
    // Stream für die Dateiausgabe
    ofstream Datei;
    SOCKET hClSock; // client socket handle returned form accept()
    
    DWORD WINAPI ThreadProc( LPVOID lpParam ){
    // --- Daten empfangen ----------------
    
    while(true){
    // ---- set listen mode ------------------------
    nRet = listen(hSock,SOMAXCONN);
    
    // --- accept connection -----------------------
    hClSock = accept(hSock,(SOCKADDR *)&receiver,(int*)sizeof(receiver));
    
    // --- receive some Bytes blocking ! ----------
    nByte = recv(hClSock,buffer_empfangen,buffer_size,0);
    	// Ausgaben
    	if(nByte > 0){
    
    		// Am ende die Null anhängen, da sonst mist ausgegeben wird
    		// WICHTIG strlen missachtet die \0 !!!
    		//buffer_empfangen[nByte] = 0;
    
    		// Textfarbe mit der Konsolenklasse auf rot setzen
    		con.setTextColor(FG_RED);
    		// Ausgabe der IP und Portnummer
    		cout << inet_ntoa(receiver.sin_addr) << ":" << ntohs(receiver.sin_port) << endl;
    		// In Datei schreiben
    		Datei << inet_ntoa(receiver.sin_addr) << ":" << ntohs(receiver.sin_port) << endl;
    		// Ausgabe der übertragennen Daten
    		cout << buffer_empfangen << endl;
    		// In Datei schreiben
    		Datei << buffer_empfangen << endl;
    	}
    	// Wenn das Event gesetzt wird, verlasse die Schleife
    	if (WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) break;
    }
    return 0;
    }
    
    int main(){
    
    con.setTitle(TEXT("UDP Chat"));
    // --- Wer bin ich ? ------------------
    cout << "UDP Sender ..." << endl << "Beenden durch Eingabe von exit" << endl;
    
    // --- Winsock initialisieren ---------
    wVersionRequested = MAKEWORD( 2, 0 ); // Version 2.0
    nRet = WSAStartup(wVersionRequested,&stWSAData);
    // Fehlerabfrage
    if(nRet < 0){
    	cout << "Fehler bei WSAStartup";
    }
    
    // --- Socket erzeugen ----------------
    hSock = socket(AF_INET,SOCK_STREAM,0);
    	if(INVALID_SOCKET == hSock){
    		return 1;
    	}
    
    // --- Socket binden ------------------
    local.sin_family = PF_INET;
    local.sin_port = htons((short)4711); // meine Portnummer
    local.sin_addr.s_addr = inet_addr("127.0.0.1"); // meine IP Adresse
    bRet = bind(hSock,(SOCKADDR *)&local,sizeof(local));
    // Fehlerabfrage
    if(bRet == SOCKET_ERROR) cout << ::WSAGetLastError();
    
    // --- Zieladresse setzen -------------
    receiver.sin_family = PF_INET;
    receiver.sin_port = htons((short)4712); // Zielport
    // receiver.sin_addr.s_addr = inet_addr("127.0.0.1"); // Ziel IP Adresse
    receiver.sin_addr.s_addr = inet_addr("127.0.0.1"); // Ziel IP Adresse
    
    Datei.open("Verlauf_sender.txt", ios_base::out | ios::app);
    
    // Event erzeugen
    hEvent = CreateEvent( 
        0,         // default security attributes
        TRUE,         // manual-reset event
        0,         // initial state is non signaled
        0  // object name
        );
    
    nRet = connect(hSock,(SOCKADDR *)&receiver,sizeof(receiver));
    if(SOCKET_ERROR == nRet) cout << ::WSAGetLastError();
    cout << "connected" << endl;
    
    // Thread erzeugen
    //hThread = CreateThread( 
    //            NULL,              // default security attributes
    //            0,                 // use default stack size  
    //            ThreadProc,        // thread function 
    //            0,             // argument to thread function 
    //            0,                 // use default creation flags 
    //            &dwThreadId);   // returns the thread identifier
    
    while(true){
    	// Tesxtfarbe auf blau setzen
    	con.setTextColor(FG_BLUE);
    	// eine gnaze Zeile einlesen
    	getline(cin, buffer);
    	// Wenn exit eingegeben wird, beende die Eingabe und setze das Event
    	if(!strcmp(buffer.c_str(), "exit")){
    		SetEvent(hEvent);
    		buffer = "Partner hat den Chat verlassen";
    		Datei << buffer << endl;
    		while(!(nRet = send(hSock,&buffer[0],buffer.length(),0)));
    		break;
    	}
    	Datei << buffer << endl;
    	cout << "Daten senden" << endl;
    	// --- Daten senden -------------------
    	while(!(nRet = send(hSock,&buffer[0],buffer.length(),0)));
    }
    
    // --- Verbindung schliessen ----------
    nRet = shutdown(hSock,SD_BOTH);
    
    //DeleteCriticalSection(&CS);
    // --- Socket schliessen --------------
    nRet = closesocket(hSock);
    
    // --- Winsock deinitialisieren -------
    nRet = WSACleanup();
    
    // --- Winsock deinitialisieren -------
    nRet = WSACleanup();
    
    // Unendlich Warten bis der Thread ordnungsgemaes beendet wurde
    WaitForSingleObject(hThread, INFINITE);
    
    // Dateistream schließen
    Datei.close();
    
    return 0;
    }
    


  • Ceos schrieb:

    mal abgesehen davon, dein recv liefert entweder anzahl bytes oder 0 wenn verbindung getrennt oder -1 wenn fehler .... du solltest mal ne fehlerkontrolle einbauen und nicht einfach davon ausgehen das die verbindung schon irgendwie hinhaut.

    Hab jetzt sowas stehen

    nByte = recv(usocket,buffer,buffer_size,0);
    if(nByte < 0) cout << WSAGetLastError() ;
    

    Ich bekomme den Fehler 10093.
    Im help steht:

    Successful WSAStartup not yet performed.
    Either the application has not called WSAStartup or WSAStartup failed. The application may be accessing a socket that the current active task does not own (that is, trying to share a socket between tasks), or WSACleanup has been called too many times.

    Das scheint es zu sein was Probleme macht... und jetzt 😕



  • Du musst am Anfang deines Programms noch "WSAStartup()" aufrufen! Am Ende dann auch irgendwas zum aufräumen, bin mir aber nicht mehr sicher, evtl WSACleanUp, müsstest du aber auch bei der MSDN-Referenz zu WSAStartup finden 😉



  • Badestrand schrieb:

    Du musst am Anfang deines Programms noch "WSAStartup()" aufrufen! Am Ende dann auch irgendwas zum aufräumen, bin mir aber nicht mehr sicher, evtl WSACleanUp, müsstest du aber auch bei der MSDN-Referenz zu WSAStartup finden 😉

    Das hab ich aber in der main, das recv is ja oben drüber, vielleicht "findet" er deshalb das WSAStartup nicht.

    Wenn ich WSAStartup über den ThreadProc setze gibt er mir einen haufen Fehler, ich denke das muss in der main sein...



  • Oh, stimmt, entschuldige! Aber ich glaub ich habs: In deiner main rufst du WSACleanUp auf und dann wartest du auf die anderen Threads, heißt es wird aufgeräumt während die anderen Threads noch laufen. Mach das Cleanup einfach nach dem WaitForSingleObject.



  • Hey der Fehler ist weg, dafür hab ich jetzt folgenden bei recv:

    10038:
    Socket operation on nonsocket.
    An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.



  • Falls der gepostete Code noch aktuell ist, dann gehört shutdown () und closesocket () auch noch hinter WaitForSingleObject () und vor WSACleanup ().



  • Habs gelößt, war einiges falsch 🙄

    Danke an alle! 👍



  • werte den fehler bei deinem wsastartup doche einfach mal aus

    nRet = WSAStartup(wVersionRequested,&stWSAData);
    // Fehlerabfrage
    if(nRet < 0){
        cout << "Fehler bei WSAStartup";
        cout << WSAGetLastError(); //<----- so oder so ähnlich
    }
    

    EDIT: O_o ups da war ja noch ne seite 2 bei dem topic ... DAMN



  • MSDN:

    If successful, the WSAStartup function returns zero. Otherwise, it returns one of the error codes listed below.

    The WSAStartup function directly returns the extended error code in the return value for this function. A call to the WSAGetLastError function is not needed and should not be used.

    -> WSAGetLastError() sollte nicht benutzt werden bei WSAStartup(..).

    Simon



  • doppel autsch .... hast ja recht ... mittlerweilen kopier ich teile meines code nur noch, btw. hab mit ne tool lib angelegt und ruf einfach nur noch initWSA(); auf >_<


Anmelden zum Antworten