[C/Socket] Funktionsweise von select()?

Biehler

BiehlerProductions
ID: 89792
L
4 Mai 2006
1.948
181
Hallo,

Folgendes:
Client verbindet sich zum Server.
Der Server muss nun sichergehen, dass der Client keine Daten sendet, bzw wenn er dies tut, nimmt er diese entgegen.
Erst wenn quasi der Eingabebuffer leer ist, sendet der Server Daten an den Clienten.

Ich verwende unter Hinzunahme der Funktion "select()" folgenden Code:

Code:
int flush_net(int sock2) { 

  int maxfd;
  char temp[1];
  fd_set ac_state;
  fd_set ac_state2;
  maxfd=sock2;  
  FD_ZERO(&ac_state);
  FD_SET(sock2,&ac_state);
  ac_state2=ac_state;
  
  while(1) {
  
    select(maxfd+1,&ac_state2,NULL,NULL,NULL); 

    if(FD_ISSET(sock2,&ac_state2)) {
    
      recv(sock2,temp,1,0);
      printf(temp);
      printf("a");
      
    }else{
    
      break;
      
    }
    
  }
  
  return 0;
}

Nur das bringt keinerlei Wirkung.
Rein theoretisch müsste ja, sobald der Client mit dem Server verbindet, die Schleife abbrechen, weil ja keine Daten zum Empfangen anstehen.
Nur dies ist nicht der Fall, es entsteht eine Endlosschleif, bei der scheinbar zwar select() sagt, dass Daten da sind, aber weil keine da sind, wartet recv schön brav weiter.

Drücke ich eine Taste 'x' wird beim Server 'xDa' ausgegeben.
Das 'x' und das 'a' sind kalr, aber das 'D' nicht. Aber da sist erstmal zweitrangig.

In einem anderen Beispielcode, habe ich select verwendet, um ein CR_LF abzufangen, wenn ENter gedrückt wurde.
Ich habe überprüft, ob das gesendete zeichen ein CR oder ein LF ist.
Und dann eine andere Aktion ausführen wollen.
Da Windows jedoch CR/LF sendet, muste ich ja prüfen, ob noch ein weiteres Zeichen gesendet wurde.
Hierbei verwendete ich ebenfalls select() und da funktionierte es.

Nun frage ich mich natürlich, ob ich select() für mein Vorhaben gebrauchen kann?
Hab die Erklärungen zu select() nur bedingt kapiert, jedoch habe ich aus diversen Beispielcodes entnommen, dass select() mir sagt, ob Daten zum abholen bereitstehen oder nicht.


Und: Allgemeine Frage zu C & Strukturen

Angenommen eine Funktion gibt mir einen gecasteten Integer zurück, der einen Pointer auf eine Struktur darstellt.
Wie kann ich nun auf die einzelnen Elemente dieser Struktur zurückgreifen?


Also Quasi:

Code:
struct ERR {
int a;
int b;
};
struct ERR errn;

main() {
int a=abc();
}

int abc() {
return (int)&errn;
}

Wie kann ich nun auf die Struktur zurückgreifen, die durch den Pointer in "a" repräsentiert wird?
Hab versucht, den Pointer auf ne Struktur umzubiegen:
Code:
struct ERR asdf=(struct ERR)a;
Aber da war der Kompiller gar nicht glücklich drüber :ugly:
 
Drücke ich eine Taste 'x' wird beim Server 'xDa' ausgegeben.
Das 'x' und das 'a' sind kalr, aber das 'D' nicht. Aber da sist erstmal zweitrangig.
Hehe, da kann ich dir helfen:
PHP:
printf("%c", temp);
Bei deiner Konstruktion hängt kein Null-Byte an (zumindest würd ich mich nicht drauf verlassen, dass es der Compiler tut).
 
zu 2.
PHP:
typedef struct anonym
{
int a;
int b;
 } ERR;

ERR eins;
printf("%d %d\n",ERR.a,ERR.b);
ERR * zwei;
printf("%d %d\n",ERR->a,ERR->b);
 
Dein select() problem würd ich mal darauf zurück führen das du kein Timeout hast (letzer Param)... dadurch wartetest du halt auf immer ;)

(edit: ich hab die funktion bis etz noch nie benutzt deswegen reines querdenken hier ;))
 
Zum zweiten Problem:

Code:
struct two_dim_point_t {int x; int y};

void print_value(struct two_dim_point_t point)
{
    printf("point is (%d/%d)\n", point.x, point.y);
}

void print_pointer(struct two_dim_point_t *point)
{
    printf("point is (%d/%d)\n", point->x, point->y);
    /*
     * auch möglich:
     * (*point).x, (*point).y
     */
}

void foo(void)
{
     struct two_dim_point_t a;
     a.x = 1;
     a.y = 2;
     print_value(a);
     print_value(&a);
}

Select ist dazu da einen Descriptor (egal ob filedescriptor oder socket) zu überwachen und zu melden, wenn sich da was tut. Select ist praktisch, wenn ein Server mehrere Verbindungen gleichzeitig offen hat, aber mit einem einzigen Thread bedienen will. Was, wenn auf einem Socket nix kommt und der Server ewig auf Daten wartet, während auf dem anderen schon Überläufe sind? Select überwacht alle sockets und kehrt zurück, sobald sich an wenigstens einem etwas getan hat.

Du willst - wenn ich das richtig verstanden habe - genau das Gegenteil: Du willst erfahren, wenn nichts mehr kommt. Sowas ist per se unmöglich. Einziger ausweg: der Client sendet etwas wie "Ende der Übertragung" (z.B. als OOB Daten) oder es wird vereinbart, daß nach soundsoviel Sekunden (z.B. 200 ms) Funkstille angenommen wird, daß der Client fertig ist.
Im letzteren Fall kannst Du mit select arbeiten: Du mußt den Timeout setzen, dann, wenn select zurückkehrt, überprüfen, ob da Daten zum Verarbeiten sind, oder einfach nur der Timeout abgelaufen ist und je nachdem mal das eine und mal das andere tun.

Übrigens: Bevor nanosleep die Runde machte wurde select ohne irgendwelche descriptoren aber mit timeout zum kurzfristigen (<1s) schlafen verwendet.
 
Sorry, ich habe Dein zweites Problem mißverstanden:

struct ERR a;

int i = (int) &a;

struct ERR *b = (struct ERR*)i;

Der Compiler Meckert, weil die Größer der Struktur ERR 8 bytes ist (zwei ints), aber der returnwert (ein int) nur vier.

In C++ würde man übrigens

struct ERR *b = reinterpret_cast<struct ERR*>(i);

schreiben, was den Aspect des "einfach die BITS anders interpretieren" besser verdeutlicht.
 
@theHacker
Ahja, stimmt, da hab ich nicht drangedacht :biggrin:

@Samy
:kiss: das wars.
Ich hab mich verlesen bei den ganzen select() Erläuterungen.
Ich hab gedacht, wenn ich NULL anstatt eines Pointers auf den Timeout übergebe, blockiert select() gar nicht und wartet auch gar nicht.

Wenn ich ein Timeout angebe scheint es das gewollte VErhalten an den Tag zu befördern.

@dubberle
Sowas ist per se unmöglich.
Es geht um folgende Situation:
Jemand verbindet sich mit Telnet unter Windows zu meinem Serverprogramm.
Der Server erwartet nun ein Kommando, welches er Zeichenweise einliest.
Um zu wissen, wann das Kommando "fertig" ist, wartet er darauf, dass vom Clienten CR oder LF gesendet wird.
Windows sendet allerdings CRLF, dieses LF bekommt mein Server dann jedoch nicht mehr mit.
Ich brauche also eine Möglichkeit, abzufragen, ob noch ein LF im Eingabebuffer ist oder nicht.

Und da ja recv() unter normalen Umständen blockiert, ist select() ne nette Lösung ;)


@Struktur Zeugs.
Thx, habs noch nicht getestet, aber ich vertrau auf euch :biggrin: