Hilfe beim Client/Server...
-
Hallo Leute, ich habe ein Client und Server. Der Client übergibt dem Server ein Befehl der dann eine bestimmte *.exe startet. Diese Ausgabe des Befehls wird vom Server an den Client umgeleitet. Das Problem ist, dass die Ausgabe vom Server zu spät beim Client ankommt, d.h. wenn ich ein Befehl eingabe und Enter drücke, dann kommt nicht sofort die Ausgabe beim Client an, sondern nach einem zweiten Enter.
Könntet Ihr euch das bitte anschaun.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; }
-
kernel64 schrieb:
Könntet Ihr euch das bitte anschaun.
versuch den fehler weiter einzugrenzen (bau z.b. überall debug-ausgaben ein)...
-
Habe im mittleren Teil vom Client folgendes eingefügt:
//Eingabe des Befehl 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()); } cout << "vor While..." << endl; // 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) { cout << "in while..." << endl; 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; } cout << "empfange..." << endl; // empfangene daten ausgeben buf[rc]='\0'; cout << buf << endl; } cout << "nach While()" << endl;Folgendes passiert wenn ich test eingebe: (test ist eine test.exe mit einer Ausgabe)
Eingabe: test //test dann Enter
vor While...
nach While()
//keine AusgabeEingabe: //hier nichts eingegeben und dann Enter gedrückt
vor While...
in While...
empfange...
....//Hier kommt die Ausgabe von test
nach while()Wie man sieht wird bei der ersten eingabe die while schleife nicht abgearbeitet.
Woran kann das liegen ist der server fehlerhaft??
Bitte um Hilfe!
-
Hi
Hab ehrlich gesagt keine Lust, deinen kompletten Code durchzusehen (bin aber drübergeflogen). Und ein Tip: Poste nicht zuviel Code (das da ist definitiv zu viel! Das treibt nämlich potenziellen Helfern die Lust am helfen aus!
<- Nicht böse gemeint
Zu deinem Problem:
Wenn man die Ausgabe richtig deutet, wird in deinem Fall bei der Eingabe von "test" folgende Zeilewhile((rc=select(0,&fdSetRead,NULL,NULL,&timeout))>0)abgearbeitet und select gibt irgendwas kleiner gleich 0 zurück. Logisch, oder? Immerhin geht er gar nicht erst in die Schleife rein. Also finde am besten erstmal raus, warum select <= 0 zurückgibt. Gib für diesen Fall z.B. mal "rc" aus.
-
Hab folgendes ergänzt:
//vor der schleife cout << "vor While..." << endl; cout << "rc:" << rc << endl; while((rc=select(0,&fdSetRead,NULL,NULL,&timeout))>0) { cout << "in while..." << endl; cout << "rc:" << rc << endl; //... } cout << "nach While()" << endl; cout << "rc:" << rc << endl;Folgendes wird ausgegeben wenn ich ein Befehl eingebe:
Eingabe: test //Befehl
vor While...
rc:4
nach While()
rc:0Eingabe: //hier nichts eingegeben und dann Enter gedrückt
vor While...
rc:0
in while...
rc:1
empfange...
...//Hier kommt die Ausgabe von test
nach While()
rc:0
-
Das ist doch schonmal was! Aber könntest ja auch mal selber versuchen, deine Ausgaben zu interpretieren :p
Naja, also:
Bei dieser Ausgabe: "cout << "rc:" << rc << endl;" ist rc ja der Rückgabewert von send(...). Nachschauen-> send gibt die Anzahl von Bytes zurück, die gesendet wurden. Also wurden erfolgreich die 4 Bytes ("test") gesendet! Das funktioniert also!
Der Eintritt in die While-Schleife scheitert und select hat 0 zurückgegeben. Bedeutet, dass nix angekommen ist, in dieser kurzen Zeit.

Bei der nächsten Eingabe (bei dir "" <-Nix) ruft er wieder select auf und siehe da
Es wartet ein Paket.
Daraus könnte man schlussfolgern, dass das erste select so schnell aufgerufen wurde (direkt nach dem senden), dass das Paket in der kurzen Zeit noch gar nicht angekommen ist!
Ist das nicht eine Erkenntnis
? Lass dem Paket also ein bisschen Zeit, dann müsste es funktionieren, scheint ja sonst alles korrekt zu sein.Mit freundlichen Grüßen,
Badestrand
-
Das was du meinst hab ich auch die ganze Zeit gedacht, dass beim Client die Daten viel zu früh erwartet werden. Hab den Client mal mit dem debugger gestartet also mit F10 und gabs keine Probleme, da hier alles Schritt für Schritt abgearbeitet wird, deshalb sind alle Daten angekommen.
Lass dem Paket also ein bisschen Zeit, dann müsste es funktionieren, scheint ja sonst alles korrekt zu sein.Also ich werde ein Sleep(1000) einbauen, mal sehn wie es dann läuft.
Danke nochmals für die Erkenntnis.[Edit] Es funktioniert danke
habe für Sleep(500) eingesetzt müsste ausreichen.
Wie sieht es mit dem Buffer aus, der dritte parameter bei recv() send()?recv(s,buf,1024,0);Soll da 1024 oder 1023 stehn?
-
Bin froh, dass es doch noch geklappt hat!
kernel64 schrieb:
Wie sieht es mit dem Buffer aus, der dritte parameter bei recv() send()?
recv(s,buf,1024,0);Soll da 1024 oder 1023 stehn?
Da dein Buffer 1024 Byte groß ist, stimmt das schon mit der 1024. Da du allerdings das letzte Zeichen auf '\0' setzt, mach lieber 1023. Wenn du nämlich 1024 Bytes an Daten empfängst (Rückgabewert rc=1024), dann schreibst du mit "Buf[rc]='\0';" in das 1025-ste Byte. Das wär zuviel.
Mfg,
badestrand
-
Vielen vielen Dank, endlich klappts

Hatte immer ein fehler wenn ich den client beendet habe:'buf' Stack corrupted
Wahrscheinlich wegen denn 1024
-
Noch ne kleine Frage nebenbei, wie soll ich folgendes senden:
string pc; pc += "host:"; pc += ComputerName(); pc += "\n";Habe es so gemacht:
send(s, pc.c_str(), pc.length(), 0);Wie würdest du das machen?
-
kernel64 schrieb:
Habe es so gemacht:
send(s, pc.c_str(), pc.length(), 0);Wie würdest du das machen?
Kannste doch so machen, allerdings kannste zur Verkettung auch das machen:
string pc(string("host:") + string(ComputerName()) + string("\n"));
-
Aber wie sieht das Empfangen auf der Gegenseite aus, also welche größe soll bei recv() dann verwendet werden? Die göße von pc ist ja dynamisch!
-
Du kannst ja einfach auch einen Puffer von 1024 Bytes nehmen. Wenn recv(...) dann einen Wert von 1024 zurückgibt, besteht eine gute Chance, dass noch mehr Bytes warten. Es werden dann ja schließlich nicht mehr als 1024 in deinen Puffer geschrieben!
Also dann Puffer vergrößern
Dynamischer Puffer mit new[] und delete[] oder malloc, realloc(!) und free anlegen.- Puffer anlegen mit 1024 Bytes Größe - recv mit 1024 aufrufen - Wenn recv 1024 zurückgibt, dann Puffer vergrößern und immer wieder recv mit wieder 1024 und richtiger Pufferposition aufrufen, bis recv<1024 - Dann letztes Byte auf '\0' setzen und ausgeben