c++ sockets recv

Gast #3844372
Hallo,
ich möchte/muss unter C++ mit Sockets arbeiten. Das sieht jetzt so aus 
und funktioniert:
1
char echo_buffer[RCVBUFSIZE];
2
int recv_size;
3

4
recv_size = recv(sock, echo_buffer, RCVBUFSIZE,0);
5
    if(recv_size < 0)
6
    error_exit("Fehler bei recv()");
7

8
echo_buffer[recv_size] = '\0';
9
leer[recv_size] = '\0';

Bei recv gibt er mir alle epfangenen Daten seit dem letzten Mal. Wenn 
aber keine Daten kommen, wartet er, bis Daten kommen. Das darf nicht 
sein.
Mit
1
recv_size > 0 //Daten sind da
wird das auch nichts.

Meine Frage:
Wie kann ich gucken, ob überhaupt in diesem Moment neue Daten verfügbar 
sind, damit recv auf gar keinen Fall wartet?
#3844391
Auf Linux "man recv" tippen oder ein Buch lesen?

Man kann den Socket Non-Blocking machen (mit fcntl) oder (üblicher) mit 
select abfragen, ob Daten anliegen.

Ich würde zum Erlernen der Socket-Programmierung das Buch Unix Network 
Programming von Ruchard W. Stevens empfehlen. Es enthält sehr gut 
dokumentierte Beispiele in C.
Gast #3844407
Danke für die Antworten!!!

Select scheint schonmal das richtige zu sein. Bisher suche ich noch nach 
einer Möglichkeit select() zu benutzen.

Hat da jemand einen Gedankenanstoß?
Gast #3844435
Irgendwie hat das alles nichts mit meinem TCP zu tun.

Also mein Code bisher sieht so aus:
1
#include "Tcp.h"
2
#include <stdio.h>
3
#include <stdlib.h>
4
#include <string.h>
5
#include <errno.h>
6

7
#include <iostream>
8
#include <string.h>
9
#include <cstring>
10

11
#include <sys/types.h>
12
#include <sys/socket.h>
13
#include <netinet/in.h>
14
#include <netdb.h>
15
#include <arpa/inet.h>
16
#include <unistd.h>
17

18
#define RCVBUFSIZE 8192
19

20
static void eingeben();
21
static void error_exit(char *errorMessage);
22
static void send(char *text);
23

24
int _port = 13050;
25

26
struct sockaddr_in server;
27
struct hostent *host_info;
28
unsigned long addr;
29

30
int sock;
31

32
unsigned int _len;
33

34

35
int Tcp::begin( int argc, char *argv[])
36
{
37
    //printf("" + argc);
38
    
39
    if (argc < 2)
40
        error_exit("usage: client server-ip echo_word\n");
41

42
    sock = socket( AF_INET, SOCK_STREAM, 0 );
43

44
    if (sock < 0)
45
        error_exit( "Fehler beim Anlegen eines Sockets");
46

47
    
48
    if ((addr = inet_addr( argv[1])) != INADDR_NONE)
49
    {
50
        //argv[1] sollte eine numerische IP-Adresse sein
51
        memcpy( (char *)&server.sin_addr, &addr, sizeof(addr));
52
    }
53
    else
54
    {
55
        //Computernamen oder "localhost" in IP-Adressen umwandeln
56
        host_info = gethostbyname(argv[1]);
57
        if (NULL == host_info)
58
        {
59
            addr = inet_addr( "127.0.0.1");
60
            memcpy( (char *)&server.sin_addr, &addr, sizeof(addr));
61
        }
62
        else
63
        {
64
            //Server-IP-Adresse
65
            memcpy( (char *)&server.sin_addr,
66
                    host_info->h_addr, host_info->h_length );
67
        }
68
    }
69

70
    //Eine IPv4-Verbindung solls werden
71
    server.sin_family = AF_INET;
72

73
    //Setze Portnummer
74
    server.sin_port = htons(_port);
75

76
    //Baue die Verbindung zum Server auf
77
    if(connect(sock,(struct sockaddr*)&server,sizeof(server)) <0)
78
        error_exit("Kann keine Verbindung zum "
79
                   "Server herstellen");
80
    
81
    
82
    return 0;
83
}
84

85
string Tcp::_all = "";
86

87
/**
88
 *  TCP-Eingabe überprüfen und gegebenenfalls verarbeiten lassen.
89
**/
90
bool Tcp::eingeben()
91
{
92
    sleep(10);
93
    
94
    char echo_buffer[RCVBUFSIZE];
95
    char leer[RCVBUFSIZE];
96
    int recv_size;
97

98
    recv_size = recv(sock, echo_buffer, RCVBUFSIZE,0);
99
    
100
    if(recv_size < 0)
101
        error_exit("Fehler bei recv()");
102

103
    echo_buffer[recv_size] = '\0';
104
    leer[recv_size] = '\0';
105

106
    std::string test1 = std::string(echo_buffer);
107

108
    int ready=select(sock_max+1, &sock, NULL, NULL, NULL);   //!! Das Problem!!
109
    
110
    if(recv_size > 0)
111
    {
112
      _all+=test1;
113
        
114
        //return 0;
115

116
        printf(echo_buffer);
117
      printf("\n");
118
      printf("=================================\n");
119
        return 1;
120
    }
121
    
122
    cout << _all << endl;
123
    
124
    _all = "";
125
    
126
    printf("\n");
127
    printf("=================================\n");
128
    
129
    return 1;
130
}
Gast #3844442
Der ist falsch. Wie es richtig geht steht in der man-Page, zu der ich 
Dir den Link gegeben habe. Passt ja schon allein mit den Datentypen 
nicht.

Ein Tipp: Im Link fragen sie Eingaben vom Keyboard ab (entspricht etwa 
einem Socket mit dem Wert 0).


Für den Rest: Tutorials sind dein Freund.
Gast #3844452
CC schrieb:
> Ah, es macht auch wenig sinn, recv() VOR select() aufzurufen.
> Letzteres
> teilt nämlich mit, ob recv() blockieren wird oder nicht.

Mir fehlt der erste Parameter von select() Das ist das große Problem.
Gast #3844453
c++ schrieb:
> #include <stdio.h>
In C++ heißt diese Datei <cstdio>
> #include <stdlib.h>
und die <cstdlib>
> #include <string.h>
und die <cstring>
> #include <errno.h>
und die <cerrno>
> #include <string.h>
und die <cstring> - hoppla, die haben wir ja schon includet
> #include <cstring>
Uund gleich noch einmal includen.

c++ schrieb:
> #define RCVBUFSIZE 8192
In C++ muss man sich keiner Textersetzung bedienen, sondern kann echte 
Konstanten verwenden um die diversen Makro-Probleme zu vermeiden:
1
const size_t RCVBUFSIZE = 8192;

Wie wäre es mit Boost.Asio, das ist genau dafür gedacht was du machen 
willst:
http://www.boost.org/doc/libs/1_56_0/doc/html/boost_asio.html
#3844612
Warum eigentlich überhaupt select()? Das ergibt doch hier überhaupt 
keinen Sinn. Das Haupt-Ziel von select() ist es, sich um mehrere fds 
gleichzeitig zu kümmern. Die gibt es hier aber gar nicht.
Es reicht, einfach den Socket non-blocking zu machen. Dann kehrt recv() 
immer ohne Wartezeit zurück, und wenn keine Daten verfügbar sind, 
liefert es -1 zurück, und errno wird auf den Wert EAGAIN gesetzt.

Dr. Sommer schrieb:
> In C++ muss man sich keiner Textersetzung bedienen, sondern kann echte
> Konstanten verwenden um die diversen Makro-Probleme zu vermeiden:
> const size_t RCVBUFSIZE = 8192;

Dann aber bitte auch nicht komplett groß scheiben, da das eigentlich das 
Erkennungszeichen für Makros ist.

c++ schrieb:
> Mir fehlt der erste Parameter von select() Das ist das große Problem.

Das große Problem ist eher, daß du noch gar nicht verstanden hast, was 
select() überhaupt tut.
Gast #3845866
struct pollfd fd;
int res;

fd.fd = s;
fd.events = POLLIN;
res = poll(&fd, 1, 1000); // 1000 ms timeout

if (res == 0)
{
    // timeout
}
else if (res == -1)
{
    // error
}
else
{
    // implies (fd.revents & POLLIN) != 0
    recv(s,buf,sizeof(buf),0); // we can read ...
}
Gast #3845868
c++ schrieb:
> Rolf Magnus schrieb:
>> Es reicht, einfach den Socket non-blocking zu machen. Dann kehrt recv()
>> immer ohne Wartezeit zurück, und wenn keine Daten verfügbar sind,
>> liefert es -1 zurück,
>
> Genau das will ich!!! Hast da jemand einen Ansatz?

Ich hab sogar mehrere:

- man-Page lesen
- Ein Buch lesen
- Nach dem Thema googeln
- falls das Lesen von Doku untragbar ist: umsatteln auf Briefmarken 
sammeln
Gast #3845885
Rolf Magnus schrieb:
> c++ schrieb:
>> Rolf Magnus schrieb:
>>> Es reicht, einfach den Socket non-blocking zu machen. Dann kehrt recv()
>>> immer ohne Wartezeit zurück, und wenn keine Daten verfügbar sind,
>>> liefert es -1 zurück,
>>
>> Genau das will ich!!! Hast da jemand einen Ansatz?
>
> Ich hab sogar mehrere:
>
> - man-Page lesen
> - Ein Buch lesen
> - Nach dem Thema googeln
> - falls das Lesen von Doku untragbar ist: umsatteln auf Briefmarken
> sammeln

Danke! Ich hasse nur leider Sockets in C++ und brauche diese für EIN 
Projekt. Und dieser ganze FD-Mist entsprach nicht im Ansatz dem, was ich 
gebraucht habe. Nach langer Suche ohne FD hab ich nun
1
fcntl(sock, F_SETFL, O_NONBLOCK)
gefunden, was mein Problem löst.

Rolf Magnus schrieb:
> Dann aber bitte auch nicht komplett groß scheiben, da das eigentlich das
> Erkennungszeichen für Makros ist.

Stimmt. Der gepostete Code ist Dreck, das weiß ich selbst. Der Rest des 
Projektes sieht deutlich sauberer aus. Wir sind nämlich keine Anfänger. 
Da dieser Teil aber Softwaretechnisch unser größtes Problem darstellte, 
haben wir uns erst um eine Lösung bemüht und kümmern uns nun auch in 
dieser Klasse um einen sauberen Programmierstil.


Rolf Magnus schrieb:
> Ich hab sogar mehrere:
>
> - man-Page lesen
> - Ein Buch lesen
> - Nach dem Thema googeln
> - falls das Lesen von Doku untragbar ist: umsatteln auf Briefmarken
> sammeln

Ich lese oft Doku. Das hat mir in diesem Fall leider nicht besonders 
geholfen. Da C++ keine besonders neue Sprache ist (damit wurden schon 
uralte Großrechner programmiert, lange vor TCP) , ist der ganze TCP-Kram 
nicht so in der Sprache drin, wie in anderen Programmiersprachen.
In C# oder Java ist das schon einfacher. Da tut es "ein wenig" Doku 
lesen. So hardwareferne Sprachen können wir hier aber leider nicht 
gebrauchen.

==========

Vielen Dank an alle, die nach einer Lösung gesucht haben.
Gast #3845986
c++ schrieb:
> Nach langer Suche ohne FD hab ich nunfcntl(sock, F_SETFL, O_NONBLOCK)
> gefunden, was mein Problem löst.

Um ehrlich zu sein wundert mich das. Wenn man bei google nach 
"non-blocking socket" sucht, bekommt man seitenweise Ergebnisse, wo das 
drin steht.

c++ schrieb:
> Da C++ keine besonders neue Sprache ist (damit wurden schon
> uralte Großrechner programmiert, lange vor TCP) , ist der ganze TCP-Kram
> nicht so in der Sprache drin, wie in anderen Programmiersprachen.

Bei boost gibt's ein socket-API für C++. Hab ich aber noch nicht 
ausprobiert.
Persönliche Seite #3846113
c++ schrieb:
> Da C++ keine besonders neue Sprache ist (damit wurden schon uralte
> Großrechner programmiert, lange vor TCP)

hust

C++ gibt es effektiv* erst seit 1985, TCP ist gut zehn Jahre älter ...

Sprachbestandteil ist "der ganze TCP-Kram" aus ganz anderen Gründen 
nicht.

*) Den Namen gibt es seit '83, '85 erschien die erste Ausgabe des Buchs 
von Stroustrup

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 12 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.