Autor |
Nachricht |
|
Titel: Posix Threads entfernen ?
Verfasst am: 18.06.2006, 11:12 Uhr
|
|
Anmeldung: 30. Jun 2005
Beiträge: 449
|
|
Hallo Freunde der parallelen Algorithmen,
ich öffne n Threads, was wunderbar funktioniert, da ich den Rückgabewert auf 0 Prüfe. Hier:
Code:
threadmsg = pthread_create(&threads[i],
NULL,
threadSendTCPRequest,
&portArray[currentPort]);
if (threadmsg == 0)
threadcount++;
else ...
Hier werden alle n Threads dann wieder entfernt, was ebenfalls wunderbar funktioniert
Code:
int msg_cancel = 0, remthreads = 0;
for (int i=0; i < threadAmount; i++) {
if (threads[i] == 0)
continue;
msg_cancel = pthread_cancel(threads[i]);
if (msg_cancel == 0){
remthreads++;
threads[i] = 0;
}
else
cout <<"Thread could NOT be removed! Err.: "<<msg_cancel<<endl;
}
cout<<remthreads<<"Threads were removed." <<endl;
Status der Threads gibt keine Fehlermeldung, is' also auch o.k.:
Code:
if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) +
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS , NULL) != 0)
cout <<" unable to set thread's cancelstate/type!"<<endl;
Ich lasse die erzeugten und entfernten Threads prüfen und da diese beiden Summen identisch sind, kann ich davon ausgehen, dass stets alle erzeugten Threads auch wieder korrekt entfernt werden. Es gibt beim Entfernen der Threads keine Fehlermeldung und ich krieg' schön die 0 zurück.
Problem:
Obwohl die Threads lt. der Funktion <pthread_cancel()> alle korrekt entfernt werden, kann ich nach dem Anlegen und Löschen der Threads keine neuen Threads mehr anlegen, da das System trotz <pthread_cancel()> nicht rafft, dass die Threads freigegeben worden sind. :schock: Ich kann also maximal 382 Threads ausführen und löschen, danach ist Schluss. :schock:
Seht Euch mal den Verlauf an:
Code:
portscanner was executed ...
portscanner (C) copyright DANNYBOY 2006
***************************************
--> scanning IP 66.249.85.104 on ports 0 - 3000
--> please wait until scanning is finished ...
Amount of threads each time: 100
Checking ports 0 - 100 ...
100 threads were created ...
100 threads were removed.
Checking ports 100 - 200 ...
100 threads were created ...
100 threads were removed.
Checking ports 200 - 300 ...
100 threads were created ...
100 threads were removed.
Checking ports 300 - 400 ...
82 threads were created ...
82 threads were removed.
Checking ports 400 - 500 ...
0 threads were created ...
0 threads were removed.
Hatte statt <PTHREAD_CANCEL_ASYNCHRONOUS> auch schon <PTHREAD_CANCEL_DEFERRED> probiert, geht ebenfalls nicht. Threads werden korrekt entfernt, aber irgendwie denkt Linux, dass die entfernten Threads noch vorhanden sind und lässt mich keine neuen Threads anlegen. Hab' in den Tutorials nix weiteres gefunden. Momentan laufen die Threads nur in 'ner Schleife mit 'nem kleinen sleep(). Innerhalb der Threads kann ich sie nicht entfernen, da sie hier später eine Verbindung im Block-Modus checken sollen. Was fehlt in meinem Programm um die Threads korrekt zu entfernen?
Greetz
DANNY |
|
|
|
|
|
|
Titel: RE: Posix Threads entfernen ?
Verfasst am: 23.06.2006, 08:15 Uhr
|
|
Anmeldung: 20. Mai 2005
Beiträge: 323
Wohnort: Niedernberg
|
|
Ich habe mal ein Testprogram gemacht, aufgrund Deiner Angaben (es war mein erstes pthreads Progtramm).
Wenn ich in einer Schleife threads anlege und beende, dann kommt irgendwann ein beim create ein Returnwert "kein Speicher mehr".
Wenn ich dann nach dem pthread cancel ein join mache geht es:
Code:
if ((r = pthread_cancel(thread)) != 0)
{
printf("pthread_cancel returned %s (count: %d)\n", strerror (r), i);
exit(1);
}
void *status;
if ((r = pthread_join(thread, &status)) != 0)
printf("pthread_join returned : %s\n", strerror(r));
Wenn amn die Mna-page zu pthread_join liest, ist das auch logisch:
Zitat:
When a joinable thread terminates, its memory resources (thread
descriptor and stack) are not deallocated until another thread performs
pthread_join on it. Therefore, pthread_join must be called once for
each joinable thread created to avoid memory leaks.
Es werden die resourcen nicht freigegeben!
Vielleicht ist das auch Dein Problem... |
|
|
|
|
|
|
Titel:
Verfasst am: 27.06.2006, 03:54 Uhr
|
|
Anmeldung: 30. Jun 2005
Beiträge: 449
|
|
Hallo Boregard,
die Variante mit join funktioniert wunderbar, solange ich kein recv und kein send in den Threads aufrufe, denn sobald diese Funktionen im Thread stehen, kann und/oder will pthread_cancel den Thread nicht abbrechen. Leider benötige ich diese beiden Funktionen unbedingt im Blocking-Modus. Gibt's da 'ne threadsichere Variante, die mir erlaubt die Threads zu schließen?
Greetz
DANNY |
|
|
|
|
|
|
Titel:
Verfasst am: 28.06.2006, 08:23 Uhr
|
|
Anmeldung: 20. Mai 2005
Beiträge: 323
Wohnort: Niedernberg
|
|
Hi,
wenn ich das richtig verstehe, dann hast Du Aufrufe von recv und send, und während diese blockieren kann der thread nicht mit pthread_cancel abgebrochen werden?
Das schein mir auch logisch, den pthread_cancel ist nur eine Aufforderung zum beenden, siehe man-page:
Zitat:
Cancellation is the mechanism by which a thread can terminate the exe‐
cution of another thread. More precisely, a thread can send a cancella‐
tion request to another thread. Depending on its settings, the target
thread can then either ignore the request, honor it immediately, or
defer it till it reaches a cancellation point.
Wenn man weiter liest, wird auch klar, wo ein thread auf ein pthread_cancel reagiert:
Zitat:
Cancellation points are those points in the program execution where a
test for pending cancellation requests is performed and cancellation is
executed if positive. The following POSIX threads functions are cancel‐
lation points:
pthread_join(3)
pthread_cond_wait(3)
pthread_cond_timedwait(3)
pthread_testcancel(3)
sem_wait(3)
sigwait(3)
Ich denke, Du brauchst einen etwas komplizierteren Mechanismus. Ich würde mit "select" arbeiten, um ein blockieren in einer Systemfunktion vermeiden.
Gruß,
Bernhard |
|
|
|
|
|
|
Titel:
Verfasst am: 28.06.2006, 08:32 Uhr
|
|
Anmeldung: 20. Mai 2005
Beiträge: 323
Wohnort: Niedernberg
|
|
Noch eins,
wenn man die man-page zu Ende liest:
Zitat:
BUGS
POSIX specifies that a number of system calls (basically, all system
calls that may block, such as read(2), write(2), wait(2), etc.) and
library functions that may call these system calls (e.g. fprintf(3))
are cancellation points. LinuxThreads is not yet integrated enough
with the C library to implement this, and thus none of the C library
functions is a cancellation point.
For system calls at least, there is a workaround. Cancellation requests
are transmitted to the target thread by sending it a signal. That sig‐
nal will interrupt all blocking system calls, causing them to return
immediately with the EINTR error. So, checking for cancellation during
a read system call, for instance, can be achieved as follows:
pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();
|
|
|
|
|
|
|
Titel:
Verfasst am: 02.07.2006, 23:08 Uhr
|
|
Anmeldung: 30. Jun 2005
Beiträge: 449
|
|
Hi Boregard,
hab' mittlerweile verschiedene Varianten versucht das Problem zu lösen, u.a. auch mit expliziten sleeps ... das gefällt mir alles nicht. Sogar ein einfaches <cout> in 'ner Schleife reicht schon aus, damit thread_cancel() den Thread NICHT beenden kann. Daher werde ich Deinem Hinweis nachgehen und select() verwenden. Ich hatte bisher select() "nur" auf der Serverseite verwendet und hier eben bind() verwendet um quasi Port und IP mit dem Socket zu assoziieren ---> anschließend den select() (evtl. mit Timeout).
Kann ich bind() auch auf der Client-Seite verwenden oder wie verbinde ich Port und IP mit dem Socket, der anschließend bei Select() verwendet wird? select()-Tutorials zeigen immer nur die Serverseite.
So schlägt der bind() jedenfalls immer fehl, so dass ich den anschließenden select() gar nicht erst probieren brauche.
Code:
int sendTCPRequest(char* ip, int port) {
int mySocket = INVALID; // init. socket
// get new socket
mySocket = socket(AF_INET, SOCK_STREAM, 0); // Prot. 4, TCP, standard
if (mySocket == INVALID)
return INVALID;
// specify connection-partner via <sockaddr_in> struct
sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET; // I.net Protocol v4
serv_addr.sin_port = htons(port); // Host to Byte order
serv_addr.sin_addr.s_addr = inet_addr(ip); // partner's ip address
// bind
int b = bind(mySocket, (sockaddr *)&serv_addr, sizeof(sockaddr_in)); //schlägt fehl
cout<<"error in bind(): "<<endl;
...
PS:
Kannst de' ein gutes c/c++-Forum empfehlen?
Greetz
DANNY |
|
|
|
|
|
|
Titel:
Verfasst am: 03.07.2006, 08:02 Uhr
|
|
Anmeldung: 20. Mai 2005
Beiträge: 323
Wohnort: Niedernberg
|
|
select() wird zwar oft/meist in Beispielen für TCP/IP Übertragung, und speziell dort für Server verwendet, kann aber für alle Fileoperationen verwendet werden. Und da in Unix alles ein File ist...
Ein bind ist da falsch... mit select() wartest Du doch nur darauf, das ein File was zum lesen liefert oder etwas schreiben kann. D.h. Du hast doch irgendwann ein open() gemacht. Das dabei gelieferte Handle kann im select() dann verwendet werden. Ein timeout brauchst Du natürlich, damit es nicht auch blockt.... und es muß im non-blocking-mode geöffnet sein...
Dein Beispiel müsste doch konkret so aussehen (wenns der client ist):
Code:
int sendTCPRequest(char* ip, int port) {
int mySocket = INVALID; // init. socket
// get new socket
mySocket = socket(AF_INET, SOCK_STREAM, 0); // Prot. 4, TCP, standard
if (mySocket == INVALID)
return INVALID;
// specify connection-partner via <sockaddr_in> struct
sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET; // I.net Protocol v4
serv_addr.sin_port = htons(port); // Host to Byte order
serv_addr.sin_addr.s_addr = inet_addr(ip); // partner's ip address
if (mySocket > 0)
{
/* ... and try to connect */
if (connect (mySocket,
(struct sockaddr *)&serv_addr,
sizeof (serv_addr) ) != 0)
{
cout<<"error in connect(): "<<endl;
}
}
Und dann kannst Du mit select() arbeiten:
Code:
fd_set fdsRead;
int iMaxSelect;
int iSelRet;
int iRead;
struct timeval tTime;
/* -- now loop and select -- */
do {
/* -- clear arrays for select -- */
FD_ZERO (&fdsRead);
FD_SET (iSocket, &fdsRead);
iMaxSelect = iSocket; /* the only one is also the maximum... */
/* -- set max. waittime -- */
tTime.tv_sec = TIMEOUTSECONDS;
tTime.tv_usec = 0;
errno = 0;
iSelRet = select (iMaxSelect + 1, &fdsRead, NULL, NULL, &tTime);
if (iSelRet > 0)
{
/* -- we got something on socket ?? -- */
if (FD_ISSET (iSocket, &fdsRead))
{
iRead = read (iSocket, szBuffer, sizeof (szBuffer));
if (iRead <= 0)
break;
...........
}
}
else if (iSelRet < 0)
{
if (errno != 0)
{
fprintf (stderr, "Error reading from select: (%d) %s\n",
errno, strerror (errno));
break;
}
}
else
{
/* just timeout */
}
} while (1);
|
|
|
|
|
|
|
Titel:
Verfasst am: 05.07.2006, 01:26 Uhr
|
|
Anmeldung: 30. Jun 2005
Beiträge: 449
|
|
Hallo Boregard,
ich bin dem Ziel dank Deiner Hilfe nun näher. So ganz checken tu' ich's noch nicht.
Wie soll select() für 4 sec. blocken können, wenn ich explizit mit fcntl() auf non-block setze?
Ich bekomme für connect() ein
Code:
operation in progress
, jedoch für alle select() ein
Code:
bad filedescriptor
. Das Ergebnis ist für offene und geschlossene Ports gleich (Zustand mit nmap getestet). Ist das nicht eher eine schreibende, als lesende Operation im select()? Hier mein Sourcecode mit Non-Blocking und select():
Code:
// connects to foreign host via tcp
bool sendTCPRequest(char* ip, int port) {
int mySocket = INVALID; // init. socket
// get new socket
mySocket = socket(AF_INET, SOCK_STREAM, 0); // Prot. 4, TCP, standard
if (mySocket == INVALID){
cout<<"socket(): "<<strerror(errno)<<endl;
return false;
}
// specify connection-partner via <sockaddr_in> struct
sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET; // I.net Protocol v4
serv_addr.sin_port = htons(port); // Host to Byte order
serv_addr.sin_addr.s_addr = inet_addr(ip); // partner's ip address
// set nonblocking mode for socket
if (fcntl(mySocket, F_SETFL, O_NONBLOCK ) != 0){
cout<<"fcntl(): "<<strerror(errno)<<endl;
return false;
}
// try to connect
cout<<"Trying to connect to IP "<<ip<<":"<<port<<endl;
if (connect(mySocket, (sockaddr*) &serv_addr,
sizeof(serv_addr))!=0)
close(mySocket);
cout<<"connect(): ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
// select() with timeout
struct timeval timeout;
timeout.tv_sec = WAIT_SECONDS;
timeout.tv_usec = 0;
fd_set input;
FD_ZERO(&input);
FD_SET(mySocket, &input);
int retSelect = select(mySocket+1, &input, NULL, NULL, &timeout);
if (retSelect >0)
cout<<"open port on --> "<<port<<endl;
else
cout<<"select(): ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
Greetz
DANNY |
|
|
|
|
|
|
Titel:
Verfasst am: 05.07.2006, 13:17 Uhr
|
|
Anmeldung: 20. Mai 2005
Beiträge: 323
Wohnort: Niedernberg
|
|
Hi,
select () blockt nicht, das macht read() oder write(). select() teilt nur mit, ob man mit read() etws lesen kann (d.h. es ist etwas angekommen), oder mit write etwas schreiben kann (d.h. die Ausgabepuffer haben noch Platz), oder ob der timeout abgelaufen ist.
Was ich nicht verstehe ist:
Code:
if (connect(mySocket, (sockaddr*) &serv_addr,
sizeof(serv_addr))!=0)
close(mySocket);
d.h. wenn der connect() schief geht, machst Du den socket mit close wieder zu, ohne eine Fehlermeldung auszugeben. Das im nachfolgenden cout ausgegeben errno kann man nicht zuordnen, das kann der (Fehler-) Status von close(), von connect() oder von irgendwas vorher sein, denn: errno wird nur dann gesetzt, wenn ein Fehler passiert, es wird nicht (unbedingt) auf 0 gesetzt wenn die Funktion erfolgreich war. Außerdem sollte man errno direkt nach einem Fehler auswerten, da es jede andere Funktion wieder umsetzen kann.
Unabhängig davon frage ich mich, warum Du bei einem fehlgeschlagenen connect() zwar close() aufrufst, dann aber weitermachst - kein Wunder, daß select() einen "bad filedescriptor" liefert...
Also finde erst mal raus, woher der "operation in progress" kommt, von connect() oder vom darauffolgenden close().
Bzgl. schreibender / lesender Operation im select(): wie bereits gesagt, select() liefert Dir nur zurück, ob du lesen kannst oder ob Du schreiben kannst. Es kommt darauf an, ob du dann read() oder write() aufrufen willst. Du kannst natürlich auch auf beides gehen und dann entsprechend abfragen, dan brauchst Du halt ein fd_set für lesen und eines für schreiben...
Hast Du Dir mal die manpages durchgelesen?
Gruß,
Boregard |
|
|
|
|
|
|
Titel:
Verfasst am: 05.07.2006, 15:02 Uhr
|
|
Anmeldung: 30. Jun 2005
Beiträge: 449
|
|
Hi,
das Ganze gibt 'nen Portscanner.
Ich versuche pro Thread eine TCP-Verbindung zu einem Port aufzubauen und guck' ob's klappt. Anschl. soll keine Kommunikation stattfinden, daher auch das close() in jedem Fall. Dennoch doofer Flüchtigkeitsfehler auf einen geschlossenen Socket weitere Operationen auszuführen. Die Man-Pages zu den verwendeten Funktionen hab' ich gelesen, so ganz klar ist mir manches dennoch nicht.
Mein zweiter Rechner hat nur die Ports 21 und 22 offen und wenn ich im Blocking-Modus arbeite, dann bekomme ich das korrekte Ergebnis:
Code:
checking ports 20 - 23
4 Threads were created
WAITING...
Joining all threads ...
select(): returned with 1 (192.168.1.34:23) --> Connection refused
FD_SET(): returned with 1 (192.168.1.34:23) --> Connection refused
select(): returned with 1 (192.168.1.34:22) --> Success
FD_SET(): returned with 1 (192.168.1.34:22) --> Success
select(): returned with 1 (192.168.1.34:21) --> Success
FD_SET(): returned with 1 (192.168.1.34:21) --> Success
select(): returned with 1 (192.168.1.34:20) --> Connection refused
FD_SET(): returned with 1 (192.168.1.34:20) --> Connection refused
So far, so good. Doch mit Non-Blocking und select() krieg' ich nun die selben Ergebnisse, egal ob offener oder geschlossener Port. Somit kann ich nicht unterscheiden, welche Ports offen und welche geschlossen sind. Ich brauche scheinbar den Non-Blocking Modus, da connect() u.U sonst blockieren könnte und das wäre fatal. Hier das Ergebnis im Non-Blocking-Mode:
Code:
checking ports 20 - 23
4 Threads were created
WAITING...
Joining all threads ...
select(): returned with 1 (192.168.1.34:20) --> Operation now in progress
FD_SET(): returned with 1 (192.168.1.34:20) --> Operation now in progress
select(): returned with 1 (192.168.1.34:23) --> Operation now in progress
FD_SET(): returned with 1 (192.168.1.34:23) --> Operation now in progress
select(): returned with 1 (192.168.1.34:22) --> Operation now in progress
FD_SET(): returned with 1 (192.168.1.34:22) --> Operation now in progress
select(): returned with 1 (192.168.1.34:21) --> Operation now in progress
FD_SET(): returned with 1 (192.168.1.34:21) --> Operation now in progress
Hab' die Funktion nun so geschrieben, dass man die Ergebnisse in jedem Fall angezeigt bekommt und so sieht 'se aus:
Code:
// connects to foreign host via tcp
bool sendTCPRequest(char* ip, int port) {
int mySocket = INVALID; // init. socket
// get new socket
mySocket = socket(AF_INET, SOCK_STREAM, 0); // Prot. 4, TCP, standard
if (mySocket == INVALID){
cout<<"socket(): "<<strerror(errno)<<endl;
return false;
}
// specify connection-partner via <sockaddr_in> struct
sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET; // I.net Protocol v4
serv_addr.sin_port = htons(port); // Host to Byte order
serv_addr.sin_addr.s_addr = inet_addr(ip); // partner's ip address
//set nonblocking mode for socket
fcntl(mySocket, F_SETFL, O_NONBLOCK );
//cout<<"fcntl(): "<<strerror(errno)<<endl;
// try to connect
//cout<<"Trying to connect to IP "<<ip<<":"<<port<<endl;
connect(mySocket, (sockaddr*) &serv_addr,
sizeof(serv_addr));
// cout<<"connect(): ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
// select() with timeout
struct timeval timeout;
timeout.tv_sec = WAIT_SECONDS;
timeout.tv_usec = 0;
fd_set input;
FD_ZERO(&input);
FD_SET(mySocket, &input);
int retSelect = select(mySocket+1, &input, NULL, NULL, &timeout);
cout<<"select(): returned with "<<retSelect<<" ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
int retFD = FD_ISSET(mySocket, &input);
cout<<"FD_ISSET(): returned with "<<retFD<<" ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
close(mySocket);
return true ;
Schwere Geburt.
Greetz
DANNY |
|
|
|
|
|
|
Titel:
Verfasst am: 06.07.2006, 09:23 Uhr
|
|
Anmeldung: 20. Mai 2005
Beiträge: 323
Wohnort: Niedernberg
|
|
Hi,
das "Operation now in progress" scheint doch wohl daher zu kommen, da der Zugriff normalerweise blockieren würde, aber durch non-blocking kommt er mit dieser Meldung zurück.
Ich weiß aber nicht, ob das überhaupt funktioniert, Du willst ja mit select() nicht auf lese / schreibe, sondern auf den connect().
Vielleicht gehts mit den exceptios im select anstatt von lesen...
Trotzdem: irgendwie fehlt mir bei Deinem Programm die Schleife um select().
Du nimmst doch select(), damit es nicht blockiert, d.h. wenn Du im blocking arbeitest, dann kehrt der Aufruf zu connect() erst zurück, wenns geht oder nicht geht, d.h. es wird gewartet ("blocked") bis ein Ergebnis vorliegt. Im non-blocking kehrt er sofort zurück. Zwar sollte das select() durch den timeout warten, ABER: select() kehrt NICHT nur zurück, wenn entweder der abgefragte Descriptor oder der timeout aufgetereten sind, es kann auch durch andere Aktionen (z.B. ein Signal) mit timeout zurückkehren, OHNE daß die Zeit wirklich verstrichen ist....
Ich würde es so versuchen (Achtung: ungetestet!):
Code:
// connects to foreign host via tcp
bool sendTCPRequest(char* ip, int port) {
int mySocket = INVALID; // init. socket
// get new socket
mySocket = socket(AF_INET, SOCK_STREAM, 0); // Prot. 4, TCP, standard
if (mySocket == INVALID){
cout<<"socket(): "<<strerror(errno)<<endl;
return false;
}
// specify connection-partner via <sockaddr_in> struct
sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET; // I.net Protocol v4
serv_addr.sin_port = htons(port); // Host to Byte order
serv_addr.sin_addr.s_addr = inet_addr(ip); // partner's ip address
//set nonblocking mode for socket
fcntl(mySocket, F_SETFL, O_NONBLOCK );
connect(mySocket, (sockaddr*) &serv_addr,
sizeof(serv_addr));
// cout<<"connect(): ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
// Now we want to see, if we can connect succesfully, as this has
// to be done non-blocking (because of threads) we must use
// a select() loop....
struct timeval timeout;
fd_set input;
fd_set except;
while (true)
{
// select() with timeout
timeout.tv_sec = WAIT_SECONDS;
timeout.tv_usec = 0;
FD_ZERO(&input);
FD_SET(mySocket, &input);
FD_ZERO(&except);
FD_SET(mySocket, &except);
errno = 0;
int retSelect = select(mySocket+1, &input, NULL, NULL, &timeout);
if (retSelect > 0)
{
// here we are ...
if (FD_ISSET(mySocket, &input))
{
cout<<"FD_ISSET(input): returned with "
<<retFD<<" ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
// evtl. testweise den break auskommentieren, um zu sehen
// ob "except" zieht...
break;
}
else if (FD_ISSET(mySocket, &except))
{
cout<<"FD_ISSET(except): returned with "
<<retFD<<" ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
break;
}
else
{
cout<<"Oops: select(): returned with "<<retSelect
<<" ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
break;
}
}
else if (retSelect < 0)
{
cout << "Error occured in select (): " << strerror(errno) << endl;
break;
}
else
{
cout << "Timeout in select(), still waiting..." << endl;
}
int retFD =
}
close(mySocket);
return true ;
}
|
|
|
|
|
|
|
Titel:
Verfasst am: 06.07.2006, 21:17 Uhr
|
|
Anmeldung: 20. Mai 2005
Beiträge: 323
Wohnort: Niedernberg
|
|
Hi,
ich habe mit etwas googlen folgendes herausgefunden:
connect() liefert bei non-blocking immer "Operation in progress" (EINPROGRESS).
Man wartet dann mit select() auf schreibende Zugriffsmöglichkeit.
Falls es überhaupt funktioniert (bekommt man mit select wirklich die errno durch das connect davor gesetzt??)
Obiger Code (dem eh except in select fehlte...) wird damit zu:
Code:
// connects to foreign host via tcp
bool sendTCPRequest(char* ip, int port) {
int mySocket = INVALID; // init. socket
// get new socket
mySocket = socket(AF_INET, SOCK_STREAM, 0); // Prot. 4, TCP, standard
if (mySocket == INVALID){
cout<<"socket(): "<<strerror(errno)<<endl;
return false;
}
// specify connection-partner via <sockaddr_in> struct
sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET; // I.net Protocol v4
serv_addr.sin_port = htons(port); // Host to Byte order
serv_addr.sin_addr.s_addr = inet_addr(ip); // partner's ip address
//set nonblocking mode for socket
fcntl(mySocket, F_SETFL, O_NONBLOCK );
connect(mySocket, (sockaddr*) &serv_addr,
sizeof(serv_addr));
// cout<<"connect(): ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
// Now we want to see, if we can connect succesfully, as this has
// to be done non-blocking (because of threads) we must use
// a select() loop....
struct timeval timeout;
fd_set output;
fd_set except;
while (true)
{
// select() with timeout
timeout.tv_sec = WAIT_SECONDS;
timeout.tv_usec = 0;
FD_ZERO(&output);
FD_SET(mySocket, &output);
FD_ZERO(&except);
FD_SET(mySocket, &except);
errno = 0;
int retSelect = select(mySocket+1, NULL, &output, &except, &timeout);
if (retSelect > 0)
{
// here we are ...
if (FD_ISSET(mySocket, &output))
{
cout<<"FD_ISSET(output): returned with "
<<retFD<<" ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
// evtl. testweise den break auskommentieren, um zu sehen
// ob "except" zieht...
break;
}
else if (FD_ISSET(mySocket, &except))
{
cout<<"FD_ISSET(except): returned with "
<<retFD<<" ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
break;
}
else
{
cout<<"Oops: select(): returned with "<<retSelect
<<" ("<<ip<<":"<<port<<") --> "<<strerror(errno)<<endl;
break;
}
}
else if (retSelect < 0)
{
cout << "Error occured in select (): " << strerror(errno) << endl;
break;
}
else
{
cout << "Timeout in select(), still waiting..." << endl;
}
}
close(mySocket);
return true ;
}
|
|
|
|
|
|
|
Titel:
Verfasst am: 06.07.2006, 22:20 Uhr
|
|
Anmeldung: 20. Mai 2005
Beiträge: 323
Wohnort: Niedernberg
|
|
So müsste es eher gehen:
Code:
....
if (FD_ISSET(mySocket, &output))
{
int soError;
socklen_t soLen = sizeof (soError);
if (0 != getsockopt (mySocket, SOL_SOCKET, SO_ERROR,
(void *)&soError, &soLen))
cout<<"getsockopt error: "<<strerror(errno)<<endl;
else
cout<<"FD_ISSET(output): returned with "
<<retFD<<" ("<<ip<<":"<<port<<") --> "<<strerror(soError)<<endl;
break;
}
....
|
|
|
|
|
|
|
Titel:
Verfasst am: 08.07.2006, 17:02 Uhr
|
|
Anmeldung: 30. Jun 2005
Beiträge: 449
|
|
Hallo Boregard,
vielen, vielen, vielen Dank für Deine Mühe und Hilfe. Du hast mir wirklich viel geholfen und viel dazu beigetragen, dass das Programm nun endlich so läuft und funktioniert, wie ich mir das gewünscht habe. Kleine Änderungen werd' ich noch am „Design“ vornehmen, doch die wesentliche Funktionalität steht. Ich habe unseren kleinen Portscanner mal mit den Ergebnissen von nmap verglichen --> Äquivalenz!!! Hier ein Testlauf beider Programme losgelassen auf www.kanotix.de
nmap (www.kanotix.de):
Code:
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
25/tcp open smtp
53/tcp open domain
80/tcp open http
106/tcp open pop3pw
110/tcp open pop3
143/tcp open imap
443/tcp open https
465/tcp open smtps
993/tcp open imaps
995/tcp open pop3s
3306/tcp open mysql
8443/tcp open https-alt
Unser Portscanner (www.kanotix.de):
Code:
found open port (archive.kanotix.com):21
found open port (archive.kanotix.com):22
found open port (archive.kanotix.com):25
found open port (archive.kanotix.com):53
found open port (archive.kanotix.com):80
found open port (archive.kanotix.com):106
found open port (archive.kanotix.com):110
found open port (archive.kanotix.com):143
found open port (archive.kanotix.com):443
found open port (archive.kanotix.com):465
found open port (archive.kanotix.com):993
found open port (archive.kanotix.com):995
found open port (archive.kanotix.com):3306
found open port (archive.kanotix.com):8443
found open port (archive.kanotix.com):8880
Interessanterweise zeigt unser Portscanner sogar einen offenen Port mehr an (8880) als nmap.
Ich habe alle nun unnötigen Dinge (u.a. auch die Schleife) wie niemals eintretende Bedingungen und dergleichen entfernt. Folgendermaßen sieht die fertige Funktion nun aus:
Code:
// connects to foreign host via tcp and returns true if possible
bool scanPort(char* ip, int port) {
int mySocket = INVALID; // init. socket
errno=0;
// get new socket
mySocket = socket(AF_INET, SOCK_STREAM, 0); // Prot. 4, TCP, standard
if (mySocket == INVALID){
cout<<"socket(): "<<strerror(errno)<<endl;
return false;
}
// specify connection-partner via <sockaddr_in> struct
sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET; // I.net Protocol v4
serv_addr.sin_port = htons(port); // Host to Byte order
serv_addr.sin_addr.s_addr = inet_addr(ip); // partner's ip address
//set nonblocking mode for socket
if (fcntl(mySocket, F_SETFL, O_NONBLOCK )!=0){
cout<<"fcntl(): "<<strerror(errno)<<endl;
close(mySocket);
return false;
}
// try to connect (non-blocking)
int retCon = connect(mySocket, (sockaddr*) &serv_addr, sizeof(serv_addr));
// select() with timeout (WAIT_SECONDS)
struct timeval timeout;
timeout.tv_sec = WAIT_SECONDS;
timeout.tv_usec = 0;
fd_set output;
int retFD = 0;
FD_ZERO(&output);
FD_SET(mySocket, &output);
select(mySocket+1, NULL, &output, NULL, &timeout);
// let's see if we got something to write
retFD = FD_ISSET(mySocket, &output);
if (retFD < 1){ // occurs sometimes in case of <no route to host>
close(mySocket);
return false;
}
// test socket status
int soError=0;
socklen_t soLen = sizeof (soError);
if ( getsockopt (mySocket, SOL_SOCKET, SO_ERROR,(void *)&soError, &soLen)!=0){
cout<<"getsockopt error: "<<strerror(errno)<<endl;
close(mySocket);
return false;
}
// close socket because we don't want to communicate any more
close(mySocket);
// connection o.k. if no soError was set
return (soError == 0);
}
Danke nochmals für alles.
Greetz
DANNYBOY |
|
|
|
|
|
|
|
|
|
|