[Problem] RPG-Server Programmierung unter Linux
-
ich habe das Problem, dass mein Server plötzlich einen Speicherzugriffsfehler hat
. Und zwar genau nach dem ich zum ersten mal sende (ich teste mit telnet) :p
hier die ausgabe des programms:
-------------------------------- MyRPG Offical Server v0.2 (c) by xxxxxxxxxxxxxx and xxxxxxxxxxxx -------------------------------- Socket created... Socket bind to port 52440 ... Socket is listening... Waiting for client to connect... New Client (IP: 127.0.0.1) <----------- ich mit telnet Creating Thread for new client... Done. Waiting for client to connect... <----------- pause. dann gebe ich in telnet was ein. /bin/sh: line 1: 15544 Speicherzugriffsfehler /home/xxx/cpp/RPGServer1/debug/./src/rpgserver1
und der code:
#ifdef HAVE_CONFIG_H #include <config.h> #endif #include <iostream> #include <cstdlib> #include <pthread.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <list> #include <string.h> #define RPG_PORT 52440 #define BUFSIZE 1024 using namespace std; void *handleClient ( void * ); int send_ex ( int sock, char* text ) { char buf[BUFSIZE]; strcpy ( buf,text ); return send ( sock,buf,strlen ( buf ),0 ); } string recv_ex ( int sock ) { char buf[BUFSIZE]; int bytes = recv ( sock, buf, sizeof ( buf )-1,0 ); buf[bytes] = '\0'; return (string)buf; } int create_server ( int port, int& size ) { int s; struct sockaddr_in addr; s = socket ( AF_INET,SOCK_STREAM,0 ); if ( s == -1 ) { return -1; } printf ( "Socket created...\n" ); addr.sin_addr.s_addr = inet_addr ( "0.0.0.0" ); addr.sin_port = htons ( port ); addr.sin_family = AF_INET; size = sizeof ( addr ); if ( bind ( s, ( struct sockaddr * ) &addr, sizeof ( addr ) ) == -1 ) { return -1; } printf ( "Socket bind to port %d ...\n",RPG_PORT ); if ( listen ( s,3 ) == -1 ) { return -1; } printf ( "Socket is listening...\n" ); return s; } int main ( int argc, char *argv[] ) { string msg = ""; msg += "--------------------------------\n"; msg += " MyRPG Offical Server\n"; msg += " v0.2\n"; msg += " (c) by xxxxxxxxxxxxx\n"; msg += " and xxxxxxxxxxxx\n"; msg += "--------------------------------\n\n"; printf ( "%s",msg.c_str() ); int s_sock,s_new; struct sockaddr_in c_info; int size; list<pthread_t> clthreads; pthread_t thr; s_sock = create_server ( RPG_PORT , size ); while ( true ) { printf ( "Waiting for client to connect...\n" ); s_new = accept ( s_sock, ( struct sockaddr * ) &c_info, ( socklen_t* ) &size ); printf ( "New Client (IP: %s)\n",inet_ntoa ( c_info.sin_addr ) ); printf ( "Creating Thread for new client...\n" ); pthread_create ( &thr, NULL, handleClient, ( void* ) ( int * ) s_new ); clthreads.push_back ( thr ); printf ( "Done.\n" ); } return 1; } void *handleClient ( void *ptr ) { int sock = ( int ) ( int * ) ptr; string receive = ""; char* send = ""; while ( receive != "quit" ) { receive = recv_ex ( sock ); sprintf ( send,"You send me '%s'\n",receive.c_str() ); send_ex ( sock,send ); } }
is das erste mal dass ich unter linux c++ programmiere. unter windows is mir das noch nie passiert.
-
Ich sehe beim groben Überfliegen zwei Probleme, das zweitere dürfte den Absturz verursachen:
1. Der Parameter size von accept() sollte direkt als socklen_t deklariert und vor seiner Übergabe an accept() mit sizeof(sockaddr_in) belegt werden.
2. in handleClient ist send ein Zeiger auf ein Literal der Länge 1 (nämlich ""). Wenn Du dort mit sprintf etwas draufschreibst, ist das ziemlich sicher mehr als 1 Byte. Davon ab dürfen solche Literale konstant sein. Du solltest hierfür auch die string-Klasse benutzen.
-
1. okay
2. der verlangt dort aber ein char*. wenn ich string nehme ( hab ich davor ausprobiert ) konfrontiert er mich mit fehlermeldungen, dass string nicht in char* rum kovertierbar sei.
-
ok habe es selbst herausgefunden. habe einfach die zuweisung auf die variable send weggelassen. also char* send;
edit: komisch jezt passierts beim 2.mal
-
Das ist noch schlimmer, da der Zeiger dann "irgendwohin" zeigt.
Nimm doch einen Buffer wie in send_ex/recv_ex oder .c_str() wie in receive.c_str() in handleClient. Ist ja nicht so dass das in dem Code etwas neues wäre
-
man kann auf .c_str() auch zugreifen?
edit: tatsache. nun ich hab jezt aus send ein string gemacht. jedoch bekomm ich den fehler immer noch beim 2 mal
-
Äh, aber den String dann auch nicht per sprintf beschreiben, gell? Da kannst Du dann eleganter (und richtiger) mit + machen (bei größeren Mengen evtl. mit Streams). Im Zweifel zeig nochmal den Code von handleClient, wie er jetzt ist
string send = "You send me " + receive + "\n";
-
nein. es kommt mir so vor als würde send bzw recieve in beiden threads auf der selben speicherstelle basieren.
hier noch mal handleClient:
void *handleClient ( void *ptr ) { int sock = ( int ) ( int * ) ptr; string receive = ""; string send; while ( receive != "quit" ) { receive = recv_ex ( sock ); receive = stripRN(receive); send = "You send me '"+recieve+"'\n" send_ex ( sock,send.c_str() ); } close(sock); }
-
hatte noch keiner von euch ein ähnliches problem? oder hatte bei der serverprogrammierung mit pthreads einen weg eingeschlagen der ohne diesen fehler verlief? egal ob windows oder linux.
-
madmaurice schrieb:
hatte noch keiner von euch ein ähnliches problem? oder hatte bei der serverprogrammierung mit pthreads einen weg eingeschlagen der ohne diesen fehler verlief? egal ob windows oder linux.
man sollte nicht threads nehmen, sondern lieber select() und ähnliches.
-
deine threads lauschen alle am selben socket. das muss nicht verkehrt sein, sorgt aber u.u. für probleme. da über den socket auch steuerinformationen kommen, die neue threads erzeugen, würd ich die gesamte netzwerkkommunikation in einen einzigen thread auslagern. dieser kann dann die empfangenen daten filtern und den entsprechenden reveivern zuweisen.
-
@joomoo habe von select noch nicht gehört werde aber mal danach googeln
@thordk falsch. meine threads lauschen gar nicht. sie bekommen alle ein eigenes socket (den int wert den accept() zurückgibt) zugewiesen. dieser int wert wird per parameter an den thread übergeben.
-
Nur mal nebenbei:
char buf[BUFSIZE]; ... return (std::string)buf;
Das ist doch nicht valid?!
-
ich habe das nach einem thread in einem forum gemacht.
dort wird gesagt man soll das folgendermaßen machen:
char buf[]; string string1(buf);
also müsste das auch mit
(string)buf
gehen oder?
Hast du eine bessere Idee Kenny?
-
madmaurice schrieb:
ich habe das nach einem thread in einem forum gemacht.
dort wird gesagt man soll das folgendermaßen machen:
char buf[]; string string1(buf);
also müsste das auch mit
(string)buf
gehen oder?
Hast du eine bessere Idee Kenny?
Das eine ist ein Konstruktoraufruf, und das andere ein C-Style-Cast.
Man sollte in C++ möglichgst static_cast, reinterpret_cast etc. nutzen.
char buf[]; ... return std::string(buf);
Sollte das sein, was du suchst.
(Erzeugt ein temporäres String-Objekt mit dem Inhalt von buf und gibt dies zurück)
-
@kenny
habs geändert.jedoch löst das problem damit nicht.
@joomoo
ich finde leider keine tutorial bzw eine referenz die auf select() hinweißt.hast du da einen link?
-
-
ich blick in diesem select() nicht durch.
gibt es keinen weg das mit pthreads zu lösen?
-
doch, aber der ist scheiße
-
wenn ich richtig verstehe ist select() eine möglichkeit zu schauen ob eine neuer client connecten will bzw daten gesendet hat!?