Probleme mit Serverapplikation
-
Hallo!
Ich bin grade dabei eine kleine Server-Applikation zu schreiben. Leider funktioniert sie nicht 100%-ig und ich finde den Fehler nicht. Folgendes sollte eigentlich passieren. Ein Client (in meinem Fall ein JAVA-Programm) verbindet sich zum Server auf dem eingegebenen Port. Dieser Port soll zum Empfang von Steuernachrichten dienen. Die Verbindung zu meinem JAVA-Programm wird auch hergestellt. Mein JAVA-Programm sendet dann den Befehl "GET GRAPH". Daraufhin ruft mein Server die Methode sendFile auf. Dies funktioniert auch noch wunderbar. In dieser Methode sendet mein Server das Kommando "READY TO SEND GRAPH" über den Kommandoport ab und öffnet den Port 5001 für die Datenübertragung. Mein JAVA-Programm öffnet diesen Port ebenfalls und verbindet sich auch. Dann wird die entsprechende Datei übertragen. Dies funktioniert auch noch wunderbar.
Dann fangen aber die Probleme an. Eingentlich sollte der Server noch dem Senden der Datei den Port 5001 wieder schließen und in die Endlosschleife im Hauptprogramm zurückgehren, um neue Kommandos entgegenzunehmen. Dies geschieht allerdings nicht. Irgendwie bleibt das Programm in der sendFile-Methode hängen und kehrt nicht ins Hauptprogramm zurück.
Vielleicht könnt ihr mir helfen. Bin langsam am verzweifeln
#include <arpa/inet.h> #include <netdb.h> #include <netinet/in.h> #include <unistd.h> #include <iostream> #include <fstream> #define MAX_MSG 100 #define LINE_ARRAY_SIZE (MAX_MSG+1) using namespace std; void sendFile(int parentConnectSocket, char* filename) { ifstream myFile (filename, ios::in | ios::binary); char buffer[1024]; int listenSocket, connectSocket; socklen_t clientAddressLength; struct sockaddr_in clientAddress, serverAddress; //Create socket for listening for client connection requests. listenSocket = socket(AF_INET, SOCK_STREAM, 0); if (listenSocket < 0) { cerr << "cannot create listen socket"; exit(1); } // Bind listen socket to listen port serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(5001); if (bind(listenSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) { cerr << "cannot bind socket"; exit(1); } //Send ready message over commando port send(parentConnectSocket,"READY TO SEND GRAPH\n",20,0); // Wait for connections from clients listen(listenSocket, 1); cout << "Waiting for TCP connection on port " << 5001 << " ...\n"; // Accept a connection with a client that is requesting one. clientAddressLength = sizeof(clientAddress); connectSocket = accept(listenSocket, (struct sockaddr *) &clientAddress, &clientAddressLength); if (connectSocket < 0) { cerr << "cannot accept connection "; exit(1); } // Show the IP address of the client. cout << " connected to " << inet_ntoa(clientAddress.sin_addr); // Show the client's port number. cout << ":" << ntohs(clientAddress.sin_port) << "\n"; // Send the file while (!myFile.eof()) { myFile.read(buffer, 1024); send(connectSocket, buffer, 1024, 0); } // Close file and socket myFile.close(); close(listenSocket); } int main() { int listenSocket, connectSocket; unsigned short int listenPort; socklen_t clientAddressLength; struct sockaddr_in clientAddress, serverAddress; char line[LINE_ARRAY_SIZE]; cout << "Enter port number to listen on (between 1500 and 65000): "; cin >> listenPort; // Create socket for listening for client connection requests. listenSocket = socket(AF_INET, SOCK_STREAM, 0); if (listenSocket < 0) { cerr << "cannot create listen socket"; exit(1); } // Bind listen socket to listen port. First set various fields in // the serverAddress structure, then call bind(). // htonl() and htons() convert long integers and short integers // (respectively) from host byte order (on x86 this is Least // Significant Byte first) to network byte order (Most Significant // Byte first). serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(listenPort); if (bind(listenSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) { cerr << "cannot bind socket"; exit(1); } // Wait for connections from clients. // This is a non-blocking call; i.e., it registers this program with // the system as expecting connections on this socket, and then // this thread of execution continues on. listen(listenSocket, 5); while (1) { cout << "Waiting for TCP connection on port " << listenPort << " ...\n"; // Accept a connection with a client that is requesting one. The // accept() call is a blocking call; i.e., this thread of // execution stops until a connection comes in. clientAddressLength = sizeof(clientAddress); connectSocket = accept(listenSocket, (struct sockaddr *) &clientAddress, &clientAddressLength); if (connectSocket < 0) { cerr << "cannot accept connection "; exit(1); } // Show the IP address of the client. // inet_ntoa() converts an IP address from binary form to the // standard "numbers and dots" notation. cout << " connected to " << inet_ntoa(clientAddress.sin_addr); // Show the client's port number. // ntohs() converts a short int from network byte order (which is // Most Significant Byte first) to host byte order (which on x86, // for example, is Least Significant Byte first). cout << ":" << ntohs(clientAddress.sin_port) << "\n"; while (1) { memset(line, 0x0, LINE_ARRAY_SIZE); while (recv(connectSocket, line, MAX_MSG, 0) > 0) { cout << " -- " << line << "\n"; //Auf Befehle abfragen if (strcmp(line,"GET GRAPH")==0) { cout << "Kommando erhalten: GET GRAPH\n"; sendFile(connectSocket,"2.jpg"); } cout << "Wieder zurück im Hauptprogramm"; memset(line, 0x0, LINE_ARRAY_SIZE); // set line to all zeroes } } } }
-
wieso verwendest du so eine komplizierte methode? wäre es nicht sinnvoller, die daten des graphs einfach in der bestehenden verbindung zu senden?
listen(listenSocket, 1);
muss vor
send(parentConnectSocket,"READY TO SEND GRAPH\n",20,0);
kommen.
ready ist der server erst nach dem listen.
außerdem könnte die funktion sendfile(2) ansehen hilfreich sein.
-
Hallo!
listen(listenSocket, 1);
muss nicht vor
send(parentConnectSocket,"READY TO SEND GRAPH\n",20,0);
steht. Mit send(parentConnectSocket,"READY TO SEND GRAPH\n",20,0); sende ich eine Nachricht über die schon bestehende Verbindung für die Steuerdaten.
Den zweiten Port öffne ich, da ich sonst in Java Probleme bekomme die Steuerdaten und die Binärdaten auseinanderzuhalten, da ich dafür verschiedene InputStreamReader benutze.
-
bevor du listen ausgeführt hast, ist der port noch kein server. nichts hört daran, ob verbindungen reinkommen. schickst du jetzt das ready ab, bevor der port offen ist, kann der client versuchen, vor dem listen auf den vermeintlichen server port zuzugreifen. das ist mein argument. welches ist deines, dass man das listen nicht vor dem ready schreiben muss?
-
OK, jetzt verstehe ich deinen Einwand.
Hab die Reihenfolge der Kommandos vertauscht. Leider besteht das Problem immer noch. Die Verbindung über den Datenport 5001 funktioniert und die Datei wird fehlerfrei übertragen. Allerdings bleibt das Programm irgendwie hängen und nimmt keine Befehle auf der Befehlsleitung mehr entgegen.
-
es fällt noch auf, dass du zwar listenSocket schließt, aber nicht connectSocket n der funktion sendFile. das wird aber nicht das problem sein.
du hast sehr viele while schleifen drin. in der hauptfunktion sind 3 schleifen drin. zwei endlos und eine mit recv. die erste endlos nimmt neue verbindungen auf. die zweite endlosschleife geht um die dritte mit receive herum. die liest dann wohl befehle nach der reihe ein. das problem hier ist wohl, dass du aus der nie heraus kommst und damit und sich nie neue clients verbinden können, da das accept nie mehr aufgerufen wird. kann es sein, dass die zweite while endlosschleife unnötig ist? sobald connectedSocket der hauptfunktion geschlossen wird, dreht die zweite endlosschleife auch wirklich endlos herum und ruft zuerst das memset für die zeile auf und dann das zweite while, das immer fehlschlägt. dann geht es wieder von vorne los.
-
Hab die eine unnötige while-Schleife herausgenommen. Leider besteht das Problem weiterhin. Ich hab mal die Ausgabe meines Serverprogramms zur Analyse angehängt.
Enter port number to listen on (between 1500 and 65000): 5000 Waiting for TCP connection on port 5000 ... connected to 127.0.0.1:33994 -- GET GRAPH Kommando erhalten: GET GRAPH Waiting for TCP connection on port 5001 ... connected to 127.0.0.1:59216
Mir ist immer noch nicht klar, warum ich aus der sendFile Methode nicht mehr herauskomme. Hab dort jetzt noch eine Ausgabe hinzugefügt, wenn die Datei komplett übertragen wird. Doch scheinbar wird die Zeile gar nicht erreicht.
#include <arpa/inet.h> #include <netdb.h> #include <netinet/in.h> #include <unistd.h> #include <iostream> #include <fstream> #define MAX_MSG 100 #define LINE_ARRAY_SIZE (MAX_MSG+1) using namespace std; void sendFile(int parentConnectSocket, char* filename) { ifstream myFile (filename, ios::in | ios::binary); char buffer[1024]; int listenSocket, connectSocket; socklen_t clientAddressLength; struct sockaddr_in clientAddress, serverAddress; //Create socket for listening for client connection requests. listenSocket = socket(AF_INET, SOCK_STREAM, 0); if (listenSocket < 0) { cerr << "cannot create listen socket"; exit(1); } // Bind listen socket to listen port serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(5001); if (bind(listenSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) { cerr << "cannot bind socket"; exit(1); } //Send ready message over commando port send(parentConnectSocket,"READY TO SEND GRAPH\n",20,0); // Wait for connections from clients listen(listenSocket, 1); cout << "Waiting for TCP connection on port " << 5001 << " ...\n"; // Accept a connection with a client that is requesting one. clientAddressLength = sizeof(clientAddress); connectSocket = accept(listenSocket, (struct sockaddr *) &clientAddress, &clientAddressLength); if (connectSocket < 0) { cerr << "cannot accept connection "; exit(1); } // Show the IP address of the client. cout << " connected to " << inet_ntoa(clientAddress.sin_addr); // Show the client's port number. cout << ":" << ntohs(clientAddress.sin_port) << "\n"; // Send the file while (!myFile.eof()) { myFile.read(buffer, 1024); //cout << myFile.gcount(); send(connectSocket, buffer, myFile.gcount(),0); if (myFile.gcount()<1024) return; } // Close file and socket cout << "Dateiauslesen abgeschlossen"; myFile.close(); close(listenSocket); } int main() { int listenSocket, connectSocket; unsigned short int listenPort; socklen_t clientAddressLength; struct sockaddr_in clientAddress, serverAddress; char line[LINE_ARRAY_SIZE]; cout << "Enter port number to listen on (between 1500 and 65000): "; cin >> listenPort; // Create socket for listening for client connection requests. listenSocket = socket(AF_INET, SOCK_STREAM, 0); if (listenSocket < 0) { cerr << "cannot create listen socket"; exit(1); } // Bind listen socket to listen port. First set various fields in // the serverAddress structure, then call bind(). // htonl() and htons() convert long integers and short integers // (respectively) from host byte order (on x86 this is Least // Significant Byte first) to network byte order (Most Significant // Byte first). serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(listenPort); if (bind(listenSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) { cerr << "cannot bind socket"; exit(1); } // Wait for connections from clients. // This is a non-blocking call; i.e., it registers this program with // the system as expecting connections on this socket, and then // this thread of execution continues on. listen(listenSocket, 5); cout << "Waiting for TCP connection on port " << listenPort << " ...\n"; // Accept a connection with a client that is requesting one. The // accept() call is a blocking call; i.e., this thread of // execution stops until a connection comes in. // connectSocket is a new socket that the system provides, // separate from listenSocket. We *could* accept more // connections on listenSocket, before connectSocket is closed, // but this program doesn't do that. clientAddressLength = sizeof(clientAddress); connectSocket = accept(listenSocket, (struct sockaddr *) &clientAddress, &clientAddressLength); if (connectSocket < 0) { cerr << "cannot accept connection "; exit(1); } // Show the IP address of the client. // inet_ntoa() converts an IP address from binary form to the // standard "numbers and dots" notation. cout << " connected to " << inet_ntoa(clientAddress.sin_addr); // Show the client's port number. // ntohs() converts a short int from network byte order (which is // Most Significant Byte first) to host byte order (which on x86, // for example, is Least Significant Byte first). cout << ":" << ntohs(clientAddress.sin_port) << "\n"; while (1) { memset(line, 0x0, LINE_ARRAY_SIZE); while (recv(connectSocket, line, MAX_MSG, 0) > 0) { cout << " -- " << line << "\n"; //Auf Befehle abfragen if (strcmp(line,"GET GRAPH\n")==0) { cout << "Kommando erhalten: GET GRAPH\n"; sendFile(connectSocket,"2.jpg"); } cout << "Wieder zurück im Hauptprogramm"; memset(line, 0x0, LINE_ARRAY_SIZE); // set line to all zeroes } } }
-
Oh ich sehe grade, dass ich die eine alte Version meines Quellcodes angefügt hatte. Richtig ist dies:
#include <arpa/inet.h> #include <netdb.h> #include <netinet/in.h> #include <unistd.h> #include <iostream> #include <fstream> #define MAX_MSG 100 #define LINE_ARRAY_SIZE (MAX_MSG+1) using namespace std; void sendFile(int parentConnectSocket, char* filename) { ifstream myFile (filename, ios::in | ios::binary); char buffer[1024]; int listenSocket, connectSocket; socklen_t clientAddressLength; struct sockaddr_in clientAddress, serverAddress; //Create socket for listening for client connection requests. listenSocket = socket(AF_INET, SOCK_STREAM, 0); if (listenSocket < 0) { cerr << "cannot create listen socket"; exit(1); } // Bind listen socket to listen port serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(5001); if (bind(listenSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) { cerr << "cannot bind socket"; exit(1); } //Send ready message over commando port send(parentConnectSocket,"READY TO SEND GRAPH\n",20,0); // Wait for connections from clients listen(listenSocket, 1); cout << "Waiting for TCP connection on port " << 5001 << " ...\n"; // Accept a connection with a client that is requesting one. clientAddressLength = sizeof(clientAddress); connectSocket = accept(listenSocket, (struct sockaddr *) &clientAddress, &clientAddressLength); if (connectSocket < 0) { cerr << "cannot accept connection "; exit(1); } // Show the IP address of the client. cout << " connected to " << inet_ntoa(clientAddress.sin_addr); // Show the client's port number. cout << ":" << ntohs(clientAddress.sin_port) << "\n"; // Send the file while (!myFile.eof()) { myFile.read(buffer, 1024); //cout << myFile.gcount(); send(connectSocket, buffer, myFile.gcount(),0); } // Close file and socket cout << "Dateiauslesen abgeschlossen"; myFile.close(); close(listenSocket); } int main() { int listenSocket, connectSocket; unsigned short int listenPort; socklen_t clientAddressLength; struct sockaddr_in clientAddress, serverAddress; char line[LINE_ARRAY_SIZE]; cout << "Enter port number to listen on (between 1500 and 65000): "; cin >> listenPort; // Create socket for listening for client connection requests. listenSocket = socket(AF_INET, SOCK_STREAM, 0); if (listenSocket < 0) { cerr << "cannot create listen socket"; exit(1); } // Bind listen socket to listen port. First set various fields in // the serverAddress structure, then call bind(). // htonl() and htons() convert long integers and short integers // (respectively) from host byte order (on x86 this is Least // Significant Byte first) to network byte order (Most Significant // Byte first). serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(listenPort); if (bind(listenSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) { cerr << "cannot bind socket"; exit(1); } // Wait for connections from clients. // This is a non-blocking call; i.e., it registers this program with // the system as expecting connections on this socket, and then // this thread of execution continues on. listen(listenSocket, 5); cout << "Waiting for TCP connection on port " << listenPort << " ...\n"; // Accept a connection with a client that is requesting one. The // accept() call is a blocking call; i.e., this thread of // execution stops until a connection comes in. // connectSocket is a new socket that the system provides, // separate from listenSocket. We *could* accept more // connections on listenSocket, before connectSocket is closed, // but this program doesn't do that. clientAddressLength = sizeof(clientAddress); connectSocket = accept(listenSocket, (struct sockaddr *) &clientAddress, &clientAddressLength); if (connectSocket < 0) { cerr << "cannot accept connection "; exit(1); } // Show the IP address of the client. // inet_ntoa() converts an IP address from binary form to the // standard "numbers and dots" notation. cout << " connected to " << inet_ntoa(clientAddress.sin_addr); // Show the client's port number. // ntohs() converts a short int from network byte order (which is // Most Significant Byte first) to host byte order (which on x86, // for example, is Least Significant Byte first). cout << ":" << ntohs(clientAddress.sin_port) << "\n"; while (1) { memset(line, 0x0, LINE_ARRAY_SIZE); while (recv(connectSocket, line, MAX_MSG, 0) > 0) { cout << " -- " << line << "\n"; //Auf Befehle abfragen if (strcmp(line,"GET GRAPH\n")==0) { cout << "Kommando erhalten: GET GRAPH\n"; sendFile(connectSocket,"2.jpg"); } cout << "Wieder zurück im Hauptprogramm"; memset(line, 0x0, LINE_ARRAY_SIZE); // set line to all zeroes } } }
-
in dem fall scheine ich das nicht besser zu wissen :-).
er scheint in der schleife zum auslesen der datei hängen zu bleiben. du könntest mit der methode good() prüfen, ob beim auslesen der datei irgendwas schief gelaufen ist und er deshalb immer in der schleife bleibt. ein cout in der schleife wäre vielleicht auch hilfereich.