PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : cpp sockets: tcp server / client und ewiges connecten



Nebukadneza
11-08-2003, 00:16
hi ... ich hab den heutigen abend damit verbracht mal ne runde sockets zu lernen ... das ergebniss ist etwas ... komisch ... ich habe server und client auf ein und dem selben rechner gehabt, und der client connectet ewig (bleibt bei connect stehen), während der server keine eingehende verbindung bekommt (oder gar acceptet) ... hier der source von beidem:

server:


#include <iostream.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>


int main() {
int Msocket;
socklen_t Msocketaddrsize;

sockaddr_in Msocketaddr;
sockaddr_in Macceptaddr;
Msocket = socket(AF_INET, SOCK_STREAM, 0);
if(Msocket < 0) cout<<"fehler beim socket"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
cout<<"socket erstellt"<<endl;
Msocketaddr.sin_family = AF_INET;
Msocketaddr.sin_port = htons(34343);
Msocketaddr.sin_addr.s_addr = INADDR_ANY;
if(bind(Msocket, (sockaddr*) &Msocketaddr, sizeof(Msocketaddr)) == -1) cout<<"fehler beim bind"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
cout<<"socket gebindet"<<endl<<"socket startet hören"<<endl;
if(listen(Msocket, 2) < 0) cout<<errno<<endl<<"fehler beim listen"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
cout<<"socket hört"<<endl;
Msocketaddrsize = sizeof(sockaddr_in);
if(accept(Msocket, (sockaddr*) &Macceptaddr, (socklen_t*) &Msocketaddrsize) < 0) cout<<"bla"<<endl;
cout<<"socket hat verbindung angenommen"<<endl;
}



client :


#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <iostream.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>


int main() {
int Msocket;
sockaddr_in Msockaddr;
char hostname[MAXHOSTNAMELEN];
hostent *host;
cout<<"bitte hostname eingeben"<<endl;
cin>>hostname;
host=gethostbyname(hostname);
cout<<"die ip ist: "<<inet_ntoa(*((in_addr *)host->h_addr))<<endl;

Msocket = socket(AF_INET, SOCK_STREAM, 0);
Msockaddr.sin_family = AF_INET;
Msockaddr.sin_port = htons(34343);
Msockaddr.sin_addr = *((in_addr*) &host->h_addr);
cout<<"connecting ..."<<endl;
if(connect(Msocket, (sockaddr*) &Msockaddr, sizeof(Msockaddr)) == -1) cout<<"fehler beim verbinden"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
cout<<"connected !! well done!"<<endl;
}


sop ... nun noch eben die outputs der beiden. ich hab zuerst den server gestartet, der folgendes meinte:
./sockets_server
socket erstellt
socket gebindet
socket startet hören
socket hört

wärend danach der client meint:
./sockets_client
bitte hostname eingeben
localhost
die ip ist: 127.0.0.1
connecting ...

das kann man so bis zu 10min stehenlassen ohne das sich etwas tut ... wäre echt super, wenn mir jemand helfen könnte ...

Silver
11-08-2003, 08:39
hmm, hast du schon mal einen anderen Port probiert? versuch es mal mit der Funktion getservbyname(). Vielleicht kriegst du hier bessere Ergebnisse ;)


mfG

PS: das nächste mal verwende bitte \[code\] \[/code\] !!

//edit shit krieg das nicht hin ;)! ignoriere einfach die backslashs im PS *g*

Berufspenner
11-08-2003, 08:43
Hi@all

Willkommen im Forum :)

So, ich hab mal eben die Code-Tags gesetzt, in der Hoffnung die Lesbarkeit zu erhöhen.

Cu
André

Nebukadneza
11-08-2003, 11:44
okay ... ich habs jetzt geschafft ... im client war ein schlichtes


Msockaddr.sin_addr.s_addr = *((in_addr_t *)host->h_addr)

der fehler ... nun bin ich aber schonwieder bein nächsten problem. und zwar schicke ich im server ein hello world mit


if(send(Msocket, "Hello World", sizeof("Hello World"), 0) ) cout<<"senden fehlgeschlagen"<<endl<<errno<<" -- "<<strerror(errno)<<endl;

was laut dem output auch anständig klappt ... das recv im client sieht volgendermasen aus:


if(recv(Msocket, buffer, 10000, 0) < 0) cout<<"fehler beim empfangen der daten"<<endl<<errno<<" -- "<<strerror(errno)<<endl;;

so ... leider wird bei der ausgabe von dem char buffer[10000] deutlich, das nichts angekommen ist ... wo liegt da nun wieder der fehler // trick?

also denne ... danke schonmal!

ps:
hi berufspenner ... wir haben ja auch schon die ehre in linuxforen gehabt ... ich glaub auch das es mir hier gefallen wird :)

almoeli
11-08-2003, 13:05
Hi,

der accept Aufruf am Server liefert dir als Rückgabewert einen neuen Filedeskriptor. Dieser Deskriptor ist der gültige für deine Verbindung zum Client und ist unabhängig von dem Deskriptor, den du von der socket Fukntion bekommen hast. An diesen Deskriptor mußt du deine Daten schicken. Wird die Verbindung beendet, so mußt du diesen neuen Deskriptor auch explizit mit close wieder zumachen.
Es müßte also so lauten:



int ConnectionSocket;

...

ConnectionSocket = accept(Msocket, (sockaddr*) &Macceptaddr, (socklen_t*) &Msocketaddrsize);
if (ConnectionSocket < 0) cout << "Bla" << endl;

...

if(send(ConnectionSocket, "Hello World", sizeof("Hello World"), 0) ) cout<<"senden fehlgeschlagen"<<endl<<errno<<" -- "<<strerror(errno)<<endl;


Gruß

almoeli

Nebukadneza
11-08-2003, 20:15
achso ... okay! danke für den tipp!

Nebukadneza
11-08-2003, 22:56
tja ja ööö ... vergehen keine 4 stunden, schon bin ich beim nexten problem: ich wollt das ganze jetzt einfach in ein "charartiges" gebilde umwandeln ... ich glaub ich bin da etwas falsch rangegangen ... hier wie vorhin auch schon code und output:
server:


#include <iostream.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>


int main() {
int Msocket=0;
int sende=0;
char buffer[10000];
char buffer2[10000];
socklen_t Msocketaddrsize;
sockaddr_in Msocketaddr;
sockaddr_in Macceptaddr;
int Mconnectsocket;
int status; // 0=not connectet, 1==connectet, 2==close connection

memset(&Msocketaddrsize, 0, sizeof(Msocketaddrsize));
memset(&Msocketaddr, 0, sizeof(Msocketaddr));
memset(&Macceptaddr, 0, sizeof(Macceptaddr));

Msocket = socket(AF_INET, SOCK_STREAM, 0);
if(Msocket < 0) cout<<"fehler beim socket"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
cout<<"socket erstellt"<<endl;
Msocketaddr.sin_family = AF_INET;
Msocketaddr.sin_port = htons(34343);
Msocketaddr.sin_addr.s_addr = INADDR_ANY;
if(bind(Msocket, (sockaddr*) &Msocketaddr, sizeof(Msocketaddr)) == -1) cout<<"fehler beim bind"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
cout<<"socket gebindet"<<endl<<"socket startet hören"<<endl;
for(int i=0; i==0; i=0) {
if(listen(Msocket, 2) < 0) cout<<errno<<endl<<"fehler beim listen"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
cout<<"socket hört"<<endl;
Msocketaddrsize = sizeof(sockaddr_in);
Mconnectsocket = accept(Msocket, (sockaddr*) &Macceptaddr, (socklen_t*) &Msocketaddrsize);
cout<<"socket hat verbindung angenommen"<<endl;
status=1;
while(status==1){
if(recv(Msocket, buffer, 10000, 0) == -1) cout<<"fehler beim empfangen der daten"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
cout<<buffer<<endl;
// if(buffer=="exit") exit(0);
cin>>buffer2;
if(send(Mconnectsocket, buffer2, sizeof("Hello World"), 0) == -1) cout<<"fehler beim senden der daten"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
}
}
}


client:


#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <iostream.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>


int main(int argc, char *argv[]) {
int Msocket=0;
sockaddr_in Msockaddr;
char hostname[MAXHOSTNAMELEN];
hostent *host;
char buffer[10000];
char buffer2[10000];
int recive=0;
int status=0; // status. 0==not connectet, 1==conectet, 2==close connection
memset(&Msockaddr, 0, sizeof(Msockaddr));
memset(&host, 0, sizeof(host));
if(argc < 2){
cout<<"kein hostname angegeben. bitte sockets_client hostname starten."<<endl;
exit(0);
}
cout<<argv[1]<<endl;
strcpy(hostname, argv[1]);
host=gethostbyname(hostname);
cout<<"die ip ist: "<<inet_ntoa(*((in_addr *)host->h_addr))<<endl;

Msocket = socket(AF_INET, SOCK_STREAM, 0);
Msockaddr.sin_family = AF_INET;
Msockaddr.sin_port = htons(34343);
Msockaddr.sin_addr.s_addr = *((in_addr_t *)host->h_addr);
// Msockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
cout<<"connecting ..."<<endl;
if(connect(Msocket, (sockaddr*) &Msockaddr, sizeof(Msockaddr)) == -1) cout<<"fehler beim verbinden"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
cout<<"connected! well done!"<<endl;
status=1;
while(status==1){
if(recv(Msocket, buffer, 10000, 0) == -1) cout<<"fehler beim empfangen der daten"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
cout<<buffer<<endl;
// if(buffer=="exit") exit(0);
cin>>buffer2;
if(send(Msocket, buffer2, sizeof(buffer), 0) == -1) cout<<"fehler beim senden der daten"<<endl<<errno<<" -- "<<strerror(errno)<<endl;
}


}


so ... und nun der output:

server:
socket erstellt
socket gebindet
socket startet hören
socket hört
socket hat verbindung angenommen
sende hello world
fehler beim empfangen der daten
107 -- Transport endpoint is not connected

client:
localhost
die ip ist: 127.0.0.1
connecting ...
connected! well done!


beide programme würden nach diesem output noch weiterlaufen. falls ich in einem etwas eingeben, oder gar exit eingebe funktioniert interessiert das das andere überhauptnicht.

danke schonmal für die bisherige hilfe ...

almoeli
12-08-2003, 07:44
Moin,

nun ja da sind wohl einige Fehler in deinem Code:

1. Das von mir bereits erwähnte mit dem Filedeskriptor vom accept gilt auch, wenn du mit recv Daten vom Client empfangen willst. Also dein recv muß auch den 'Mconnectsocket' Filedeskriptor verwenden. Kurz gesagt: Für alle Datentransfers und z.b. ioctl die sich auf eine über accept angenommene Verbindung beziehen mußt du den Filedeskriptor benutzen der vom accept zurückgeliefert wird. Der Filedeskriptor den du vom socket Aufruf bekommen hast dient einzig und allein dem annehmen (accept) neuer Verbindugnen!
2. Der recv Aufruf ist blockierend. Dein Programm wird solange angehalten, bis Daten am verbundenen Socket eingehen. So wie deine Programme dastehen, laufen beide erst mal auf ein recv und bleiben deshalb stehen ohne das was passiert. Willst du den recv nicht blockierend, so mußt du die Verbindung als NONBLOCK deklarieren. Dies geschieht über einen ioctl Aufruf (siehe Manpage vom recv).
3. Beim senden von buffer2 solltest du nicht sizeof("Hello world!") oder sizeof(buffer2) verwenden sondern 'strlen(buffer2)'. Die erste Variante schickt immer fest 12 Bytes Daten weil Hello world! 12 Zeichen hat, die zweite schickt immer die vollen 10000 Bytes Daten. Das ist wohl nicht das, was du willst.

Dann mal weiterhin viel Spaß

almoeli