tcp server
-
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netdb.h> #include <iostream> #include <stdlib.h> #include <string> #include <ctype.h> #include <pthread.h> #include <sstream> using namespace std; #define PORT 1550 #define MAX_MSG 100 #define LINE_ARRAY_SIZE (MAX_MSG+1) void *fchatter(int *connectSocket) { char line[LINE_ARRAY_SIZE]; memset(line, 0x0, LINE_ARRAY_SIZE); while (recv(*connectSocket, line, MAX_MSG, 0) > 0) { cout << " -- " << line << "\n"; int i; for (i = 0; line[i] != '\0'; i++) line[i] = toupper(line[i]); if (send(*connectSocket, line, strlen(line) + 1, 0) < 0) cerr << "Error: cannot send modified data"; memset(line, 0x0, LINE_ARRAY_SIZE); // set line to all zeroes } } int main() { int listenSocket, connectSocket, i; unsigned short int listenPort; socklen_t clientAddressLength; struct sockaddr_in clientAddress, serverAddress; char line[LINE_ARRAY_SIZE]; listenPort = PORT; listenSocket = socket(AF_INET, SOCK_STREAM, 0); if (listenSocket < 0) { cerr << "cannot create listen socket"; exit(1); } 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); } listen(listenSocket, 5); while (1) { cout << "Waiting for TCP connection on port " << listenPort << " ...\n"; clientAddressLength = sizeof(clientAddress); connectSocket = accept(listenSocket, (struct sockaddr *) &clientAddress, &clientAddressLength); if (connectSocket < 0) { cerr << "cannot accept connection "; exit(1); } cout << " connected to " << inet_ntoa(clientAddress.sin_addr); cout << ":" << ntohs(clientAddress.sin_port) << "\n"; pthread_t chatter; cout << "1" << connectSocket << endl; pthread_create(&chatter, NULL,&fchatter,(int *) connectSocket); } }
sobald sich ein client verbindet beendet sich der server mit segmentation fault
-
moin,
du bindest zum Ersten die stdlib.h zweimal ein!
Wo und wann bricht er denn ab, was spricht der debugger?
-
steff schrieb:
moin,
du bindest zum Ersten die stdlib.h zweimal ein!
Wo und wann bricht er denn ab, was spricht der debugger?danke,
hab den gdb zuvor noch nie verwendet(gdb) r
Starting program: /root/tpchatd
[New Thread 1024 (LWP 23465)]
Waiting for TCP connection on port 1550 ...
connected to xxx.xxx.30.233:1554
18
[New Thread 2049 (LWP 23473)]
[New Thread 1026 (LWP 23474)]
Waiting for TCP connection on port 1550 ...Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 1026 (LWP 23474)]
0x080491b3 in fchatter (connectSocket=0x8) at tpchatd.cpp:31
31 cerr << "Error: cannot send modified data";
(gdb)memset(line, 0x0, LINE_ARRAY_SIZE)
hab ich raus weil line sowieso nur in der funktion steht
kann die ausgabe vom gdb jemand interpretieren?
ich bin da noch etwas überfordert
-
debian inside schrieb:
memset(line, 0x0, LINE_ARRAY_SIZE)
hab ich raus weil line sowieso nur in der funktion steht
Daran wirds aber IMO nicht liegen, weil diese Zeile korrekt ist.
kann die ausgabe vom gdb jemand interpretieren?
ich bin da noch etwas überfordertNach einem SIGSEGV fragt man denn gdb üblicherweise noch "where". Tu das und wir wissen mehr.
-
debian inside schrieb:
if (send(*connectSocket, line, strlen(line) + 1, 0) < 0)
Dumme Frage, aber warum "strlen(line)+1"?
-
nman schrieb:
debian inside schrieb:
if (send(*connectSocket, line, strlen(line) + 1, 0) < 0)
Dumme Frage, aber warum "strlen(line)+1"?
+1 stellt der rückgabe ein leerzeichen voran
wenn ich connectSocket als globalen int verwende klappts
ich versteh die übergabe von pthread_create in die funktion nichtwenn der socket in main 8 hat wir er durch diese übergabe 0x8
-
0x8 ist eine Hexadezimalzahl und eine andere Darstellung für Dezimal 8
Und das +1 sorgt nur dafür, dass eine terminierende 0 mit gesendet wird.
Schau mal mit bt nach dem genaueren Fehler (mit -g vorher kompilieren).
-
kingruedi schrieb:
0x8 ist eine Hexadezimalzahl und eine andere Darstellung für Dezimal 8
Und das +1 sorgt nur dafür, dass eine terminierende 0 mit gesendet wird.
Schau mal mit bt nach dem genaueren Fehler (mit -g vorher kompilieren).
wirkt sich die darstellung auch irgendwie aus?
(gdb) bt
#0 0x080491b3 in fchatter (connectSocket=0x8) at tpchatd.cpp:32
#1 0x4001e0ba in pthread_start_thread () from /lib/libpthread.so.0
#2 0x4001e101 in pthread_start_thread_event () from /lib/libpthread.so.0
(gdb)keine ahnung ob ich das richtig interpretiere aber hier siehts doch so aus wie wenn die hex darstellung probleme macht oder?
-
0x080491b3 in fchatter (connectSocket=0x8) at tpchatd.cpp:31
Der Pointer connectSocket mit der Adresse 0x8 sieht nicht sehr koscher aus!
Wenn man dan schaut wo und wie die Funktion aufgerufen wird, stellt man folgendes fest:
pthread_create(&chatter, NULL,&fchatter,(int
connectSocket);
Du castest einen Integer in einen Pointer auf einen Integer.
Jetzt ein kleiner Blick auf deine Threadfunction
void *fchatter(int *connectSocket)
Jetzt muss dir bewusst sein, was connectSocket in Wirklichkeit ist. Ein Pointer auf ein Integer? Nein! Ein Integer gecasted als Pointer auf einen Integer! Also dereferenzieren ist nicht!
Die libpthread hat nicht umsonst den Parameter als void-Pointer definiert.
mfg Unixer
P.S.: Eigne dir die Basics über Pointer an
-
alle threads benutzen das selbe client socket...
sendet thread a und es connected ein neuer client (->thread b wird erzeugt)
wird der socket von thread a ueberschrieben. boese.int clientSocket; clientSocket = accept(...); ... pthread_create(&chatter, NULL,&fchatter,(int *)clientSocket ); /* -> clientSocket liegt auf dem stack, jeder thread besitzt einen zeigen auf die selbe int-var */
-> moegliche loesung: jedem thread ein mit malloc/new erzeugtes int uebergeben
(der thread raeumts am ende auf).
-
alle threads benutzen das selbe client socket...
sendet thread a und es connected ein neuer client (->thread b wird erzeugt)
wird der socket von thread a ueberschrieben. boese.Falsch!
Es heisst:
pthread_create(&chatter, NULL,&fchatter,(int *)clientSocket );
und nicht
pthread_create(&chatter, NULL,&fchatter,(int *) &clientSocket );
Man achte auf das kleine aber feine '&'
mfg unixer
-
-> moegliche loesung: jedem thread ein mit malloc/new erzeugtes int uebergeben(der thread raeumts am ende auf).
Ansich ist es kein Problem den Descriptor als Param (also der void-Pointer-Parameter) zu übergeben. Man muss beachten, dass man ihn dan auch wirklich als Descriptor verwendet und nicht als Pointer.
unixer
-
unixer schrieb:
alle threads benutzen das selbe client socket...
sendet thread a und es connected ein neuer client (->thread b wird erzeugt)
wird der socket von thread a ueberschrieben. boese.Falsch!
Es heisst:
pthread_create(&chatter, NULL,&fchatter,(int *)clientSocket );
und nicht
pthread_create(&chatter, NULL,&fchatter,(int *) &clientSocket );
Man achte auf das kleine aber feine '&'
mfg unixer
super. wenn du glueck hast funktioniert das tatsaechlich.
ansi c garantiert das nicht. das funktioniert nur, solange
ein int kleiner oder gleich der groesse eines zeigers ist;
was zwar oft aber nicht zwingend der fall ist.machs lieber indem fuer fuer jeden thread ein int allokierst
da bist du auf der sicheren seite.
-
super. wenn du glueck hast funktioniert das tatsaechlich.
ansi c garantiert das nicht. das funktioniert nur, solange
ein int kleiner oder gleich der groesse eines zeigers ist;
was zwar oft aber nicht zwingend der fall ist.Das ist wahr! Aber ich kenn keine Architektur, auf der die libpthread läuft, bei der das der Fall ist. IMHO muss man nicht solch einen Mehraufwand betreiben um diesen _sehr_ theoretischen Fall abzudecken.
mfg unixer
-
unixer schrieb:
super. wenn du glueck hast funktioniert das tatsaechlich.
ansi c garantiert das nicht. das funktioniert nur, solange
ein int kleiner oder gleich der groesse eines zeigers ist;
was zwar oft aber nicht zwingend der fall ist.Das ist wahr! Aber ich kenn keine Architektur, auf der die libpthread läuft, bei der das der Fall ist. IMHO muss man nicht solch einen Mehraufwand betreiben um diesen _sehr_ theoretischen Fall abzudecken.
mfg unixer
danke
fazit:
es darf nicht immer die selbe threadid, der selbe socket verwendet werden und ich seh mir pointer an
-
Igitt, ich weiß schon, warum ich kein C mag.
-
so das läuft jetzt
nicht unbedingt schön programmiert aber is ja schon spät und war ein langer tag#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netdb.h> #include <iostream> #include <string> #include <ctype.h> #include <pthread.h> #include <sstream> using namespace std; #define PORT 1550 #define MAX_MSG 100 #define LINE_ARRAY_SIZE (MAX_MSG+1) #define MAX_THREADS 5 int threads = 0; int thread = 0; int connectSocket[MAX_THREADS]; int threadrotate(); void *fchatter(int* thisthread) { int temp = (int) thisthread; char line[LINE_ARRAY_SIZE]; memset(line, 0x0, LINE_ARRAY_SIZE); while (recv(connectSocket[temp], line, MAX_MSG, 0) > 0) { cout << "Thread" << temp << ": " << line << "\n"; int i; for (i = 0; line[i] != '\0'; i++) line[i] = toupper(line[i]); //if (send(connectSocket[temp], line, strlen(line) + 1, 0) < 0) if (send(connectSocket[temp], line, strlen(line), 0) < 0) cerr << "Error: cannot send modified data"; memset(line, 0x0, LINE_ARRAY_SIZE); } cout << "Thread" << temp << " end" << endl; connectSocket[temp] = 0; threads--; } int main() { int listenSocket, i; unsigned short int listenPort; socklen_t clientAddressLength; struct sockaddr_in clientAddress, serverAddress; char line[LINE_ARRAY_SIZE]; listenPort = PORT; listenSocket = socket(AF_INET, SOCK_STREAM, 0); if (listenSocket < 0) { cerr << "cannot create listen socket"; exit(1); } 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); } listen(listenSocket, 5); pthread_t chatter[MAX_THREADS]; while (1) { while (threads<=MAX_THREADS) { cout << "Waiting for TCP connection on port " << listenPort << " ...\n"; cout << threads << " Threads running" << endl; clientAddressLength = sizeof(clientAddress); thread = threadrotate(); connectSocket[thread] = accept(listenSocket, (struct sockaddr *) &clientAddress, &clientAddressLength); if (connectSocket[thread] < 0) { cerr << "cannot accept connection "; exit(1); } cout << " connected to " << inet_ntoa(clientAddress.sin_addr); cout << ":" << ntohs(clientAddress.sin_port) << "\n"; pthread_create(&chatter[thread], NULL,&fchatter,(int *) thread); threads++; } } } int threadrotate() { int f = 0; while(connectSocket[f]!=0) f++; return f; }
-
wäre es möglich das jemand mit einer der beiden versionen ne ddos attacke ausführt?
-
wäre es möglich das jemand mit einer der beiden versionen ne ddos attacke ausführt?
DDos Attacken sind prinzipiell immer möglich, unabhängig von der verwendeten Serversoftware..
Igitt, ich weiß schon, warum ich kein C mag.
Findest wohl static_cast<void *>(var) schöner als (void
var
mfg unixer
-
debian inside schrieb:
so das läuft jetzt
void *fchatter(int* thisthread)
{
int temp = (int) thisthread;
...
}
...
cout << ":" << ntohs(clientAddress.sin_port) << "\n";
pthread_create(&chatter[thread], NULL,&fchatter,(intthread);
threads++;
}
}
}
[/cpp]jetzt haste ne mischloesung
wichtig ist, dass der hauptthread (in dem das accept ist)
den socket-fd kopiert.
theoretisch kann es passieren, dass der hauptthread einen neuen
socket annimmt bevor der worker-thread den alten socket-fd kopiert
hat.du wirst um ein dynamisches allokieren eines neuen socket-fd nicht
drum rum kommen.wenn du das programm nur fuer private zwecke hast, nimm die loesung
von unixer; d.h. lass das "(intthread" stehen und gud is.