Parallelabläufe realisieren



  • Hallo Forum,

    erst mal möchte ich mich herzlich bedanken für die Antworten auf meine gestellten Fragen im letzten Thread (Socketprogrammierung)!!! 👍
    Ich mache das in diesem Thread, da der letzte mittlerweile ja schon überholt ist 🙂

    Nun noch eine Frage zu dem Ablauf eines Programms.

    Hierzu erst einmal wieder die zwei Dateien (mittlerweile etwas umgeschrieben):

    Server.cpp

    //Server.cpp
    
    #include <windows.h>
    #include <winsock.h>
    #include <iostream>
    
    using namespace std;
    
    //---------------------------------------------------------------------------------------------------||||Prototypen deklarieren
    
    int WinSockStart();
    
    int main()
    {
      long handle;
      SOCKET sock_main, sock_specified;
      SOCKADDR_IN server;
      char data_sent[300], data_received[300];
    
      memset(&server, 0, sizeof(SOCKADDR_IN));
    
      server.sin_family = AF_INET;
      server.sin_port = htons(12345);
      server.sin_addr.s_addr = ADDR_ANY;
    
    //---------------------------------------------------------------------------------------------------||||Vorarbeit für Socketnutzung erledigen
    
      handle = WinSockStart();
      if(handle == SOCKET_ERROR)
        cout << "Fehler! WinSockStart wurde nicht erfolgreich ausgeführt!" << '\n';
      else
        cout << "WinSock gestartet..." << '\n';
    
    //---------------------------------------------------------------------------------------------------||||Socket erstellen
    
      sock_main = socket(AF_INET, SOCK_STREAM, 0);
    
      if(sock_main == INVALID_SOCKET)
        cout << "Fehler! Socket konnte nicht erstellt werden!" << '\n';
      else
        cout << "Socket erstellt..." << '\n';
    
    //---------------------------------------------------------------------------------------------------||||Socket an Server binden
    
      handle = bind(sock_main, (SOCKADDR*)&server, sizeof(SOCKADDR));
    
      if(handle == SOCKET_ERROR)
        cout << "Fehler! Socket konnte nicht an den Server gebunden werden!" << '\n';
      else
        cout << "Socket wurde an den Server gebunden..." << '\n';
    
    //---------------------------------------------------------------------------------------------------||||Auf Kunden warten
    
      handle = listen(sock_main, 10);
    
      if(handle == SOCKET_ERROR)
        cout << "Fehler! Socketfunktion Listen konnte nicht richtig aufgerufen werden!" << '\n';
      else
        cout << "Server lauscht..." << '\n';  
    
    //---------------------------------------------------------------------------------------------------||||Entdeckte Kunden akzeptieren
    
      sock_specified = accept(sock_main, NULL, NULL);
    
      if(sock_specified == INVALID_SOCKET)
        cout << "Fehler! Server konnte nicht mit Client verbunden werden!" << '\n';
      else
      {
        cout << "Neue Verbindung akzeptiert..." << '\n' << '\n' << '\n' << '\n';
        cout << "---Chatbereich---" << '\n' << '\n' << '\n';
      }
    
    //---------------------------------------------------------------------------------------------------||||Daten senden & empfangen
    
      while(handle != SOCKET_ERROR)
      {
        handle = recv(sock_specified, data_received, 256, 0);
        if(handle == 0)
        {
          cout << "Gegenseite hat die Verbindung abgebrochen!" << '\n';
         break;
        }
        else if(handle == SOCKET_ERROR)
        {
          cout << "Fehler beim Empfangen von Datenpaketen!" << '\n';
         break;
        }
        data_received[handle] = '\0';
        cout << '\n' << "-> " << data_received << '\n';
        cout << "<- ";
        gets(data_sent);
        handle = send(sock_specified, data_sent, strlen(data_sent), 0);
      }
      closesocket(sock_main);
      closesocket(sock_specified);
      WSACleanup();
      system("pause>nul");
     return 0;
    }
    
    //---------------------------------------------------------------------------------------------------||||Funktionen
    
    int WinSockStart()
    {
      WSADATA wsa;
     return WSAStartup(MAKEWORD(2,2), &wsa);
    }
    

    Client.cpp

    //Client.cpp
    
    #include <winsock.h>
    #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    //---------------------------------------------------------------------------------------------------||||Prototypen deklarieren
    
    int WinSockStart();
    
    int main()
    {
      long handle;
      SOCKET sock;
      SOCKADDR_IN server;
      char data_sent[300], data_received[256];
    
      memset(&server, 0, sizeof(SOCKADDR_IN));
    
      server.sin_family = AF_INET;
      server.sin_port = htons(12345);
      server.sin_addr.s_addr = inet_addr("84.158.36.172");
    
    //---------------------------------------------------------------------------------------------------||||Vorarbeit für Socketnutzung erledigen
    
      handle = WinSockStart();
    
      if(handle == SOCKET_ERROR)
        cout << "Fehler! WinSockStart wurde nicht erfolgreich ausgeführt!" << '\n';
      else
        cout << "WinSock gestartet..." << '\n';
    
    //---------------------------------------------------------------------------------------------------||||Socket erstellen
    
      sock = socket(AF_INET, SOCK_STREAM, 0);
    
      if(sock == INVALID_SOCKET)
        cout << "Fehler! Socket konnte nicht erstellt werden!" << '\n';
      else
        cout << "Socket erstellt..." << '\n';
    
    //---------------------------------------------------------------------------------------------------||||Server kontaktieren
    
      handle = connect(sock, (SOCKADDR*)&server, sizeof(SOCKADDR));
    
      if(handle == SOCKET_ERROR)
        cout << "Fehler! Verbindung konnte nicht hergestellt werden!" << '\n';
      else
      {
        cout << "Verbindung hergestellt..." << '\n' << '\n' << '\n' << '\n';
        cout << "---Chatbereich---" << '\n' << '\n' << '\n';
      }
    
    //---------------------------------------------------------------------------------------------------||||Daten senden & empfangen
    
      while(handle != SOCKET_ERROR)
      {
        cout << "<- ";
        gets(data_sent);
        send(sock, data_sent, strlen(data_sent), 0);
        handle = recv(sock, data_received, 256, 0);
        if(handle == 0)
        {
          cout << "Gegenseite hat die Verbindung abgebrochen!" << '\n';
         break;
        }
        else if(handle == SOCKET_ERROR)
        {
          cout << "Fehler beim Empfangen von Datenpaketen!" << '\n';
         break;
        }
        data_received[handle] = '\0';
        cout << '\n' << "-> " << data_received << '\n';
      }
      system("pause>nul");
     return 0;
    }
    
    //---------------------------------------------------------------------------------------------------||||Funktionen
    
    int WinSockStart()
    {
      WSADATA wsa;
     return WSAStartup(MAKEWORD(2,2), &wsa);
    }
    

    Wer sich die zwei Dateien nun aufmerksam durchgelesen hat, wird schnell feststellen, dass man immer nur abwechelnd Server-Client-Server-Client schreiben kann, d.h der Client kann beispielsweise nicht 2 mal hintereinander schreiben, ohne dass der Server dazwischenfunken muss.
    Doch um zwei seperate while-Schleifen (eine fürs Empfangen, eine fürs Senden) laufen zu lassen, bräuchte ich doch so etwas wie einen Timer, oder mit Threads ist das anscheinend auch realisierbar, aber ich habe leider keine Ahnung wie! 😕

    In meinem Buch habe ich nach Threads sowie nach Timern "gegoogelt", jedoch erfolglos!

    Könnte mir da vielleicht jemand einen Lösungsansatz bringen?
    Wäre echt nett!

    Viele Grüße
    Gapa



  • In meinem Buch habe ich nach Threads sowie nach Timern "gegoogelt", jedoch erfolglos!

    Man kann in einem Buch nicht googeln 😉 .

    Für Threads erstellst du einfach Funktionen die du dann mit einem Thread aufrufst, dieser läuft dann parallel zu main Funktion.

    Unter Windows kannst du entweder mit CreateThread einen Thread erstellen -> http://msdn.microsoft.com/en-us/library/ms682453(VS.85).aspx
    Oder du verwendest Boost um gleich noch Plattforumübergreifend zu arbeiten, oder unter Linux POSIX Threads.

    Um die nächste Frage gleich schonmal vorweg zunehmen, mehrere Clients behandelst du auf dem Server mit select, mehr dazu gibts bei http://www.c-worker.ch/

    MFG ReduX

    P.S.: Ich habe die beiden Dateien nicht gelesen also vergib mir wenn du select schon eingebaut hast.



  • Hallo!

    Super vielen Dank für die Links!!! 👍

    Ok ich habe mir das in der MSDN mal angeschaut und versucht, in mein Script einzubauen:

    Server.cpp

    //Server.cpp
    
    #include <windows.h>
    #include <process.h>
    #include <winsock.h>
    #include <iostream>
    
    using namespace std;
    
    //---------------------------------------------------------------------------------------------------||||Prototypen deklarieren
    
    int WinSockStart();
    DWORD WINAPI thread_send(LPVOID);
    DWORD WINAPI thread_receive(LPVOID);
    
    long handle;
    SOCKET sock_main, sock_specified;
    
    int main()
    {
      SOCKADDR_IN server;
    
      memset(&server, 0, sizeof(SOCKADDR_IN));
    
      server.sin_family = AF_INET;
      server.sin_port = htons(12345);
      server.sin_addr.s_addr = ADDR_ANY;
    
    //---------------------------------------------------------------------------------------------------||||Vorarbeit für Socketnutzung erledigen
    
      handle = WinSockStart();
      if(handle == SOCKET_ERROR)
        cout << "Fehler! WinSockStart wurde nicht erfolgreich ausgeführt!" << '\n';
      else
        cout << "WinSock gestartet..." << '\n';
    
    //---------------------------------------------------------------------------------------------------||||Socket erstellen
    
      sock_main = socket(AF_INET, SOCK_STREAM, 0);
    
      if(sock_main == INVALID_SOCKET)
        cout << "Fehler! Socket konnte nicht erstellt werden!" << '\n';
      else
        cout << "Socket erstellt..." << '\n';
    
    //---------------------------------------------------------------------------------------------------||||Socket an Server binden
    
      handle = bind(sock_main, (SOCKADDR*)&server, sizeof(SOCKADDR));
    
      if(handle == SOCKET_ERROR)
        cout << "Fehler! Socket konnte nicht an den Server gebunden werden!" << '\n';
      else
        cout << "Socket wurde an den Server gebunden..." << '\n';
    
    //---------------------------------------------------------------------------------------------------||||Auf Kunden warten
    
      handle = listen(sock_main, 10);
    
      if(handle == SOCKET_ERROR)
        cout << "Fehler! Socketfunktion Listen konnte nicht richtig aufgerufen werden!" << '\n';
      else
        cout << "Server lauscht..." << '\n';  
    
    //---------------------------------------------------------------------------------------------------||||Entdeckte Kunden akzeptieren
    
      sock_specified = accept(sock_main, NULL, NULL);
    
      if(sock_specified == INVALID_SOCKET)
        cout << "Fehler! Server konnte nicht mit Client verbunden werden!" << '\n';
      else
      {
        cout << "Neue Verbindung akzeptiert..." << '\n' << '\n' << '\n' << '\n';
        cout << "---Chatbereich---" << '\n' << '\n' << '\n';
      }
    
    //---------------------------------------------------------------------------------------------------||||Daten senden & empfangen
      HANDLE thread_handle1 = CreateThread(NULL, 0, thread_send, 0, 0, 0);
      HANDLE thread_handle2 = CreateThread(NULL, 0, thread_receive, 0, 0, 0);
      WaitForSingleObject(thread_handle1, INFINITE);
      WaitForSingleObject(thread_handle2, INFINITE);
      closesocket(sock_main);
      closesocket(sock_specified);
      WSACleanup();
      system("pause>nul");
     return 0;
    }
    
    //---------------------------------------------------------------------------------------------------||||Funktionen
    
    int WinSockStart()
    {
      WSADATA wsa;
     return WSAStartup(MAKEWORD(2,2), &wsa);
    }
    
    void thread_send()
    {
      char data_sent[300];
      while(handle != SOCKET_ERROR)
      {
        cout << "<- ";
        gets(data_sent);
        handle = send(sock_specified, data_sent, strlen(data_sent), 0);
      }
    }
    
    void thread_receive()
    {
      char data_received[300];
      while(handle != SOCKET_ERROR)
      {
        handle = recv(sock_specified, data_received, 256, 0);
        if(handle == 0)
        {
          cout << "Gegenseite hat die Verbindung abgebrochen!" << '\n';
         break;
        }
        else if(handle == SOCKET_ERROR)
        {
          cout << "Fehler beim Empfangen von Datenpaketen!" << '\n';
         break;
        }
        data_received[handle] = '\0';
        cout << '\n' << "-> " << data_received << '\n';
      }
    }
    

    1. Ist das der richtige Weg?

    2. Mein Linker spuckt folgende Fehlermeldungen aus:

    [Linker error] undefined reference to \_Z11thread\_sendPv@4' [Linker error] undefined reference to_Z14thread_receivePv@4'
    ld returned 1 exit status
    C:\*****\Makefile.win [Build Error] [Server.exe] Error 1

    Welche Dateien muss ich noch mit einincludieren??

    Aber noch viel wichtiger wäre mir eine Antwort auf Frage 1!
    Ist mein Gedankengang hier richtig, oder würde dieses Script nicht laufen, wie es soll??

    Man kann in einem Buch nicht googeln

    Ja das weiß ich auch 😃 - deswegen ja die ""!

    Viele Grüße
    Gapa



  • 1.) Im Prinzip würde es gehen, aber der Server würde sich schließen sobald der Kunde disconnected.

    zu 2.) Ein heller Satz aus der msdn: Do not declare this callback function with a void return type and cast the function pointer to LPTHREAD_START_ROUTINE when creating the thread. Code that does this is common, but it can crash on 64-bit Windows.

    Das heißt schonmal das die Threads so gestartet werden:

    HANDLE thread_handle1 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&thread_send, 0, 0, 0);
      HANDLE thread_handle2 = CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)&thread_receive, 0, 0, 0);
    

    Des weiteren hast du die beiden Funktionen so definiert:

    DWORD WINAPI thread_send(LPVOID);
    DWORD WINAPI thread_receive(LPVOID);
    

    Das sollte man dann halt auch unten schreiben und nicht void thread_send();

    Ich würde dir aber raten wenn du mit Socket arbeitest das du die in eine Klasse packst, glaub mir das hat viele Vorteile. Musste nur schauen wegen den Threads da die WinAPI für C ist, unterstützen die keine Klassen. Muss man halt en bisschen rumhacken oder bis nächstes Jahr warten.

    MFG ReduX



  • Dieser Thread wurde von Moderator/in HumeSikkins 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.


Anmelden zum Antworten