# Hilfe bei der Umleitung der Konsolenausgabe...



## partitionist (7. September 2006)

Hallo Leute,

ich habe eine Art RPC Projekt (Konsole) erstellt, d.h. man kann im Netzwerk/LAN von einem Client Befehle zum Server senden, der diese dann ausführt. In dem Projekt sind mehrere System Tools in Form von *.exe Dateien wie z.B. *kill.exe* (Schließt Prozesse), *info.exe* (Ausgabe von System Infos), *proc.exe* (Ausgabe von Prozessen),* user.exe*, ...
Diese Tools und der Client/Server befinden sich im gleichen Ordner. 

*Beispiel:*
Auf dem PC1 läuft der Client.
Auf dem PC2 läuft der Server.

*Ablauf:*
Jetzt baue ich eine Verbindung mit dem Client zum Server auf. Soabald dies geschehen ist, kann ich in der Konsole des Clients Befehle wie kill, info, proc,... übergeben/senden. Der Server startet mit system(BEFEHL) alle übegebenen Befehle die in dem gleichen Ordner sind. 
Beispiel: Soabald der Befehl info übegeben wird, startet der Server die *info.exe *im gleichen Ordner und führt sie aus, und es erscheint beim Server die Ausgabe von info.

*Problem:*
Wie bekommt man die Ausgabe vom Server übers Netzwerk umgeleitet?
Also wie in dem obigen Beispiel mit info, die Ausgabe von *info.exe* möchte ich nur im Client sehen.

Hab mich hier im Forum umgeschaut und es gab ein ähnliches Thema aber keine Lösung: http://www.tutorials.de/forum/c-c/244182-cmd-steuern.html?highlight=pipes


Hier mein Client/Server

Client:

```
#include <stdlib.h> 
#include <stdio.h> 
#include <windows.h> 
#include <winsock.h> 
#include <conio.h> 
#include <string>
#include <iostream>
#include <sstream>
#include <cstdio> 
#include <vector>

using namespace std;

#pragma comment(lib,"wsock32.lib")


// Startet Winsock und gibt einige Infos zur Version aus 
// Starts winsock and dumps some infos about the version 
int startWinsock() 
{ 
   int rc; 
   WSADATA wsaData; 
   rc=WSAStartup(MAKEWORD(2,0),&wsaData); 
   
   if(rc==SOCKET_ERROR) 
   { 
      printf("Error, exiting!\n"); 
      return rc; 
   }  
   printf("System Status: %s\n",wsaData.szSystemStatus); 
   return 0; 
} 

// Sucht eine IP anhand eines Strings, der entweder die IP als String 
// oder einen Hostname enthalten kann 
long getAddrFromString(char* hostnameOrIp, SOCKADDR_IN* addr) 
{ 
   long rc; 
   unsigned long ip; 

   HOSTENT* he; 

   if(hostnameOrIp==NULL || addr==NULL) 
      return SOCKET_ERROR; 
   ip=inet_addr(hostnameOrIp); 

   if(ip!=INADDR_NONE)
   { 
      addr->sin_addr.s_addr=ip; 
      return 0; 
   } 
   else 
   { 
      he=gethostbyname(hostnameOrIp); 
      if(he==NULL) 
      { 
         return SOCKET_ERROR; 
      } 
      else 
      { 
         memcpy(&(addr->sin_addr),he->h_addr_list[0],4); 
      } 
      return 0; 
   } 
} 

int main(int argc, char* argv[]) 
{ 
    if(argc > 2)
    {
        char* HOST = argv[1];
        int PORT = atoi(argv[2]);

        SOCKET s; 
        SOCKADDR_IN addr; 
        char c; 
        char buf[1024]; 
        char inpBuf[1024]; 
        int inpBufPos=0; 
        fd_set fdSetRead; 
        TIMEVAL timeout; 
        int rc; 


        // start winsock 
        rc=startWinsock(); 
        if(rc==SOCKET_ERROR) 
        return 1; 

        // addr vorbereiten, hostname auflösen 
        // prepare addr, resolve hostname 
        memset(&addr,0,sizeof(SOCKADDR_IN)); 
        addr.sin_family=AF_INET; 
        addr.sin_port=htons(PORT); 
        rc=getAddrFromString(HOST, &addr); 
        if(rc==SOCKET_ERROR) 
        { 
        printf("Error: Cannot resolve Host %s\n", HOST); 
        return 1; 
        } 

        // socket erstellen 
        // create socket 
        s=socket(PF_INET,SOCK_STREAM,0); 
        if(s==INVALID_SOCKET) 
        { 
        printf("Error, cannot create socket: %d\n",WSAGetLastError()); 
        return 1; 
        } 

        // verbinden.. 
        // connect.. 
        printf("Connecting...\n"); 
        rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR)); 
        if(rc==SOCKET_ERROR) 
        { 
        printf("Error: connect failed: %d\n",WSAGetLastError()); 
        return 1; 
        } 

        printf("\n"); 
        
        string str; //Eingabe String

        do
        {
            cout << "Eingabe:";
            getline(cin, str);

            if(str == "exit")
            {
                closesocket(s); 
                WSACleanup(); 
                return 0;
            }

            else if(str == "close")
            {
                rc=send(s,str.c_str(),strlen(str.c_str()),0); 
                closesocket(s); 
                WSACleanup(); 
                return 0;
            }

        
            //cout << "send->" << str << endl;
            rc=send(s,str.c_str(),strlen(str.c_str()),0); 

            
            // fd_set und timeout vorbereiten 
            // prepare fd_set and timeout 
            FD_ZERO(&fdSetRead); 
            FD_SET(s,&fdSetRead); 
            timeout.tv_sec=0; 
            timeout.tv_usec=0; 

            // prüfen ob ein socket bereit ist, da timeout=0 kehrt die funktion 
            // sofort wieder zurück nach dem aufruf. 
            // achtung: das timeout auf 0 setzen oder als paremeter NULL mitgeben 
            // ist NICHT das gleiche. auf 0 gesetzt kehrt sofort zurück, während 
            // NULL blockt. 
            // check if any socket is ready (timeout=0, the function returns without delay) 
            while((rc=select(0,&fdSetRead,NULL,NULL,&timeout))>0) 
            { 
                rc=recv(s,buf,1023,0); 
                // server hat die verbindung beendet ? 
                // server closed connection ? 
                if(rc==0) 
                { 
                    printf("Server closed connection!\n"); 
                    return 1; 
                // fehler: beenden! 
                // error: abort! 
                } else if(rc==SOCKET_ERROR) 
                { 
                    printf("Error: recv failed: %d\n",WSAGetLastError()); 
                    return 1; 
                } 
                // empfangene daten ausgeben 
                // print received data 
                buf[rc]='\0'; 
                printf("%s\n",buf); 
            } 
    

        }while(rc!=SOCKET_ERROR);//Ende do-while

        // aufräumen 
        // cleanup.. 
        closesocket(s); 
        WSACleanup(); 
        printf("Client shutdown, press any key to exit\n"); 
        getch(); 

       }
       else    
       {
           cout << "Client HOST PORT" << endl;
       }
       return 0; 

}
```


Server:

```
// max. Anzahl Clients 
// Max. number of clients 
#define MAX_CLIENTS 100 


// Der Standartwert für FD_SETSIZE ist 64, dieser kann aber verändert 
// werden indem man FD_SETSIZE auf einen anderen Wert setzt bevor man 
// winsock2.h includiert. 
// FD_SETSIZE auf die max. Anzahl Clients setzten 
#define FD_SETSIZE   MAX_CLIENTS 

// includes... 
#include <stdlib.h> 
#include <stdio.h> 
#include <windows.h> 
#include <winsock.h> 
#include <conio.h> 
#include <string>
#include <iostream>
#include "convert.h"
#include "registry.h"

#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "advapi32.lib") 

using namespace std;

// Stellt eine Verbindung mit einem Client dar 
// Represents a connection with a Client 
struct Connection 
{ 
   Connection() 
   { 
      used=false; 
      socket=INVALID_SOCKET; 
   } 
   void set(SOCKET s, SOCKADDR_IN addr) 
   { 
      this->socket=s; 
      this->addr=addr; 
      this->used=true; 
   } 
   void erase() 
   { 
      this->used=false; 
      this->socket=INVALID_SOCKET; 
   } 
   bool used;   // connection benutzt ? / connection slot used ? 
   SOCKET socket; // socket 
   SOCKADDR_IN addr; // client addr 
}; 

// clients 
Connection clients[MAX_CLIENTS]; 

// Sucht den nächsten freien Platz im clients Array 
// -1 = kein platz frei 
// Searches the next free slot in the clients array 
// -1 = no free slot 
int getFreeClientSlot() 
{ 
   for(int i=0;i<MAX_CLIENTS;i++) 
   { 
      if(clients[i].used==false) 
         return i; 
   } 
   return -1; 
} 

// Sendet eine Nachricht an alle Clients 
// Send's a Message to all clients 
int sendToAllClients(char* msg) 
{ 
   int rc,i; 
   for(i=0;i<MAX_CLIENTS;i++) 
   { 
      if(!clients[i].used) 
         continue; 
      rc=send(clients[i].socket,msg,strlen(msg),0); 
      if(rc==SOCKET_ERROR) 
      { 
         printf("Error: Sending to Client %d failed: %d\n",i,WSAGetLastError()); 
      } 
   } 
   return 0; 
} 

// Startet Winsock und gibt einige Infos zur Version aus 
// Starts winsock and dumps some infos about the version 
int startWinsock() 
{ 
   int rc; 
   WSADATA wsaData; 
   rc=WSAStartup(MAKEWORD(2,0),&wsaData); 
   
   if(rc==SOCKET_ERROR) { 
      printf("Error, exiting!\n"); 
      return rc; 
   }   
   printf("System Status: %s\n",wsaData.szSystemStatus); 
   return 0; 
} 

int main(int argc, char* argv[]) 
{ 
    if(argc > 1)
    {
        //Startet auf dem übergebenem PORT
        int PORT = atoi(argv[1]);
    
       // SOCKET welcher neue Verbindungen annimmt 
       // SOCKET which accepts new connections 
       SOCKET acceptSocket; 
       SOCKADDR_IN addr; 
       int rc,addrsize=sizeof(SOCKADDR_IN); 
       unsigned int i,j; 
       // fd_set 
       fd_set fdSetRead; 
       // timout für select() / timeout for select() 
       timeval selectTimeout; 
       // temporär benutz für neue verbindungen 
       // temporary used for new connections 
       Connection newConnection; 
       // buffer 
       char buf[1024]; 

       // clients array leeren / clear clients array 
       memset(clients,0x0,sizeof(Connection)*MAX_CLIENTS); 

       // start winsock 
       rc=startWinsock(); 
       if(rc==SOCKET_ERROR) 
          return 1; 

       // socket erstellen / create socket 
       acceptSocket=socket(PF_INET,SOCK_STREAM,0); 
       if(acceptSocket==INVALID_SOCKET) 
       { 
          printf("Error, cannot create socket: %d\n",WSAGetLastError()); 
          return 1; 
       } 

       // sockt an port 1234 binden / bind socket to port 1234 
       memset(&addr,0,sizeof(SOCKADDR_IN)); 
       addr.sin_family=AF_INET; 
       addr.sin_port=htons(PORT); 
       addr.sin_addr.s_addr=INADDR_ANY; 
       rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN)); 
        if(rc==SOCKET_ERROR) 
        { 
          printf("Error, bind() failed: %d\n",WSAGetLastError()); 
          return 1; 
       } 

       // auf verbindungen warten / listen for connections 
       rc=listen(acceptSocket,10); 
       if(rc==SOCKET_ERROR) 
       { 
          printf("Error,listen() failed: %d\n",WSAGetLastError()); 
          return 1; 
       } 


       // The parameter readfds identifies the sockets that are to be checked for readability. 
       // If the socket is currently in the listen state, it will be marked as readable if an 
       // incoming connection request has been received such that an accept is guaranteed to 
       // complete without blocking. 
        
       while(1) 
       { 

          // fd_set leeren / clear fd_set 
          FD_ZERO(&fdSetRead); 
           
          // den socket welcher verbindungen annimmt hinzufügen 
          // add the SOCKET which accepts new connections 
           
          FD_SET(acceptSocket,&fdSetRead); 
          // alle clients hinzufügen 
          // add all clients 
          for(i=0;i<MAX_CLIENTS;i++) 
          { 
             if(clients[i].used) 
                FD_SET(clients[i].socket,&fdSetRead); 
          } 

          // warten bis irgend ein socket bereit ist, wenn timout NULL ist kehrt select() 
          // erst zurück wenn ein socket bereit ist, select() blockt also in diesem falle 
          // wait until any socket is ready (timeout = NULL, block until one socket is ready) 
          rc=select(0,&fdSetRead,NULL,NULL,NULL); 

          // abbrechen bei einem fehler 
          // break on error 
          if(rc<1) 
             break; 

          printf("select() returned %d ready sockets\n",rc); 
           
          for(i=0;i<fdSetRead.fd_count;i++) 
          { 
           
             // acceptSocket ? 
             if(fdSetRead.fd_array[i]==acceptSocket) 
             { 
                // verbindung annehmen / accept new connection 
                newConnection.socket=accept(acceptSocket,(SOCKADDR*)&newConnection.addr,&addrsize); 
                rc=getFreeClientSlot(); 
                if(rc==-1) 
                { 
                   printf("Cannot accept new clients\n"); 
                   continue; 
                } 
                // zu den clients hinzufügen 
                // add to clients 
                clients[rc]=newConnection; 
                clients[rc].used=true; 
                printf("New Client accepted from %s\n",inet_ntoa(newConnection.addr.sin_addr)); 
                continue; 
             } 
              
             // ein client ? 
             // a client ? 
             for(j=0;j<MAX_CLIENTS;j++) 
             { 
                if(!clients[j].used) 
                   continue; 

                if(clients[j].socket==fdSetRead.fd_array[i]) 
                { 
                   rc=recv(clients[j].socket,buf,1023,0); 
                   buf[rc]='\0'; 
                   // rc==0 => client hat die verbindung beendet 
                   // rc==0 => client closed connection 
                   if(rc==0) { 
                      printf("Client %d (%s): closed connection\n",j,inet_ntoa(clients[j].addr.sin_addr)); 
                      closesocket(clients[j].socket); 
                      clients[j].erase(); 
                      continue; 
                   // rc==SOCKET_ERROR => fehler, verbindung beenden! 
                   // rc==SOCKET_ERROR => error, close connection! 
                   } 
                   else if(rc==SOCKET_ERROR) 
                   { 
                      printf("Client %d (%s): Error %d\n",j,inet_ntoa(clients[j].addr.sin_addr),WSAGetLastError()); 
                        printf("Client %d (%s): Server aborts connection\n",j,inet_ntoa(clients[j].addr.sin_addr)); 
                      closesocket(clients[j].socket); 
                      clients[j].erase(); 
                      continue; 
                   // daten empfangen und an alle clients senden 
                   // receive data and send it to all clients 
                   } 
                   else 
                   { 
                      printf("Client %d (%s): received '%s' \n",j,inet_ntoa(clients[j].addr.sin_addr),buf); 
                      //sendToAllClients(buf); 
                      
                      string command = buf;
                      int pos = command.find(' ');   
                      int lang = command.length();
                        string task = command.substr(0,pos);
                      string para = command.substr(pos+1,lang);
                

                      if(task == "close")
                      {
                          //rc=send(clients[i].socket,msg,strlen(msg),0); 
                          rc=send(clients[j].socket,task.c_str(),strlen(task.c_str()),0); 
                            closesocket(acceptSocket); 
                            WSACleanup(); 
                      }    
                      else
                      {
                          string str;
                          str += '"';
                          str += reg.xmd_GetValue("bin");
                          str += "\\";
                          str += task;
                          str += '"';
                          str += " ";
                          str += para;

                          cout << "exec:" << str << endl;
                          system(str.c_str());  //  <<--------- Hier werden die Befehle ausgeführt.
                      }
                      
                   } 
                } 
             } 
          }
          cout << "-----------------------------------" << endl;
       }//Ende while

       // aufräumen 
       // cleanup 
       closesocket(acceptSocket); 
       WSACleanup();        
    }
    else 
    {
        cout << "server PORT" << endl;
    }
        return 0;
   
}
```


----------



## jokey2 (7. September 2006)

Dazu solltest Du das Dienstprogramm nicht mit 'system' sondern mit 'CreateProcess' starten. Damit hast Du die Möglichkeit, die Ausgabe mittels einer Pipe umzuleiten. Diese verhalten sich dann wie Dateien, Du kannst also aus ihnen lesen bzw. in sie schreiben. Diese gelesenen Daten kannst Du dann wieder an den Client schicken.


----------



## partitionist (7. September 2006)

Vielen Dank für den Tipp

Hab auf die schnelle im Server statt system() jetzt CreateProcess() eingefügt:


> //Befehle einlesen...
> 
> STARTUPINFO siStartupInfo;
> PROCESS_INFORMATION piProcessInfo;
> ...



Doch wie mache ich jetzt weiter?
Wie oder woher bekomme ich jetzt die Daten
Wie sende ich die Daten mit send()?


----------



## partitionist (7. September 2006)

Hab ein Code gefunden mit CreateProcess() + Pipes():

```
CString ExecuteExternalFile(CString csExeName, CString csArguments)
{
  CString csExecute;
  csExecute=csExeName + " " + csArguments;
  
  SECURITY_ATTRIBUTES secattr; 
  ZeroMemory(&secattr,sizeof(secattr));
  secattr.nLength = sizeof(secattr);
  secattr.bInheritHandle = TRUE;

  HANDLE rPipe, wPipe;

  //Create pipes to write and read data
  CreatePipe(&rPipe,&wPipe,&secattr,0);
  //
  STARTUPINFO sInfo; 
  ZeroMemory(&sInfo,sizeof(sInfo));
  PROCESS_INFORMATION pInfo; 
  ZeroMemory(&pInfo,sizeof(pInfo));
  sInfo.cb=sizeof(sInfo);
  sInfo.dwFlags=STARTF_USESTDHANDLES;
  sInfo.hStdInput=NULL; 
  sInfo.hStdOutput=wPipe; 
  sInfo.hStdError=wPipe;
  char command[1024]; strcpy(command,  
          csExecute.GetBuffer(csExecute.GetLength()));

  //Create the process here.
  CreateProcess(0 command,0,0,TRUE,
          NORMAL_PRIORITY_CLASS|CREATE_NO_WINDOW,0,0,&sInfo,&pInfo);
  CloseHandle(wPipe);

  //now read the output pipe here.
  char buf[100];
  DWORD reDword; 
  CString m_csOutput,csTemp;
  BOOL res;
  do
  {
                  res=::ReadFile(rPipe,buf,100,&reDword,0);
                  csTemp=buf;
                  m_csOutput+=csTemp.Left(reDword);
  }while(res);
  return m_csOutput;
}
```

Ist der Code das Richtige für die Lösung meines Problems ?


----------



## jokey2 (8. September 2006)

Hier habe ich eion Beispiel, wie ich das mal gemacht habe. Es gibt da bestimmt noch elegentere Lösungen (z.B. mit Exceptions statt der goto's. Das ist tatsächlich der einzige Fall, wo ich goto überhaupt verwendet habe.), aber es zeigt die grundsätzliche Vorgehensweise mit CreateProcess und Pipes.


```
BOOL CProcessingClass::ProcessCommandLine(char * pcCommandLine)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    HANDLE hReadPipe, hWritePipe;
    DWORD dwWaitResult = WAIT_TIMEOUT, dwBytesRead, dwExitCode, dwSizeLow, dwSizeHigh, dwError;
    char cReadLine[MAX_LINE_LENGTH];
    BOOL bDoRead = TRUE, bOK = TRUE;
    MSG AppMsg;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);


    //Pipes erzeugen
    sa.nLength=sizeof(sa);
    sa.bInheritHandle=TRUE;
    sa.lpSecurityDescriptor=NULL;
    bOK = CreatePipe(&hReadPipe, &hWritePipe, &sa, 1048576);
    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        theApp.m_Log.LogErrorMessage(dwError, pCommand);
        bOK = FALSE;
        goto PROCESS_END_NOPIPE;
    }

    //Pipes eintragen
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    si.hStdOutput = hWritePipe;                        //Schreib-Ende der Pipe an Prozess übergeben
    si.hStdError = hWritePipe;                        //Schreib-Ende der Pipe an Prozess übergeben
    si.wShowWindow = SW_SHOWMINNOACTIVE;

    //Prozess starten
    bOK = CreateProcess(NULL,
                        pcCommandLine,
                        NULL,
                        NULL,
                        TRUE,
                        NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
                        lpEnvironment,
                        pCommand->m_cstrExecuteDir,
                        &si,
                        &pi);

    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        goto PROCESS_END_NOPROC;
    }

    //Auf Ende warten und Messages lesen
    while(dwWaitResult != WAIT_OBJECT_0)
    {
        dwWaitResult = WaitForSingleObject(pi.hProcess, 10);
        while(dwSizeLow = GetFileSize(hReadPipe, &dwSizeHigh))
        {
            ZeroMemory(cReadLine, MAX_LINE_LENGTH);
            //Aus dem Leseende der Pipe die Progzessausgaben lesen
            if(bDoRead = ReadFile(hReadPipe, cReadLine, MAX_LINE_LENGTH - 1, &dwBytesRead, NULL))
            {
                if(dwBytesRead)
                {
                    //hier Programmausgabe verarbeiten (z.B. send)
                }
            }
            else
            {
                bOK = FALSE;
                dwError = GetLastError();
            }
        }
        //Applikations-Messagequeue verarbeiten
        if(PeekMessage(&AppMsg, 0, 0, 0, PM_NOREMOVE))
        {
            GetMessage(&AppMsg, 0, 0, 0);
            TranslateMessage(&AppMsg);
            DispatchMessage(&AppMsg);
        }
    }

    if(bOK)
    {
        bOK = GetExitCodeProcess(pi.hProcess, &dwExitCode);
        if(bOK)
        {
            if(dwExitCode != 0)
            {
                //Prozess kehrt mit Ergebnis != 0 zurück
                bOK = FALSE;
            }
        }
        else
        {
            //FEHLER im GetExitCodeProcess
            dwError = GetLastError();
            bOK = FALSE;
        }
    }

    //Close handles
    m_hRunningProcess = NULL;
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

PROCESS_END_NOPROC:
    CloseHandle(hWritePipe);
    CloseHandle(hReadPipe);

PROCESS_END_NOPIPE:
    return bOK;
}
```


----------



## partitionist (8. September 2006)

Vielen Dank Jokey2,

ist das ein MFC Code, denn bei mir werden 9 Fehler gezeigt mit nicht "deklarierten Bezeichner". Haste du ne Klasse geschrieben


----------



## jokey2 (8. September 2006)

Ja, das ist Code aus einer MFC-Applikation. Offensichtlich habe ich ein paar Sachen vergessen zu löschen ;-).
Das Error-Logging (Zeile 25 im Listing) mußt Du rausschmeißen.
Das Message-Handling kannst Du evtl, auch weglassen, obwohl das kein MFC ist.
Poste doch mal, was sonst nicht gefunden wird.


----------



## partitionist (8. September 2006)

Habe jetzt 5 Fehler:



> error C2065: 'MAX_LINE_LENGTH': nichtdeklarierter Bezeichner
> error C2065: 'lpEnvironment': nichtdeklarierter Bezeichner
> error C2065: 'pCommand': nichtdeklarierter Bezeichner
> error C2227: Links von "->m_cstrExecuteDir" muss sich ein Zeiger auf Klassen-/Struktur-/Union-/generischen Typ befinden.
> error C2065: 'm_hRunningProcess': nichtdeklarierter Bezeichner


----------



## jokey2 (8. September 2006)

'MAX_LINE_LENGTH' mußt du definieren, das bezeichnet nur die Größe des Lesepuffers (bei mir 1024 Bytes)
Für 'lpEnvironment' und 'pCommand->m_cstrExecuteDir' kannst Du im CreateProcess-Aufruf NULL einsetzen.
die Zeile mit 'm_hRunningProcess' kannst Du löschen

Sieht dann so aus (Ich hoffe, ich habe nicht noch was übersehen):

```
#define MAX_LINE_LENGTH 1024

BOOL CProcessingClass::ProcessCommandLine(char * pcCommandLine)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    HANDLE hReadPipe, hWritePipe;
    DWORD dwWaitResult = WAIT_TIMEOUT, dwBytesRead, dwExitCode, dwSizeLow, dwSizeHigh, dwError;
    char cReadLine[MAX_LINE_LENGTH];
    BOOL bDoRead = TRUE, bOK = TRUE;
    MSG AppMsg;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);


    //Pipes erzeugen
    sa.nLength=sizeof(sa);
    sa.bInheritHandle=TRUE;
    sa.lpSecurityDescriptor=NULL;
    bOK = CreatePipe(&hReadPipe, &hWritePipe, &sa, 1048576);
    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        bOK = FALSE;
        goto PROCESS_END_NOPIPE;
    }

    //Pipes eintragen
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    si.hStdOutput = hWritePipe;                        //Schreib-Ende der Pipe an Prozess übergeben
    si.hStdError = hWritePipe;                        //Schreib-Ende der Pipe an Prozess übergeben
    si.wShowWindow = SW_SHOWMINNOACTIVE;

    //Prozess starten
    bOK = CreateProcess(NULL,
                        pcCommandLine,
                        NULL,
                        NULL,
                        TRUE,
                        NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
                        NULL,
                        NULL,
                        &si,
                        &pi);

    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        goto PROCESS_END_NOPROC;
    }

    //Auf Ende warten und Messages lesen
    while(dwWaitResult != WAIT_OBJECT_0)
    {
        dwWaitResult = WaitForSingleObject(pi.hProcess, 10);
        while(dwSizeLow = GetFileSize(hReadPipe, &dwSizeHigh))
        {
            ZeroMemory(cReadLine, MAX_LINE_LENGTH);
            //Aus dem Leseende der Pipe die Progzessausgaben lesen
            if(bDoRead = ReadFile(hReadPipe, cReadLine, MAX_LINE_LENGTH - 1, &dwBytesRead, NULL))
            {
                if(dwBytesRead)
                {
                    //hier Programmausgabe verarbeiten (z.B. send)
                }
            }
            else
            {
                bOK = FALSE;
                dwError = GetLastError();
            }
        }
        //Applikations-Messagequeue verarbeiten
        if(PeekMessage(&AppMsg, 0, 0, 0, PM_NOREMOVE))
        {
            GetMessage(&AppMsg, 0, 0, 0);
            TranslateMessage(&AppMsg);
            DispatchMessage(&AppMsg);
        }
    }

    if(bOK)
    {
        bOK = GetExitCodeProcess(pi.hProcess, &dwExitCode);
        if(bOK)
        {
            if(dwExitCode != 0)
            {
                //Prozess kehrt mit Ergebnis != 0 zurück
                bOK = FALSE;
            }
        }
        else
        {
            //FEHLER im GetExitCodeProcess
            dwError = GetLastError();
            bOK = FALSE;
        }
    }

    //Close handles
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

PROCESS_END_NOPROC:
    CloseHandle(hWritePipe);
    CloseHandle(hReadPipe);

PROCESS_END_NOPIPE:
    return bOK;
}
```


----------



## partitionist (8. September 2006)

Vielen Dank. 

So funktionierts:

```
#include <windows.h>
#include <iostream>

using namespace std;

#define MAX_LINE_LENGTH 1024

#pragma comment(lib,"user32.lib")

BOOL ProcessCommandLine(char * pcCommandLine)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    HANDLE hReadPipe, hWritePipe;
    DWORD dwWaitResult = WAIT_TIMEOUT, dwBytesRead, dwExitCode, dwSizeLow, dwSizeHigh, dwError;
    char cReadLine[MAX_LINE_LENGTH];
    BOOL bDoRead = TRUE, bOK = TRUE;
    MSG AppMsg;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);


    //Pipes erzeugen
    sa.nLength=sizeof(sa);
    sa.bInheritHandle=TRUE;
    sa.lpSecurityDescriptor=NULL;
    bOK = CreatePipe(&hReadPipe, &hWritePipe, &sa, 1048576);
    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        bOK = FALSE;
        goto PROCESS_END_NOPIPE;
    }

    //Pipes eintragen
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    si.hStdOutput = hWritePipe;                        //Schreib-Ende der Pipe an Prozess übergeben
    si.hStdError = hWritePipe;                        //Schreib-Ende der Pipe an Prozess übergeben
    si.wShowWindow = SW_SHOWMINNOACTIVE;

    //Prozess starten
    bOK = CreateProcess(NULL,
                        pcCommandLine,
                        NULL,
                        NULL,
                        TRUE,
                        NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
                        NULL,
                        NULL,
                        &si,
                        &pi);

    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        goto PROCESS_END_NOPROC;
    }

    //Auf Ende warten und Messages lesen
    while(dwWaitResult != WAIT_OBJECT_0)
    {
        dwWaitResult = WaitForSingleObject(pi.hProcess, 10);
        while(dwSizeLow = GetFileSize(hReadPipe, &dwSizeHigh))
        {
            ZeroMemory(cReadLine, MAX_LINE_LENGTH);
            //Aus dem Leseende der Pipe die Progzessausgaben lesen
            if(bDoRead = ReadFile(hReadPipe, cReadLine, MAX_LINE_LENGTH - 1, &dwBytesRead, NULL))
            {
                if(dwBytesRead)
                {
                    //hier Programmausgabe verarbeiten (z.B. send)
                }
            }
            else
            {
                bOK = FALSE;
                dwError = GetLastError();
            }
        }
        //Applikations-Messagequeue verarbeiten
        if(PeekMessage(&AppMsg, 0, 0, 0, PM_NOREMOVE))
        {
            GetMessage(&AppMsg, 0, 0, 0);
            TranslateMessage(&AppMsg);
            DispatchMessage(&AppMsg);
        }
    }

    if(bOK)
    {
        bOK = GetExitCodeProcess(pi.hProcess, &dwExitCode);
        if(bOK)
        {
            if(dwExitCode != 0)
            {
                //Prozess kehrt mit Ergebnis != 0 zurück
                bOK = FALSE;
            }
        }
        else
        {
            //FEHLER im GetExitCodeProcess
            dwError = GetLastError();
            bOK = FALSE;
        }
    }

    //Close handles
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

PROCESS_END_NOPROC:
    CloseHandle(hWritePipe);
    CloseHandle(hReadPipe);

PROCESS_END_NOPIPE:
    return bOK;
}

int main(int argc, char* argv[])
{
    if(argc > 1)
    cout << ProcessCommandLine(argv[1]) << endl;

    return 0;
}
```

Kannst du mir kurz erklären was hier richtig passiert. 
Wie schon  gesagt möchte ich mit dem Client zum Server eine verbindung aufbauen und dann befehle an den server senden der diese dann ausführt. Der Server sollte dann die Ausgabe des gestarteten Prozesses zum Client übers Netzwerk umleiten. Also der Code oben wär dann wahrscheinlich im Server und die Ausgabe wird von CreateProcess abgefangen und umgeleitet wenn ich das richtig verstanden habe. Doch wieso sehe ich denn gestarteten externen Prozess nicht im gleich Konsolenfenster'?


----------



## jokey2 (8. September 2006)

> Also der Code oben wär dann wahrscheinlich im Server und die Ausgabe wird von CreateProcess abgefangen und umgeleitet wenn ich das richtig verstanden habe.


 Das hast du in etwa richtig verstanden. Eins, setzen!;-)



> Doch wieso sehe ich denn gestarteten externen Prozess nicht im gleich Konsolenfenster'?


 Meinst Du die Ausgabe des Prozesses?
Die Ausgabe des gestarteten Prozesses kannst Du ja nicht mehr im Konsolenfenster sehen, da sie nicht mehr auf die Konsole ausgegeben wird sondern mit ReadFile aus der Pipe in den Lesepuffer gelesen wird. An der Stelle, an der steht '//hier Programmausgabe verarbeiten (z.B. send)' kannst Du den Inhalt des Puffers auswerten. Zum Testen kannst du ihn z.B. wieder auf die Kommandozeile ausgeben (mit cout oder printf).
Dein Server sollte später an dieser Stelle eine Funktion aufrufen, die den Inhalt des Puffers an den Client sendet.


----------



## partitionist (8. September 2006)

Danke für die Aufklärung 

Habe die Funktion in den Server eingefügt:


```
BOOL ProcessCommandLine(char * pcCommandLine)
//main...
```

Den empfangenen buffer mit dem Befehl gebe ich nun weiter an die Funktion ProcessCommandLine(). Dann soll sie an der beschriebenen Stelle mit send() den Buffer an den Client senden. Es gibt 2 Möglichkeiten an den Client zu senden.

1) Damit ich in der Funktion ProcessCommandLine() senden kann, muss ich den Socket übergeben damit ich das so starten kann: 
	
	
	



```
send(clients[j].socket,task.c_str(),strlen(task.c_str()),0);
```

2) Anstatt des Rückgabetyps BOOL bei ProcessCommandLine() dachte ich mir ersetze ich ihn durch den Puffer, so kann ich in der main gleich send() mit allen Parametern verwenden.

Welche dieser Möglichkeiten ist besser?


----------



## partitionist (8. September 2006)

Bin soweit fertig, habe folgendes geändert:


```
ProcessCommandLine(char * pcCommandLine, SOCKET s)
```
Hierbei übergebe ich der Funktion den Socket des Clients.

Habe langsam die Übersicht verloren und wollte wissen was(Daten) ich überhaupt senden soll und wie ich die empfangenen Daten beim Client ausgeben soll.

Server: 
send(s, Daten, strlen(Daten), 0)

Client:
recv(s, Daten, strlen(Daten), 0)


----------



## partitionist (10. September 2006)

Sorry wegen der Fragerei habs jetzt hinbekommen 

Hier mein Client/Server:

Client

```
#include <stdlib.h> 
#include <stdio.h> 
#include <windows.h> 
#include <winsock.h> 
#include <conio.h> 
#include <string>
#include <iostream>
#include <sstream>
#include <cstdio> 
#include <vector>
#include "format.h"

using namespace std;

#pragma comment(lib,"wsock32.lib")


// Startet Winsock und gibt einige Infos zur Version aus 
// Starts winsock and dumps some infos about the version 
int startWinsock() 
{ 
   int rc; 
   WSADATA wsaData; 
   rc=WSAStartup(MAKEWORD(2,0),&wsaData); 
   
   if(rc==SOCKET_ERROR) 
   { 
      printf("Error, exiting!\n"); 
      return rc; 
   }  
   printf("System Status: %s\n",wsaData.szSystemStatus); 
   return 0; 
} 

// Sucht eine IP anhand eines Strings, der entweder die IP als String 
// oder einen Hostname enthalten kann 
long getAddrFromString(char* hostnameOrIp, SOCKADDR_IN* addr) 
{ 
   long rc; 
   unsigned long ip; 

   HOSTENT* he; 

   if(hostnameOrIp==NULL || addr==NULL) 
      return SOCKET_ERROR; 
   ip=inet_addr(hostnameOrIp); 

   if(ip!=INADDR_NONE)
   { 
      addr->sin_addr.s_addr=ip; 
      return 0; 
   } 
   else 
   { 
      he=gethostbyname(hostnameOrIp); 
      if(he==NULL) 
      { 
         return SOCKET_ERROR; 
      } 
      else 
      { 
         memcpy(&(addr->sin_addr),he->h_addr_list[0],4); 
      } 
      return 0; 
   } 
} 

int main(int argc, char* argv[]) 
{
    textcolor(white);
    if(argc > 2)
    {
        char* HOST = argv[1];
        int PORT = atoi(argv[2]);

        SOCKET s; 
        SOCKADDR_IN addr; 
        char c; 
        char buf[1024]; 
        char inpBuf[1024]; 
        int inpBufPos=0; 
        fd_set fdSetRead; 
        TIMEVAL timeout; 
        int rc; 


        // start winsock 
        rc=startWinsock(); 
        if(rc==SOCKET_ERROR) 
        return 1; 

        // addr vorbereiten, hostname auflösen 
        // prepare addr, resolve hostname 
        memset(&addr,0,sizeof(SOCKADDR_IN)); 
        addr.sin_family=AF_INET; 
        addr.sin_port=htons(PORT); 
        rc=getAddrFromString(HOST, &addr); 
        if(rc==SOCKET_ERROR) 
        { 
        printf("Error: Cannot resolve Host %s\n", HOST); 
        return 1; 
        } 

        // socket erstellen 
        // create socket 
        s=socket(PF_INET,SOCK_STREAM,0); 
        if(s==INVALID_SOCKET) 
        { 
        printf("Error, cannot create socket: %d\n",WSAGetLastError()); 
        return 1; 
        } 

        // verbinden.. 
        // connect.. 
        printf("Connecting...\n"); 
        rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR)); 
        if(rc==SOCKET_ERROR) 
        { 
        printf("Error: connect failed: %d\n",WSAGetLastError()); 
        return 1; 
        } 

        printf("\n"); 
        
        string str; //Eingabe String

        do
        {
            cout << "Eingabe:";
            getline(cin, str);

            if(str == "exit")
            {
                closesocket(s); 
                WSACleanup(); 
                return 0;
            }

            else if(str == "close")
            {
                rc=send(s,str.c_str(),strlen(str.c_str()),0); 
                closesocket(s); 
                WSACleanup(); 
                return 0;
            }

        
            //cout << "send->" << str << endl;
            rc=send(s,str.c_str(),strlen(str.c_str()),0); 
            if(rc==SOCKET_ERROR)
            {
                printf("Error: Sending to Server failed: %d\n",WSAGetLastError()); 
            } 
                        
            // fd_set und timeout vorbereiten 
            // prepare fd_set and timeout 
            FD_ZERO(&fdSetRead); 
            FD_SET(s,&fdSetRead); 
            timeout.tv_sec=0; 
            timeout.tv_usec=0; 

            // prüfen ob ein socket bereit ist, da timeout=0 kehrt die funktion 
            // sofort wieder zurück nach dem aufruf. 
            // achtung: das timeout auf 0 setzen oder als paremeter NULL mitgeben 
            // ist NICHT das gleiche. auf 0 gesetzt kehrt sofort zurück, während 
            // NULL blockt. 
            // check if any socket is ready (timeout=0, the function returns without delay) 
            while((rc=select(0,&fdSetRead,NULL,NULL,&timeout))>0) 
            { 
                rc=recv(s,buf,1023,0); 
                // server hat die verbindung beendet ? 
                // server closed connection ? 
                if(rc==0) 
                { 
                    printf("Server closed connection!\n"); 
                    return 1; 
                // fehler: beenden! 
                // error: abort! 
                } else if(rc==SOCKET_ERROR) 
                { 
                    printf("Error: recv failed: %d\n",WSAGetLastError()); 
                    return 1; 
                } 
                // empfangene daten ausgeben 
                // print received data 
                buf[rc]='\0'; 
                printf("%s\n",buf); 
            } 
    

        }while(rc!=SOCKET_ERROR);//Ende do-while

        // aufräumen 
        // cleanup.. 
        closesocket(s); 
        WSACleanup(); 
        printf("Client shutdown, press any key to exit\n"); 
        getch(); 

       }
       else    
       {
           cout << "Client HOST PORT" << endl;
       }
       return 0; 

}
```

Server:


```
// max. Anzahl Clients 
// Max. number of clients 
#define MAX_CLIENTS 20


// Der Standartwert für FD_SETSIZE ist 64, dieser kann aber verändert 
// werden indem man FD_SETSIZE auf einen anderen Wert setzt bevor man 
// winsock2.h includiert. 
// FD_SETSIZE auf die max. Anzahl Clients setzten 
#define FD_SETSIZE   MAX_CLIENTS 

// includes... 
#include <stdlib.h> 
#include <stdio.h> 
#include <windows.h> 
#include <winsock.h> 
#include <conio.h> 
#include <string>
#include <iostream>
#include "convert.h"
#include "registry.h"

#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib,"user32.lib")

using namespace std;

// Stellt eine Verbindung mit einem Client dar 
// Represents a connection with a Client 
struct Connection 
{ 
   Connection() 
   { 
      used=false; 
      socket=INVALID_SOCKET; 
   } 
   void set(SOCKET s, SOCKADDR_IN addr) 
   { 
      this->socket=s; 
      this->addr=addr; 
      this->used=true; 
   } 
   void erase() 
   { 
      this->used=false; 
      this->socket=INVALID_SOCKET; 
   } 
   bool used;   // connection benutzt ? / connection slot used ? 
   SOCKET socket; // socket 
   SOCKADDR_IN addr; // client addr 
}; 

// clients 
Connection clients[MAX_CLIENTS]; 

// Sucht den nächsten freien Platz im clients Array 
// -1 = kein platz frei 
// Searches the next free slot in the clients array 
// -1 = no free slot 
int getFreeClientSlot() 
{ 
   for(int i=0;i<MAX_CLIENTS;i++) 
   { 
      if(clients[i].used==false) 
         return i; 
   } 
   return -1; 
} 

// Sendet eine Nachricht an alle Clients 
// Send's a Message to all clients 
/*int sendToAllClients(char* msg) 
{ 
   int rc,i; 
   for(i=0;i<MAX_CLIENTS;i++) 
   { 
      if(!clients[i].used) 
         continue; 
      rc=send(clients[i].socket,msg,strlen(msg),0); 
      if(rc==SOCKET_ERROR) 
      { 
         printf("Error: Sending to Client %d failed: %d\n",i,WSAGetLastError()); 
      } 
   } 
   return 0; 
} 
*/

// Startet Winsock und gibt einige Infos zur Version aus 
// Starts winsock and dumps some infos about the version 
int startWinsock() 
{ 
   int rc; 
   WSADATA wsaData; 
   rc=WSAStartup(MAKEWORD(2,0),&wsaData); 
   
   if(rc==SOCKET_ERROR) { 
      printf("Error, exiting!\n"); 
      return rc; 
   }   
   printf("System Status: %s\n",wsaData.szSystemStatus); 
   return 0; 
} 




#define MAX_LINE_LENGTH 1024


BOOL ProcessCommandLine(char * pcCommandLine, SOCKET s)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    HANDLE hReadPipe, hWritePipe;
    DWORD dwWaitResult = WAIT_TIMEOUT, dwBytesRead, dwExitCode, dwSizeLow, dwSizeHigh, dwError;
    char cReadLine[MAX_LINE_LENGTH];
    BOOL bDoRead = TRUE, bOK = TRUE;
    MSG AppMsg;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);


    //Pipes erzeugen
    sa.nLength=sizeof(sa);
    sa.bInheritHandle=TRUE;
    sa.lpSecurityDescriptor=NULL;
    bOK = CreatePipe(&hReadPipe, &hWritePipe, &sa, 1048576);
    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        bOK = FALSE;
        goto PROCESS_END_NOPIPE;
    }

    //Pipes eintragen
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    si.hStdOutput = hWritePipe;                        //Schreib-Ende der Pipe an Prozess übergeben
    si.hStdError = hWritePipe;                        //Schreib-Ende der Pipe an Prozess übergeben
    si.wShowWindow = SW_SHOWMINNOACTIVE;

    //Prozess starten
    bOK = CreateProcess(NULL,
                        pcCommandLine,
                        NULL,
                        NULL,
                        TRUE,
                        NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
                        NULL,
                        NULL,
                        &si,
                        &pi);

    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        goto PROCESS_END_NOPROC;
    }

    //Auf Ende warten und Messages lesen
    while(dwWaitResult != WAIT_OBJECT_0)
    {
        dwWaitResult = WaitForSingleObject(pi.hProcess, 10);
        while(dwSizeLow = GetFileSize(hReadPipe, &dwSizeHigh))
        {
            ZeroMemory(cReadLine, MAX_LINE_LENGTH);
            //Aus dem Leseende der Pipe die Progzessausgaben lesen
            if(bDoRead = ReadFile(hReadPipe, cReadLine, MAX_LINE_LENGTH - 1, &dwBytesRead, NULL))
            {
                if(dwBytesRead)
                {
                    //**** hier Programmausgabe verarbeiten (z.B. send) *******
                    send(s, cReadLine, strlen(cReadLine), 0);
                }
            }
            else
            {
                bOK = FALSE;
                dwError = GetLastError();
            }
        }
        //Applikations-Messagequeue verarbeiten
        if(PeekMessage(&AppMsg, 0, 0, 0, PM_NOREMOVE))
        {
            GetMessage(&AppMsg, 0, 0, 0);
            TranslateMessage(&AppMsg);
            DispatchMessage(&AppMsg);
        }
    }

    if(bOK)
    {
        bOK = GetExitCodeProcess(pi.hProcess, &dwExitCode);
        if(bOK)
        {
            if(dwExitCode != 0)
            {
                //Prozess kehrt mit Ergebnis != 0 zurück
                bOK = FALSE;
            }
        }
        else
        {
            //FEHLER im GetExitCodeProcess
            dwError = GetLastError();
            bOK = FALSE;
        }
    }

    //Close handles
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

PROCESS_END_NOPROC:
    CloseHandle(hWritePipe);
    CloseHandle(hReadPipe);

PROCESS_END_NOPIPE:
    return bOK;
}




int main(int argc, char* argv[]) 
{ 
    if(argc > 1)
    {
        //Startet auf dem übergebenem PORT
        int PORT = atoi(argv[1]);
    
       // SOCKET welcher neue Verbindungen annimmt 
       // SOCKET which accepts new connections 
       SOCKET acceptSocket; 
       SOCKADDR_IN addr; 
       int rc,addrsize=sizeof(SOCKADDR_IN); 
       unsigned int i,j; 
       // fd_set 
       fd_set fdSetRead; 
       // timout für select() / timeout for select() 
       timeval selectTimeout; 
       // temporär benutz für neue verbindungen 
       // temporary used for new connections 
       Connection newConnection; 
       // buffer 
       char buf[1024]; 

       // clients array leeren / clear clients array 
       memset(clients,0x0,sizeof(Connection)*MAX_CLIENTS); 

       // start winsock 
       rc=startWinsock(); 
       if(rc==SOCKET_ERROR) 
          return 1; 

       // socket erstellen / create socket 
       acceptSocket=socket(PF_INET,SOCK_STREAM,0); 
       if(acceptSocket==INVALID_SOCKET) 
       { 
          printf("Error, cannot create socket: %d\n",WSAGetLastError()); 
          return 1; 
       } 

       // sockt an port 1234 binden / bind socket to port 1234 
       memset(&addr,0,sizeof(SOCKADDR_IN)); 
       addr.sin_family=AF_INET; 
       addr.sin_port=htons(PORT); 
       addr.sin_addr.s_addr=INADDR_ANY; 
       rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN)); 
       if(rc==SOCKET_ERROR) 
       { 
          printf("Error, bind() failed: %d\n",WSAGetLastError()); 
          return 1; 
       } 

       // auf verbindungen warten / listen for connections 
       rc=listen(acceptSocket,10); 
       if(rc==SOCKET_ERROR) 
       { 
          printf("Error,listen() failed: %d\n",WSAGetLastError()); 
          return 1; 
       } 


       // The parameter readfds identifies the sockets that are to be checked for readability. 
       // If the socket is currently in the listen state, it will be marked as readable if an 
       // incoming connection request has been received such that an accept is guaranteed to 
       // complete without blocking. 
        
       while(1) 
       { 

          // fd_set leeren / clear fd_set 
          FD_ZERO(&fdSetRead); 
           
          // den socket welcher verbindungen annimmt hinzufügen 
          // add the SOCKET which accepts new connections 
           
          FD_SET(acceptSocket,&fdSetRead); 
          // alle clients hinzufügen 
          // add all clients 
          for(i=0;i<MAX_CLIENTS;i++) 
          { 
             if(clients[i].used) 
                FD_SET(clients[i].socket,&fdSetRead); 
          } 

          // warten bis irgend ein socket bereit ist, wenn timout NULL ist kehrt select() 
          // erst zurück wenn ein socket bereit ist, select() blockt also in diesem falle 
          // wait until any socket is ready (timeout = NULL, block until one socket is ready) 
          rc=select(0,&fdSetRead,NULL,NULL,NULL); 

          // abbrechen bei einem fehler 
          // break on error 
          if(rc<1) 
             break; 

          printf("select() returned %d ready sockets\n",rc); 
           
          for(i=0;i<fdSetRead.fd_count;i++) 
          { 
           
             // acceptSocket ? 
             if(fdSetRead.fd_array[i]==acceptSocket) 
             { 
                // verbindung annehmen / accept new connection 
                newConnection.socket=accept(acceptSocket,(SOCKADDR*)&newConnection.addr,&addrsize); 
                rc=getFreeClientSlot(); 
                if(rc==-1) 
                { 
                   printf("Cannot accept new clients\n"); 
                   continue; 
                } 
                // zu den clients hinzufügen 
                // add to clients 
                clients[rc]=newConnection; 
                clients[rc].used=true; 
                printf("New Client accepted from %s\n",inet_ntoa(newConnection.addr.sin_addr)); 
                continue; 
             } 
              
             // ein client ? 
             // a client ? 
             for(j=0;j<MAX_CLIENTS;j++) 
             { 
                if(!clients[j].used) 
                   continue; 

                if(clients[j].socket==fdSetRead.fd_array[i]) 
                { 
                   rc=recv(clients[j].socket,buf,1023,0); 
                   buf[rc]='\0'; 
                   // rc==0 => client hat die verbindung beendet 
                   // rc==0 => client closed connection 
                   if(rc==0) { 
                      printf("Client %d (%s): closed connection\n",j,inet_ntoa(clients[j].addr.sin_addr)); 
                      closesocket(clients[j].socket); 
                      clients[j].erase(); 
                      continue; 
                   // rc==SOCKET_ERROR => fehler, verbindung beenden! 
                   // rc==SOCKET_ERROR => error, close connection! 
                   } 
                   else if(rc==SOCKET_ERROR) 
                   { 
                      printf("Client %d (%s): Error %d\n",j,inet_ntoa(clients[j].addr.sin_addr),WSAGetLastError()); 
                      printf("Client %d (%s): Server aborts connection\n",j,inet_ntoa(clients[j].addr.sin_addr)); 
                      closesocket(clients[j].socket); 
                      clients[j].erase(); 
                      continue; 
                   // daten empfangen und an alle clients senden 
                   // receive data and send it to all clients 
                   } 
                   else 
                   { 
                       printf("Client %d (%s): Befehl: '%s' \n",j,inet_ntoa(clients[j].addr.sin_addr),buf); 
                      //sendToAllClients(buf); 
                      
                      string command = buf;
                      if(command.find(' ') != string::npos)
                      {                          
                          int pos = command.find(' ');   
                          int lang = command.length();
                            string task = command.substr(0,pos);
                          string para = command.substr(pos+1,lang);

                          string str;
                          str += '"';
                          str += reg.xmd_GetValue("bin");
                          str += "\\";
                          str += task;
                          str += ".exe";
                          str += '"';
                          str += " " + para;
                                                    
                          cout << "Erfolgreich: " << ProcessCommandLine(cvt.StringToChar(str), clients[j].socket) << endl;
                      }
                      
                      else
                      {                            
                         if(command == "close")                        
                         {
                             //rc=send(clients[i].socket,msg,strlen(msg),0); 
                             //  rc=send(clients[j].socket,task.c_str(),strlen(task.c_str()),0); 
                             closesocket(acceptSocket); 
                             WSACleanup();
                         }                         
                         cout << "Erfolgreich: " << ProcessCommandLine(cvt.StringToChar(command), clients[j].socket) << endl;
                      }          

                   } 
                } 
             } 
          }

          cout << "-----------------------------------" << endl;
       }//Ende while

       // aufräumen 
       // cleanup 
       closesocket(acceptSocket); 
       WSACleanup();        
    }
    else 
    {
        cout << "server PORT" << endl;
    }
    
    return 0;   
}
```

Ich hab noch ein kleines Problem, sobald ich mit dem client ein befehl übergebe dann wird nicht sofort nach der ersten Eingabe der inhalt angezeigt, sondern nach der zweiten Eingabe, woran liegt das?


----------



## jokey2 (11. September 2006)

Ersmal schön, daß es soweit funktioniert.
Was Deine Frage angeht, so verstehe ich leider nicht, was du meinst. Welche Eingabe und welcher Inhalt?
Bis dahin noch ein paar Tipps:
- Für 
	
	
	



```
strlen(str.c_str())
```
 kannst Du gleich 
	
	
	



```
str.length()
```
 verwenden

- Statt 
	
	
	



```
printf("%s\n",buf);
```
 solltest Du lieber 
	
	
	



```
cout << std::string(buf) << endl;
```
 verwenden, wenn Du C++ programmierst


----------



## partitionist (11. September 2006)

Also sobald ich etwas eingebe z.b. info und dann Enter drücke passiert garnix, d.h. es kommt noch keine ausgabe. Erst wenn ich nochmal Enter drücke ohne etwas einzugeben kommt die ausgabe von info. Hab versucht im client nochmals ein recv() einzubauen und es hat funktioniert, aber es läuft nicht stabil, wenn ich nix eingebe dann bleibt der client hängen.


----------



## jokey2 (11. September 2006)

Das muß wohl irgendwie mit dem getline zusammenhängen. Allerdings sieht da alles ok aus.
Hast Du mal einen Breakpoint nach dem getline gesetzt, ob es schon nach dem ersten oder erst nach dem 2. Enter zurückkehrt?
Welche IDE verwendest Du denn?


----------



## partitionist (11. September 2006)

Also ich verwende VC8. 
Breakpoint? Könntest du mir erkären was das ist und wie ich es setze.


----------



## jokey2 (11. September 2006)

Ein Breakpoint ist eine Anweisung an den Debugger, an einer bestimmten Stelle die Programmausführung anzuhalten. Aber wenn du das nicht wei0t, dann solltest Du Dich dringend mal mit dem Thema 'Debugging' beschäftigen.

Es gibt verschiedene Arten von Breakpoints:
- Code-Breakpoints: Der Debugger hält an, wenn eine bestimmte Codezeile erreicht wurde (in meinem VS .NET 2003 kann man dazu Zeilen und Zeichennummer innerhalb einer Funktion oder einer Datei angeben oder eine Adresse im Code)
- Daten-Breakpoints: Der Debugger hält an, wenn sich der Wert einer Variablen ändert

Wenn das Programm am Breakpoint angehalten hat, kannst Du es z.B. Schritt für Schritt weiter ausführen und kannst die Arbeit Deiner Anwendung sowie die Variablen beobachten.

Wenn du mit VC8 das VisualStudio .NET 2005 meinst, dann mußt du nur im Codefenster links auf den grauen Streifen klicken, und zwar in der Zeile, in der das Programm anhalten soll. Dann erscheint dort ein großer roter Punkt, der symbolisiert den Breakpoint. Wenn das Programm diese Codezeile erreicht, wird der Debugger anhalten. Mit F10 und F11 kannst Du dann schrittweise weitergehen, wobei F11 in die Funktionen reingeht, F10 führt sie am Stück aus. Einfach mal ausprobieren.

Du mußt natürlich in den Projekteigenschaften das Debugging eingeschaltet haben. Nortmalerweise wird im Visual Studio immer mindestens eine Debug- und eine Releaseversion angelegt. Da mußt Du die Debugversion als aktive Konfiguration auswählen.

Um mehr über den Debugger zu erfahren, gib mal 'Debugger' im MSDN-Hilfe-Index ein.


----------



## partitionist (11. September 2006)

Habs aus Neugier ausprobiert mit F11 ist es wohl zu kompliziert, aber mit F10 ist es übersichtlicher. Nur das bei main() Argumente erwartet werden und wenn ich dann Schritt für Schritt debugge dann springt er gleich auf else{} da kein parameter angegben wurde. 
Komme nicht drauf, wieso erst nach dem zweiten drücken der Eingabetaste die Ausgabe ausgegeben wird, liegt es hier eher am Client oder am Server

Paar Fragen:
1) In meinen Tools sind an einigen Stellen die Texte farbig hervorgehoben, doch wenn sie mit der Pipe() umgelenkt werden, wird nur eine Farbe ausgegeben, ist das möglich auch in der Pipe zu machen

2) Alle Tools funktionieren prima da sie mit parametern aufgerufen werden, doch sobald eine Eingabe mit cin >> str; in einem Tool ist so kann ich kein wert im Client eingeben da dieser die Eingabe überspringt


----------



## jokey2 (12. September 2006)

Du kannst dem VS sagen, welche Argumente dem Programm beim Debuggen übergeben werden sollen. Dazu gehst Du im Menü auf Projekt->Eigenschften von <Projektname>. Im folgenden Dialog wählst Du Deine Debug-Konfiguration (die ist normalerweise schon ausgewählt, wenn sie die aktive Konfiguration ist). Im linken Teil wählst Du unter 'Konfigurationseigenschaften' den Punkt 'Debuggen' aus. Dann kannst Du im rechten Teil in der Zeile 'Befehlsargumente' Deine Parameter angeben. Die werden dann bei jedem Debug-Start Deinem Programm übergeben.
Zu Deinen Fragen:
1.: Das dürfte, wenn überhaupt, nur sehr schwierig machbar zu sein. Du bräuchtest ein HANDLE auf die Console und müßtest die Farbinformationen ihres Buffers abfragen. Du hast zwar das Prozesshandle, aber ob das auch das Konsolenhandle ist weiß ich nicht.
2.: Dazu müßtest Du eine zweite Pipe erzeugen und damit auch noch das InputHandle füttern:

```
bOK = CreatePipe(&hReadOutPipe, &hWriteOutPipe, &sa, 1048576);
    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        bOK = FALSE;
        goto PROCESS_END_NOPIPE;
    }
 bOK = CreatePipe(&hReadInPipe, &hWriteInPipe, &sa, 1048576);
    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        bOK = FALSE;
        goto PROCESS_END_NOINPIPE;
    }
    //Pipes eintragen
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.hStdInput = hReadInPipe; //Lese-Ende der Eingabe-Pipe an Prozess
    si.hStdOutput = hWriteOutPipe;                        //Schreib-Ende der Ausgabe-Pipe an Prozess übergeben
    si.hStdError = hWriteOutPipe;                        //Schreib-Ende der Ausgabe-Pipe an Prozess übergeben
    si.wShowWindow = SW_SHOWMINNOACTIVE;
```
Dann müßtest Du noch einen 2. Thread erzeugen, der auf gesendete Eingaben (mit recv) wartet und diese in das Schreib-Ende der Eingabe-Pipe schreibt. So bekommt der Prozess diese Eingaben.

Alles in Allem sieht das schon mehr aus wie ein Telnet- oder SSH-Terminal. Bei einem solchen könnte dann auch das mit der farbigen Ausgabe klappen.


----------



## partitionist (12. September 2006)

Hab den Code eingefügt, doch im restlichem Code sind noch die alten Handles wie hReadPipe, hWritePipe. In welchen Handle soll ich die alten ändern z.b. hier:


```
while(dwSizeLow = GetFileSize(hReadPipe, &dwSizeHigh))
```


```
if(bDoRead = ReadFile(hReadPipe, cReadLine, MAX_LINE_LENGTH - 1, &dwBytesRead, NULL))
```


```
PROCESS_END_NOPROC:
    CloseHandle(hWritePipe);
    CloseHandle(hReadPipe);
```
Das mit dem Thread hab ich nicht ganz so verstanden, soll dieser Thread vor der Funktion ProcessCommandLine() laufen und wie soll CreateProcess() rausfinden ob es um ein Out- oder Input handelt? 



> Alles in Allem sieht das schon mehr aus wie ein Telnet- oder SSH-Terminal. Bei einem solchen könnte dann auch das mit der farbigen Ausgabe klappen.


 Anfangs wollte ich ein server erstellen, welcher im LAN befehle von client ausführt, doch es hat sich bißchen erweitert mit Pipes und vielleicht kommt noch eine Authentifizierung, jeder Client muss sich registrieren (MAC, Hostname,..) der sich mit dem Server in Verbindung setzt und vielleicht noch eine Passwort Abfrage... 
Wie meintest du das mit der farbigen Ausgabe das es klappen könnte.


----------



## jokey2 (12. September 2006)

> In welchen Handle soll ich die alten ändern


Ich dachte, das erklärt sich aus der STARTUPINFO-Struktur. Die alten Pipe-Handles heißen jetzt hReadOutPipe und hWriteOutPipe.


> soll dieser Thread vor der Funktion ProcessCommandLine() laufen


Du solltest den Thread starten, nachdem der Prozess erfolgreich gestartet wurde, aber bevor Du die ersten Daten aus der Prozess-Pipe liest.


> Wie meintest du das mit der farbigen Ausgabe das es klappen könnte.


Ein Telnet-Server könnte sich auf dem Rechner für das gestartete Tool verhalten wie eine normale Konsole und so auch die Anweisungen für die Textfarbe vom Tool bekommen und sie an den Client weiterleiten. Ob das mit dem Windows-Telnet funktioniert, weiß ich nicht.

Zu meinem vorherigen Post:
Ich habe gerade festrgestellt, daß das Konsolenhandle normalerweise das Standard-Output-Handle ist. Jetzt kommen einige wilde Vermutungen:
Vielleicht kannst Du ja die Farbinformationen aus dem hWriteOutPipe-Handle oder dem hReadOutPipe-Handle lesen (Mit 'GetConsoleScreenBufferInfo'). Wenn das klappt, dann könntest Du diese Informationen an den Client senden, der sie dann in der Anzeige seiner Konsole umsetzt. Dazu müßtest Du natürlich die Zeile mit dem 'send' so abändern, daß der Server weiß, was da gesendet wurde (Text oder Farbinformation). Du kannst also nicht mehr nur einfach den Lesepuffer senden, sondern ein struct, welches die Art der Daten, die Datenlänge und die Daten selber enthält.
Vielleicht mußt du dann auch die Zeichen einzeln an den Client senden und vorher immer die Buffer-Attribute abfragen, da in der CONSOLE_SCREEN_BUFFER_INFO-Struktur immer nur die aktuell eingestellten Attribute stehen, also die, die für das nächste auf der Konsole eingegebene Zeichen gelten. Dann könntest du natürlich immer zu jedem Zeichen die entsprechenden Attribute mitschicken. Aber, wie gesagt, das sind alles Vermutungen. Du kannst es gerne ausprobieren und Deine Ergebnisse hier posten.

Putty ist ein GNU-Telnet, die Binaries und den Sourcecode gibt es hier. Du kannst Dir ja mal den Sourcecode ansehen, vielleicht hilft Dir das weiter. Vielleicht verwirrt es Dich aber auch nur ;-)


----------



## partitionist (12. September 2006)

Wenn ich jetzt denn geänderten Code ausführe, dann bekomme ich ein Fehler:

```
error C2094: Marke 'PROCESS_END_NOINPIPE' nicht definiert
```


```
BOOL ProcessCommandLine(char * pcCommandLine)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    //HANDLE hReadPipe, hWritePipe;
    DWORD dwWaitResult = WAIT_TIMEOUT, dwBytesRead, dwExitCode, dwSizeLow, dwSizeHigh, dwError;
    char cReadLine[MAX_LINE_LENGTH];
    BOOL bDoRead = TRUE, bOK = TRUE;
    MSG AppMsg;
    HANDLE hReadOutPipe, hWriteOutPipe, hReadInPipe, hWriteInPipe;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);


    //Pipes erzeugen
    sa.nLength=sizeof(sa);
    sa.bInheritHandle=TRUE;
    sa.lpSecurityDescriptor=NULL;

    bOK = CreatePipe(&hReadOutPipe, &hWriteOutPipe, &sa, 1048576);
    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        bOK = FALSE;
        goto PROCESS_END_NOPIPE;
    }
    bOK = CreatePipe(&hReadInPipe, &hWriteInPipe, &sa, 1048576);
    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        bOK = FALSE;
        goto PROCESS_END_NOINPIPE;
    }
    //Pipes eintragen
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.hStdInput = hReadInPipe; //Lese-Ende der Eingabe-Pipe an Prozess
    si.hStdOutput = hWriteOutPipe;                        //Schreib-Ende der Ausgabe-Pipe an Prozess übergeben
    si.hStdError = hWriteOutPipe;                        //Schreib-Ende der Ausgabe-Pipe an Prozess übergeben
    si.wShowWindow = SW_SHOWMINNOACTIVE;

    //Prozess starten
    bOK = CreateProcess(NULL,
                        pcCommandLine,
                        NULL,
                        NULL,
                        TRUE,
                        NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
                        NULL,
                        NULL,
                        &si,
                        &pi);

    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        goto PROCESS_END_NOPROC;
    }

    //Auf Ende warten und Messages lesen
    while(dwWaitResult != WAIT_OBJECT_0)
    {
        dwWaitResult = WaitForSingleObject(pi.hProcess, 10);
        while(dwSizeLow = GetFileSize(hReadOutPipe, &dwSizeHigh))
        {
            ZeroMemory(cReadLine, MAX_LINE_LENGTH);
            //Aus dem Leseende der Pipe die Progzessausgaben lesen
            if(bDoRead = ReadFile(hReadOutPipe, cReadLine, MAX_LINE_LENGTH - 1, &dwBytesRead, NULL))
            {
                if(dwBytesRead)
                {
                    //hier Programmausgabe verarbeiten (z.B. send)                    
                }
            }
            else
            {
                bOK = FALSE;
                dwError = GetLastError();
            }
        }
        //Applikations-Messagequeue verarbeiten
        if(PeekMessage(&AppMsg, 0, 0, 0, PM_NOREMOVE))
        {
            GetMessage(&AppMsg, 0, 0, 0);
            TranslateMessage(&AppMsg);
            DispatchMessage(&AppMsg);
        }
    }

    if(bOK)
    {
        bOK = GetExitCodeProcess(pi.hProcess, &dwExitCode);
        if(bOK)
        {
            if(dwExitCode != 0)
            {
                //Prozess kehrt mit Ergebnis != 0 zurück
                bOK = FALSE;
            }
        }
        else
        {
            //FEHLER im GetExitCodeProcess
            dwError = GetLastError();
            bOK = FALSE;
        }
    }

    //Close handles
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

PROCESS_END_NOPROC:
    CloseHandle(hWriteOutPipe);
    CloseHandle(hReadOutPipe);

PROCESS_END_NOPIPE:
    return bOK;
}
```


----------



## jokey2 (12. September 2006)

Ich hatte nicht erwartet, Dir jede Anpassung explizit erklären zu müssen! Selber denken schadet nicht.  

Natürlich mußt du die erzeugten Handles der OutPipe schließen, wenn die Prozedur beendet wird oder wenn das Erzeugen der InPipe fehlschlägt:

```
PROCESS_END_NOPROC:
    CloseHandle(hWriteInPipe);
    CloseHandle(hReadInPipe);

PROCESS_END_NOINPIPE:
    CloseHandle(hWriteOutPipe);
    CloseHandle(hReadOutPipe);
     return bOK;

 PROCESS_END_NOPIPE:
    return bOK;
```
 Aber wie ich schon gesagt habe, wäre es besser, wenn Du die goto's ersetzen würdest, z.B. durch die Verwendung von Exceptions.


----------



## partitionist (12. September 2006)

Wenn ich richtig verstanden habe, dann soll im Thread auf die auf die Eingabe vom Client gewartet werden, welche mit recv() empfangen wird. 



> Du solltest den Thread starten, nachdem der Prozess erfolgreich gestartet wurde, aber bevor Du die ersten Daten aus der Prozess-Pipe liest.


Also in etwa hier

```
//Auf Ende warten und Messages lesen
    while(dwWaitResult != WAIT_OBJECT_0)
    {
        dwWaitResult = WaitForSingleObject(pi.hProcess, 10);
        while(dwSizeLow = GetFileSize(hReadOutPipe, &dwSizeHigh))
        {
//Thread
            hThread = CreateThread( NULL, 0, threadfunc, data, 0, 0 );

            ZeroMemory(cReadLine, MAX_LINE_LENGTH);
            //Aus dem Leseende der Pipe die Progzessausgaben lesen
            if(bDoRead = ReadFile(hReadOutPipe, cReadLine, MAX_LINE_LENGTH - 1, &dwBytesRead, NULL))
            {
```
Die Beispiel Thread Funktion:

```
unsigned long __stdcall threadfunc( void *arg )
{    
    //recv() Empfange eingelesene Daten
    return 0;
}
```
Aber dann müsste ich auch im Client Anpassungen vornehmen oder?


----------



## jokey2 (12. September 2006)

Das stimmt so nicht ganz. So wie Du es gemacht hast, würde ja bei jedem Durchlauf der Schleife ein neuer Thread gestartet werden.
Erstmal legst Du ein struct an, in dem Du das Handle, den Socket sowie eine bool-Variable unterbringst:

```
typedef struct t_ThreadData
{
    bool bEndThread;
    HANDLE hPipe;
    SOCKET s;
};
```
 Dann startest Du den Thread, *nach* dem erfolgreichen Aufruf von CreateProcess, aber *vor* der Warteschleife:

```
//Prozess starten
    bOK = CreateProcess(NULL,
                        pcCommandLine,
                        NULL,
                        NULL,
                        TRUE,
                        NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
                        NULL,
                        NULL,
                        &si,
                        &pi);

    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        goto PROCESS_END_NOPROC;
    }

    //Thread
    t_ThreadData ThreadData;
    ThreadData.bEndThread = false;
    ThreadData.hPipe = hWriteInPipe;
    ThreadData.s = s;
    hThread = CreateThread( NULL, 0, threadfunc, (void*)&ThreadData, 0, 0 );

    //Auf Ende warten und Messages lesen
    while(dwWaitResult != WAIT_OBJECT_0)
    {
        dwWaitResult = WaitForSingleObject(pi.hProcess, 10);
        while(dwSizeLow = GetFileSize(hReadOutPipe, &dwSizeHigh))
        {
            ZeroMemory(cReadLine, MAX_LINE_LENGTH);
            //Aus dem Leseende der Pipe die Progzessausgaben lesen
            if(bDoRead = ReadFile(hReadOutPipe, cReadLine, MAX_LINE_LENGTH - 1,    &dwBytesRead, NULL))
            {
    ...
    }
    //Nach der Schleife Thread beenden
    ThreadData.bEndThread = true;
```
 Die Threadfunktion sollte dann etwa so aussehen:

```
unsigned long __stdcall threadfunc( void *data)
{
    t_ThreadData *pThreadData = (t_ThreadData*)data;
    ...
    while(!pThreadData->bEndThread)
    {
        //recv(pThreadData->s, ... ) Empfange eingelesene Daten
        //WriteFile(pThreadData->hPipe, .....) empfangene Daten in die Pipe schreiben
    }
    return 0;
}
```
Den Zugriff auf bEndThread solltest Du allerdings besser mit einer Critical Section bzw. einem Mutex oder einer Semaphore absichern.


----------



## partitionist (12. September 2006)

Hab soweit alles übernommen, hier zur Sicherheit der Thread: 


```
unsigned long __stdcall threadfunc( void *data)
{
    t_ThreadData *pThreadData = (t_ThreadData*)data;
    
    char buffer[1024];
    DWORD dwBytesWrite;
    char cReadLine[MAX_LINE_LENGTH];

    while(!pThreadData->bEndThread)
    {
        //recv(pThreadData->s, ... ) Empfange eingelesene Daten
        //WriteFile(pThreadData->hPipe, .....) empfangene Daten in die Pipe schreiben
        recv(pThreadData->s, buffer, strlen(buffer), 0);
        WriteFile(pThreadData->hPipe, cReadLine, MAX_LINE_LENGTH - 1, &dwBytesWrite, NULL);
    
    }
    return 0;
}
```

Hab mir ein Programm test.exe erstellt: 

```
string str;     
cout << "Eingabe: ";
cin >> str;
cout << "Ausgabe: ";
```
Doch sobald ich den server starte und mit dem client die test.exe starten will öffnet sich für diesen Prozess ein neues Fenster. Im Client sehe ich nur die Ausgabe "Eingabe: " von test.exe, aber ich kann nix eingeben.

Wie ich sehe wird die Thread Funktion immer ausgeführt auch wenn keine Input Eingabe verwendet wird oder?


----------



## jokey2 (12. September 2006)

> recv(pThreadData->s, buffer, strlen(buffer), 0);
> WriteFile(pThreadData->hPipe, cReadLine, MAX_LINE_LENGTH - 1, &dwBytesWrite, NULL);


 Das kann doch so garnicht funktionieren! strlen funktioniert nur bei nullterminierten strings!

```
unsigned long __stdcall threadfunc( void *data)
{
    t_ThreadData *pThreadData = (t_ThreadData*)data;
    
    char buffer[1024];
    int iBytesReceived;
    DWORD dwBytesWritten;
    char cReadLine[MAX_LINE_LENGTH];

    while(!pThreadData->bEndThread)
    {
        //recv(pThreadData->s, ... ) Empfange eingelesene Daten
        //WriteFile(pThreadData->hPipe, .....) empfangene Daten in die Pipe schreiben
        iBytesReceived=          recv(pThreadData->s, buffer, 1024, 0);
        if(iBytesReceived == SOCKET_ERROR)
        {
            //FEHLER!
        }
        else if (iBytesReceived > 0)
        {
             WriteFile(pThreadData->hPipe, buffer, iBytesReceived, &dwBytesWritten, NULL);
        }
    }
    return 0;
}
```



> Wie ich sehe wird die Thread Funktion immer ausgeführt auch wenn keine Input Eingabe verwendet wird oder?


Richtig. Der Server kann ja nicht vorher wissen, ob das gestartete Programm eine Eingabe erwartet oder nicht.



> Doch sobald ich den server starte und mit dem client die test.exe starten will öffnet sich für diesen Prozess ein neues Fenster. Im Client sehe ich nur die Ausgabe "Eingabe: " von test.exe, aber ich kann nix eingeben.


 Versuch's mal ohne den Parameter CREATE_NEW_CONSOLE beim CreateProcess. Daran könnte es liegen.


----------



## partitionist (13. September 2006)

Es funktioniert immer noch nicht, hab wenigstens CREATE_NEW_CONSOLE entfernt, jetzt startet kein neues Fenster 
Der Server soll ja die Eingabe von externen Programmen zum Client übergeben, nicht wahr? Aber wie soll der Client mit einem recv() empfangene Daten als eine Eingabe auslesen oder muss dieser noch angepasst werden
Wenn ich mich nicht irre, muss der Server dem Client sagen, dass ich von dir eine Eingabe brauche aber im Code vom Client wird nur ein recv() erwartet.

Client

```
//Eingabe...
//Sende Eingabe...
//Empfange Daten..
while((rc=select(0,&fdSetRead,NULL,NULL,&timeout))>0) 
            { 
                rc=recv(s,buf,1023,0); 
                // server hat die verbindung beendet ? 
                if(rc==0) 
                { 
                    printf("Server closed connection!\n"); 
                    return 1; 
                // fehler: beenden! 
                } 
                else if(rc==SOCKET_ERROR) 
                { 
                    printf("Error: recv failed: %d\n",WSAGetLastError()); 
                    return 1; 
                } 
                // empfangene daten ausgeben 
                buf[rc]='\0'; 
                cout << buf << endl;
            }
```

Wenns weiter nicht hilft, könnte ich die Binaries zum Testen schicken.


----------



## jokey2 (13. September 2006)

Da Du zweischen Client und Server eine bidirektionale Kommunikation hast, müssen natürlich beide gegenseitig auf sich hören.
-> Der Client schickt dem Server den Befehl zum Starten der Anwendung. Dann empfängt er Daten vom Server.
-> Der Server startet die Anwendung und schickt die Ausgaben an den Client
-> Wenn im Client Daten auf der Konsole eingegeben werden, sendet er diese an den Server.
-> Der Server übergibt die empfangenen Daten an die Anwendung
Und so geht das weiter bis die anwendung beendet ist und der Server den Socket schließt.

Ich habe jetzt leider nicht mehr die Zeit, das weiter auszuformulieren. Probier mal weiter, ich schau' mir dann morgen an, was Du hast.


----------



## partitionist (15. September 2006)

Habe im Client folgendes ergänzt:


```
//Eingabe des Befehle...
//Sende Befehl
//Empfange Daten
//Eingabe für den Input Inhalt...
getline(cin, str);
            rc=send(s,str.c_str(),strlen(str.c_str()),0); 
            if(rc==SOCKET_ERROR)
            {
                printf("Error: Sending to Server failed: %d\n",WSAGetLastError()); 
            }
```
Beim Server habe ich als Kontrolle mehrere Ausgaben hinzugefügt:


```
//Auf Ende warten und Messages lesen
    while(dwWaitResult != WAIT_OBJECT_0)
    {
        cout << "Schleife gestartet..." << endl;
        ......

if(dwBytesRead)
                {                               
                    send(s, cReadLine, strlen(cReadLine), 0);
                    cout << "send client...:" << cReadLine << endl;
        .....
```
Thread Funktion:

```
unsigned long __stdcall threadfunc( void *data)
{
    cout << "Thread gestartet..." << endl;
    .....
 
else if (iBytesReceived > 0)
        {
            cout << "buffer empfangen: " << buffer << endl;
             WriteFile(pThreadData->hPipe, buffer, iBytesReceived, &dwBytesWritten, NULL);
        }
```

Jetzt beschreibe ich detaliert, was beim Server/Client passiert mit Hilfe von test.exe(Input Eingabe).

- starte server auf port 12
- verbinde client mit server 
- gebe beim client den befehl *test *ein
- beim server wird folgendes ausgeben: 

```
Schleife gestartet...Thread gestartet...

send client...:Eingabe:
Schleife gestartet...
Schleife gestartet...
Schleife gestartet...
Schleife gestartet...
Schleife gestartet...
Schleife gestartet...
//..dauert so lange bis der client was eingibt
```
- gebe beim client bei der zweiten Eingabe *help* ein
- muss schnell beim Server pause drücken damit ich die ausgabe sehen kann.
- beim server wird folgendes ausgegeben:

```
....
buffer empfangen: helpÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ
Schleife gestartet...
Schleife gestartet...
Schleife gestartet...
Schleife gestartet...
Schleife gestartet...
Schleife gestartet..
....
```
- Die Schleife geht weiter.
- Gebe beim Client beliebig etwas ein und bekomme verspätet die ausgabe von *test.exe 

Eingabe:


*Ein Problem ist, wieso bekomme ich immer beim client die ausgaben so spät?
 Nachdem ich test zum server gesendet habe, hat dieser mit "Eingabe:" von test gesendet, aber im client ist diese Ausgabe nicht gleich ausgegeben worden.

Habe den Client debuggt mit F10, habe den befehl *info *eingegeben und sofort diese ausgabe bekommen, komisch oder? Sobald ich den client und server normal gestartet habe und den befehl eingegeben habe, musste ich beim nocheinmal enter drücken damit die ausgabe da war genauso wie mit dem oberen Beispiel.

Also langasam weiß ich auch nicht mehr weiter, wenn das nicht klappen sollte dann lasse ich es lieber und der server soll dann nur die ausgabe umleiten.


----------



## partitionist (19. September 2006)

Hallo nochmals, habe den Server wieder zurückgestzt, jetzt kann er nur die Ausgabe zum Client umleiten. 

Ich habe nur noch eine letzte Bitte, es funktioniert alles prima, doch die Ausgabe kommt immer beim Client zu spät an woran kann das liegen? 
Hat das mit der Länge Buffers zu tun oder mit Timeout...
Mit dem Debugger funktioniert es!

Bitte nochmals um Hilfe

Client:


```
#include <stdlib.h> 
#include <stdio.h> 
#include <windows.h> 
#include <winsock.h> 
#include <conio.h> 
#include <string>
#include <iostream>
#include <sstream>
#include <cstdio> 
#include <vector>
#include "format.h"

using namespace std;

#pragma comment(lib,"wsock32.lib")
#pragma comment(lib,"advapi32.lib")


// Startet Winsock und gibt einige Infos zur Version aus 
// Starts winsock and dumps some infos about the version 
int startWinsock() 
{ 
   int rc; 
   WSADATA wsaData; 
   rc=WSAStartup(MAKEWORD(2,0),&wsaData); 
   
   if(rc==SOCKET_ERROR) 
   { 
      printf("Error, exiting!\n"); 
      return rc; 
   }  
   //printf("System Status: %s\n",wsaData.szSystemStatus); 
   return 0; 
} 

// Sucht eine IP anhand eines Strings, der entweder die IP als String 
// oder einen Hostname enthalten kann 
long getAddrFromString(char* hostnameOrIp, SOCKADDR_IN* addr) 
{ 
   long rc; 
   unsigned long ip; 

   HOSTENT* he; 

   if(hostnameOrIp==NULL || addr==NULL) 
      return SOCKET_ERROR; 
   ip=inet_addr(hostnameOrIp); 

   if(ip!=INADDR_NONE)
   { 
      addr->sin_addr.s_addr=ip; 
      return 0; 
   } 
   else 
   { 
      he=gethostbyname(hostnameOrIp); 
      if(he==NULL) 
      { 
         return SOCKET_ERROR; 
      } 
      else 
      { 
         memcpy(&(addr->sin_addr),he->h_addr_list[0],4); 
      } 
      return 0; 
   } 
} 

int main(int argc, char* argv[]) 
{    
    if(argc > 2)
    {
        char* HOST = argv[1];
        int PORT = atoi(argv[2]);

        SOCKET s; 
        SOCKADDR_IN addr; 
        char c; 
        char buf[1024]; 
        char inpBuf[1024]; 
        int inpBufPos=0; 
        fd_set fdSetRead; 
        TIMEVAL timeout; 
        int rc; 


        // start winsock 
        rc=startWinsock(); 
        if(rc==SOCKET_ERROR) 
        return 1; 

        // addr vorbereiten, hostname auflösen 
        // prepare addr, resolve hostname 
        memset(&addr,0,sizeof(SOCKADDR_IN)); 
        addr.sin_family=AF_INET; 
        addr.sin_port=htons(PORT); 
        rc=getAddrFromString(HOST, &addr); 
        if(rc==SOCKET_ERROR) 
        { 
            printf("Error: Cannot resolve Host %s\n", HOST); 
            return 1; 
        } 

        // socket erstellen 
        // create socket 
        s=socket(PF_INET,SOCK_STREAM,0); 
        if(s==INVALID_SOCKET) 
        { 
            printf("Error, cannot create socket: %d\n",WSAGetLastError()); 
            return 1; 
        } 

        // verbinden.. 
        // connect.. 
        printf("Connecting...\n"); 
        rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR)); 
        if(rc==SOCKET_ERROR) 
        { 
            printf("Error: connect failed: %d\n",WSAGetLastError()); 
            return 1; 
        }
        
        cout << endl;
        
        string str; //Eingabe String

        do
        {
            
            cout << "Eingabe:>";
            
            getline(cin, str);

            

            if(str == "exit")
            {
                closesocket(s); 
                WSACleanup(); 
                return 0;
            }

            else if(str == "close")
            {
                rc=send(s,str.c_str(),strlen(str.c_str()),0); 
                if(rc==SOCKET_ERROR)
                {
                    printf("Error: Sending to Server failed: %d\n",WSAGetLastError()); 
                } 
                closesocket(s); 
                WSACleanup(); 
                return 0;
            }
            //Sende Befehl...
            rc=send(s,str.c_str(),strlen(str.c_str()),0); 
            if(rc==SOCKET_ERROR)
            {
                printf("Error: Sending to Server failed: %d\n",WSAGetLastError()); 
            } 
            
                        
            // fd_set und timeout vorbereiten 
            FD_ZERO(&fdSetRead); 
            FD_SET(s,&fdSetRead); 
            timeout.tv_sec=0; 
            timeout.tv_usec=0; 

            // prüfen ob ein socket bereit ist, da timeout=0 kehrt die funktion 
            // sofort wieder zurück nach dem aufruf. 
            // achtung: das timeout auf 0 setzen oder als paremeter NULL mitgeben 
            // ist NICHT das gleiche. auf 0 gesetzt kehrt sofort zurück, während NULL blockt. 
            while((rc=select(0,&fdSetRead,NULL,NULL,&timeout))>0) 
            { 
                rc=recv(s,buf,1024,0); 
                // server hat die verbindung beendet ? 
                if(rc==0) 
                { 
                    printf("Server closed connection!\n"); 
                    return 1; 
                // fehler: beenden! 
                } 
                else if(rc==SOCKET_ERROR) 
                { 
                    printf("Error: recv failed: %d\n",WSAGetLastError()); 
                    return 1; 
                } 
                // empfangene daten ausgeben 
                buf[rc]='\0'; 
                cout << buf << endl;
            } 
            
            
                
        }while(rc!=SOCKET_ERROR);//Ende do-while

        // aufräumen 
        // cleanup.. 
        closesocket(s); 
        WSACleanup(); 
        cout << "Client shutdown, press any key to exit" << endl;
        getch(); 

       }
       else    
       {
           cout << "Client HOST PORT" << endl;
       }
       return 0; 

}
```


Server:


```
// max. Anzahl Clients 
// Max. number of clients 
#define MAX_CLIENTS 20


// Der Standartwert für FD_SETSIZE ist 64, dieser kann aber verändert 
// werden indem man FD_SETSIZE auf einen anderen Wert setzt bevor man 
// winsock2.h includiert. 
// FD_SETSIZE auf die max. Anzahl Clients setzten 
#define FD_SETSIZE   MAX_CLIENTS 

// includes... 
#include <stdlib.h> 
#include <stdio.h> 
#include <windows.h> 
#include <winsock.h> 
#include <conio.h> 
#include <string>
#include <iostream>
#include "convert.h"
#include "registry.h"

#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib,"user32.lib")

using namespace std;

// Stellt eine Verbindung mit einem Client dar 
// Represents a connection with a Client 
struct Connection 
{ 
   Connection() 
   { 
      used=false; 
      socket=INVALID_SOCKET; 
   } 
   void set(SOCKET s, SOCKADDR_IN addr) 
   { 
      this->socket=s; 
      this->addr=addr; 
      this->used=true; 
   } 
   void erase() 
   { 
      this->used=false; 
      this->socket=INVALID_SOCKET; 
   } 
   bool used;   // connection benutzt ? / connection slot used ? 
   SOCKET socket; // socket 
   SOCKADDR_IN addr; // client addr 
}; 

// clients 
Connection clients[MAX_CLIENTS]; 

// Sucht den nächsten freien Platz im clients Array 
// -1 = kein platz frei 
// Searches the next free slot in the clients array 
// -1 = no free slot 
int getFreeClientSlot() 
{ 
   for(int i=0;i<MAX_CLIENTS;i++) 
   { 
      if(clients[i].used==false) 
         return i; 
   } 
   return -1; 
} 


// Startet Winsock und gibt einige Infos zur Version aus 
// Starts winsock and dumps some infos about the version 
int startWinsock() 
{ 
   int rc; 
   WSADATA wsaData; 
   rc=WSAStartup(MAKEWORD(2,0),&wsaData); 
   
   if(rc==SOCKET_ERROR) { 
      printf("Error, exiting!\n"); 
      return rc; 
   }   
   printf("System Status: %s\n",wsaData.szSystemStatus); 
   return 0; 
} 


#define MAX_LINE_LENGTH 1024


BOOL ProcessCommandLine(char * pcCommandLine, SOCKET s)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    HANDLE hReadPipe, hWritePipe;
    DWORD dwWaitResult = WAIT_TIMEOUT, dwBytesRead, dwExitCode, dwSizeLow, dwSizeHigh, dwError;
    char cReadLine[MAX_LINE_LENGTH];
    BOOL bDoRead = TRUE, bOK = TRUE;
    MSG AppMsg;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);


    //Pipes erzeugen
    sa.nLength=sizeof(sa);
    sa.bInheritHandle=TRUE;
    sa.lpSecurityDescriptor=NULL;
    bOK = CreatePipe(&hReadPipe, &hWritePipe, &sa, 1048576);
    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        bOK = FALSE;
        goto PROCESS_END_NOPIPE;
    }

    //Pipes eintragen
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
    si.hStdOutput = hWritePipe;                        //Schreib-Ende der Pipe an Prozess übergeben
    si.hStdError = hWritePipe;                        //Schreib-Ende der Pipe an Prozess übergeben
    si.wShowWindow = SW_SHOWMINNOACTIVE;

    //Prozess starten
    bOK = CreateProcess(NULL,
                        pcCommandLine,
                        NULL,
                        NULL,
                        TRUE,
                        NORMAL_PRIORITY_CLASS,
                        NULL,
                        NULL,
                        &si,
                        &pi);

    if(!bOK)
    {
        //FEHLER
        dwError = GetLastError();
        goto PROCESS_END_NOPROC;
    }

    //Auf Ende warten und Messages lesen
    while(dwWaitResult != WAIT_OBJECT_0)
    {
        dwWaitResult = WaitForSingleObject(pi.hProcess, 10);
        while(dwSizeLow = GetFileSize(hReadPipe, &dwSizeHigh))
        {
            ZeroMemory(cReadLine, MAX_LINE_LENGTH);
            //Aus dem Leseende der Pipe die Progzessausgaben lesen
            if(bDoRead = ReadFile(hReadPipe, cReadLine, MAX_LINE_LENGTH - 1, &dwBytesRead, NULL))
            {
                if(dwBytesRead)
                {
                    //**** hier Programmausgabe verarbeiten (z.B. send) *******
                    send(s, cReadLine, strlen(cReadLine), 0);
                }
            }
            else
            {
                bOK = FALSE;
                dwError = GetLastError();
            }
        }
        //Applikations-Messagequeue verarbeiten
        if(PeekMessage(&AppMsg, 0, 0, 0, PM_NOREMOVE))
        {
            GetMessage(&AppMsg, 0, 0, 0);
            TranslateMessage(&AppMsg);
            DispatchMessage(&AppMsg);
        }
    }

    if(bOK)
    {
        bOK = GetExitCodeProcess(pi.hProcess, &dwExitCode);
        if(bOK)
        {
            if(dwExitCode != 0)
            {
                //Prozess kehrt mit Ergebnis != 0 zurück
                bOK = FALSE;
            }
        }
        else
        {
            //FEHLER im GetExitCodeProcess
            dwError = GetLastError();
            bOK = FALSE;
        }
    }

    //Close handles
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

PROCESS_END_NOPROC:
    CloseHandle(hWritePipe);
    CloseHandle(hReadPipe);

PROCESS_END_NOPIPE:
    return bOK;
}




int main(int argc, char* argv[]) 
{ 
    if(argc > 1)
    {
        //Startet auf dem übergebenem PORT
        int PORT = atoi(argv[1]);
    
       // SOCKET welcher neue Verbindungen annimmt 
       // SOCKET which accepts new connections 
       SOCKET acceptSocket; 
       SOCKADDR_IN addr; 
       int rc,addrsize=sizeof(SOCKADDR_IN); 
       unsigned int i,j; 
       // fd_set 
       fd_set fdSetRead; 
       // timout für select() / timeout for select() 
       timeval selectTimeout; 
       // temporär benutz für neue verbindungen 
       // temporary used for new connections 
       Connection newConnection; 
       // buffer 
       char buf[1024]; 

       // clients array leeren / clear clients array 
       memset(clients,0x0,sizeof(Connection)*MAX_CLIENTS); 

       // start winsock 
       rc=startWinsock(); 
       if(rc==SOCKET_ERROR) 
          return 1; 

       // socket erstellen / create socket 
       acceptSocket=socket(PF_INET,SOCK_STREAM,0); 
       if(acceptSocket==INVALID_SOCKET) 
       { 
          printf("Error, cannot create socket: %d\n",WSAGetLastError()); 
          return 1; 
       } 

       // sockt an port 1234 binden / bind socket to port 1234 
       memset(&addr,0,sizeof(SOCKADDR_IN)); 
       addr.sin_family=AF_INET; 
       addr.sin_port=htons(PORT); 
       addr.sin_addr.s_addr=INADDR_ANY; 
       rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN)); 
       if(rc==SOCKET_ERROR) 
       { 
          printf("Error, bind() failed: %d\n",WSAGetLastError()); 
          return 1; 
       } 

       // auf verbindungen warten / listen for connections 
       rc=listen(acceptSocket,10); 
       if(rc==SOCKET_ERROR) 
       { 
          printf("Error,listen() failed: %d\n",WSAGetLastError()); 
          return 1; 
       } 


       // The parameter readfds identifies the sockets that are to be checked for readability. 
       // If the socket is currently in the listen state, it will be marked as readable if an 
       // incoming connection request has been received such that an accept is guaranteed to 
       // complete without blocking. 
        
       while(1) 
       { 

          // fd_set leeren / clear fd_set 
          FD_ZERO(&fdSetRead); 
           
          // den socket welcher verbindungen annimmt hinzufügen 
          // add the SOCKET which accepts new connections 
           
          FD_SET(acceptSocket,&fdSetRead); 
          // alle clients hinzufügen 
          // add all clients 
          for(i=0;i<MAX_CLIENTS;i++) 
          { 
             if(clients[i].used) 
                FD_SET(clients[i].socket,&fdSetRead); 
          } 

          // warten bis irgend ein socket bereit ist, wenn timout NULL ist kehrt select() 
          // erst zurück wenn ein socket bereit ist, select() blockt also in diesem falle 
          // wait until any socket is ready (timeout = NULL, block until one socket is ready) 
          rc=select(0,&fdSetRead,NULL,NULL,NULL); 

          // abbrechen bei einem fehler 
          // break on error 
          if(rc<1) 
             break; 

          printf("select() returned %d ready sockets\n",rc); 
           
          for(i=0;i<fdSetRead.fd_count;i++) 
          { 
           
             // acceptSocket ? 
             if(fdSetRead.fd_array[i]==acceptSocket) 
             { 
                // verbindung annehmen / accept new connection 
                newConnection.socket=accept(acceptSocket,(SOCKADDR*)&newConnection.addr,&addrsize); 
                rc=getFreeClientSlot(); 
                if(rc==-1) 
                { 
                   printf("Cannot accept new clients\n"); 
                   continue; 
                } 
                // zu den clients hinzufügen 
                // add to clients 
                clients[rc]=newConnection; 
                clients[rc].used=true; 
                printf("New Client accepted from %s\n",inet_ntoa(newConnection.addr.sin_addr)); 
                continue; 
             } 
              
             // ein client ? 
             // a client ? 
             for(j=0;j<MAX_CLIENTS;j++) 
             { 
                if(!clients[j].used) 
                   continue; 

                if(clients[j].socket==fdSetRead.fd_array[i]) 
                { 
                   rc=recv(clients[j].socket,buf,1023,0); 
                   buf[rc]='\0'; 
                   // rc==0 => client hat die verbindung beendet 
                   if(rc==0) { 
                      printf("Client %d (%s): closed connection\n",j,inet_ntoa(clients[j].addr.sin_addr)); 
                      closesocket(clients[j].socket); 
                      clients[j].erase(); 
                      continue; 
                   // rc==SOCKET_ERROR => fehler, verbindung beenden! 
                   } 
                   else if(rc==SOCKET_ERROR) 
                   { 
                      printf("Client %d (%s): Error %d\n",j,inet_ntoa(clients[j].addr.sin_addr),WSAGetLastError()); 
                      printf("Client %d (%s): Server aborts connection\n",j,inet_ntoa(clients[j].addr.sin_addr)); 
                      closesocket(clients[j].socket); 
                      clients[j].erase(); 
                      continue; 
                   // daten empfangen und an alle clients senden 
                   } 
                   else 
                   { 
                       printf("Client %d (%s): Befehl: '%s' \n",j,inet_ntoa(clients[j].addr.sin_addr),buf); 
                      //sendToAllClients(buf); 
                      
                      string command = buf;
                      if(command.find(' ') != string::npos)
                      {                          
                          int pos = command.find(' ');   
                          int lang = command.length();
                            string task = command.substr(0,pos);
                          string para = command.substr(pos+1,lang);

                          string str;
                          str += '"';
                          str += reg.xmd_GetValue("bin");
                          str += "\\";
                          str += task;
                          str += ".exe";
                          str += '"';
                          str += " " + para;
                                                    
                          cout << "Erfolgreich: " << ProcessCommandLine(cvt.StringToChar(str), clients[j].socket) << endl;
                      }
                      
                      else
                      {                            
                         if(command == "close")                        
                         {
                             //rc=send(clients[i].socket,msg,strlen(msg),0); 
                             //  rc=send(clients[j].socket,task.c_str(),strlen(task.c_str()),0); 
                             closesocket(acceptSocket); 
                             WSACleanup();
                         }                         
                         cout << "Erfolgreich: " << ProcessCommandLine(cvt.StringToChar(command), clients[j].socket) << endl;
                      }          

                   } 
                } 
             } 
          }

          cout << "-----------------------------------" << endl;
       }//Ende while

       // aufräumen 
       closesocket(acceptSocket); 
       WSACleanup();        
    }
    else 
    {
        cout << "server PORT" << endl;
    }
    
    return 0;   
}
```


----------



## jokey2 (19. September 2006)

Sorry, aber da kann ich Dir leider nicht helfen. Mit der Netzwerkprogrammierung kenne ich mich nämlich nicht sehr gut aus.
Aber was meinst Du mit 'kommt zu spät an'?


----------



## partitionist (19. September 2006)

Also es kommt die Ausgabe der einzelnen *.exe die umgeleitet wurden zu spät beim client an, d.h. wenn ich ein befehl eingebe wie z.B. info dann Enter drücke kommt nicht nach dem ersten sondern nach dem zweiten Enter die Ausgabe. Eigentlich sollte es so aussehen Eingabe = Enter = Ausgabe.

Vielleicht kannst du es mal dir ausprobieren, du müsstes eine dritte test.exe erstellen die einfach mit cout etwas ausgibt dann alle drei Programme ins gleiche Verzeichnis kopieren.


----------

