Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
000
09.05.2007, 16:49
Felheart



Hi,

ich hab nen LSocket, der wartet einfach auf ankommende clients. (LSocket == ListenSocket)

Und ich hab ein Array von CSockets (CSocket == ClientSocket)
auf dem die bereits verbundenen clients rumdödeln.

Wenn eine Verbindung auf'm LSocket eingeht dann will ich das der LSocket
seine Verbindung sofort einem freien ClientSocket zuweist und dann wider in den Listen modus geht um weiter clients zu emfangen :)

Jetzt meine Probleme:

1.
Was muss ich beim kopieren der Socketverbindung von L- nach CSocket alles kopieren ?

Nur den Socket ?
-> Ich kann keine Ip mehr vom Socket auslesen da die Address struct nicht mitkopiert wird

Socket und die "SOCKADDR_IN" ?
-> dann hab ich aber ne 1:1 kopie, und neue Clients wollen dann auf den
client Socket verbinden da der port überschieben wird.

Socket und alles von der Stuctur bis auf SOCKADDR_IN.sin_port =
-> Das geht, aber ist das so richtig ? Wird das wirklich SO umständlich gemacht ??

2. Wie setzt ich den ListenSocket wieder in den Lausch modus ?

Muss ich den Socket KOMPLETT neu aufbauen ?
also closesocket -> socket -> bind -> listen ?

Oder kann ich einfach nur wieder listen() machen ?
Da besteht dann aber das problem das der Socket immer noch connected is...

Wäre nett wenn mir einer hier die dinge ein bissel klarer machen würde bzw. wie ihr / wie man das richtig macht.

edit:

Wenn ich 3 verschachtelte for(;;) Schleifen habe und in der innersten ein break; hört die innerste schleife auf.
Wie kann ich aus der innersten schleife heraus aus der äussersten aussteigen ?

--


Dieser Beitrag wurde am 09.05.2007 um 18:29 von Felheart bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
001
09.05.2007, 19:47
HammerBlade



Du hast das ganze irgendwie nicht richtig verstanden, scheint mir.

Du öffnest mit socket + bind + listen eine Listensocket. Dieser bleibt die ganze Zeit ein Listensocket und offen. Dann rufst du accept mit dem Listensocket auf. Dieses blockt dann bis ein Client connected und gibt dir den Clientsocket sowie die Adresse des Clients zurück.

SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen);

Hier ist s dein Listensocket, addr ist eine sockaddr in die dir accept die Adresse des Clients reinschreibt und der Socket der zurückgegeben wird ist der neu erzeugte Clientsocket.

Aus verschachtelten Schleifen kommt man per goto raus (jetzt melden sich gleich wieder die Leute die gegen goto's sind zu Wort) oder indem du im innersten Block einen bool auf true setzt, in jedem Schleifenkopf auf diesen bool prüfst und abbrichst wenn dieser bool true ist.

--

"Mit C++ (noch besser mit C) kann man sich _sehr_ leicht in den Fuss schiessen." - theDon
Auspack und freu! - Auszug aus einer, aus dem japanischen übersetzten, Bedienugsanleitung für ein Spielzeugaquarium.
--
Photon Audio Player | Majestic42.net | How To Ask Questions The Smart Way

zum Seitenanfang zum Seitenende Profil || Suche
002
09.05.2007, 21:11
Felheart



Hey ^^ ich glaub da hab ich mich entweder total falsch ausgedrückt oder
du hast mich ned ganz verstanden.

Weil GENAU das was du da beschriben hast tu ich doch :)
Bessergesagt:

Ich hab mir ne Socket Klasse gemacht,
die besteht aus zwei teilen:
ServerSocket und ClientSocket

Auf meinem Server mach ich also:

ServerSocket LISTEN(1337, true); // parameter: port, listen
und dann eben noch die clients in nem Array.

Für den Server Socket hab ich die Funktionen SOCKET ServerSocket::GetSocket()

und ServerSocket::SetSocket(SOCKET _s)

und meine frage ist:

Muss ich nur den Socket vom LISTEN Socket einem freien Client Slot
zuweisen oder den Socket UND die SOCKETADDR_IN (wobei ja dann auch der port geändert wird)?

und 2.

Wenn ich vom Listen Socket die verbindung "abgegriffen" habe,
wie versetzt ich den Socket dann wieder in den Listen modus ?

Reicht es wenn ich nur ServerSocket::SetListenMode() mach ?
oder muss ich den socket ganz neu aufbauen ?
Also: closesocket + socket + bind + listen ?

edit:
Man muss ja nicht immer gleich nen neuen Thread aufmachen :)
Angenommen ich hab ein "int ar[5];" dann veränder ich dessen dimensionsgröße mittels "realloc"

Aber wenn ich ein int "ar[5][6][3];" habe, wie änder ich da zum beispiel die 2. dimension ?

--


Dieser Beitrag wurde am 09.05.2007 um 21:17 von Felheart bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
003
09.05.2007, 22:45
HammerBlade



Ah. Der Socket reicht, ausser du willst noch was mit der SocketAddr machen ,die du von accept() bekommst, also anzeigen oder so, weil für recv()/send() brauchst du die ja nicht mehr.

Und wie gesagt ein Listensocket bleibt immer im Listenmode, d.h. du musst nichts tun nach einem accept() damit der Listensocket weiter Verbinungen animmt.

Du hast einen int ar[5]; auf dem Stack und ändert den mit realloc? Das ist nicht gut! Du meinst nicht int* ar = malloc(5 * sizeof(int)); ? Auf dem Stack sollte dir realloc um die Ohren fliegen. Die Grösse von Arrays auf dem Stack kannst du garnicht ändern. Du kannst das nur ändern wenn du das mit malloc gemacht hast.

--

"Mit C++ (noch besser mit C) kann man sich _sehr_ leicht in den Fuss schiessen." - theDon
Auspack und freu! - Auszug aus einer, aus dem japanischen übersetzten, Bedienugsanleitung für ein Spielzeugaquarium.
--
Photon Audio Player | Majestic42.net | How To Ask Questions The Smart Way

zum Seitenanfang zum Seitenende Profil || Suche
004
10.05.2007, 11:23
oxff



Wenn man realloc auf einen Stack-Pointer anwendet, kann man relativ lustige Effekte erzielen. Dann werden die Daten dadrüber (wenn der Stack-Pointer oben ist, sind das dann sogar lokale Daten von einer vorherigen Prozedur) als Heap-Header interpretiert und irgendwo dann hingeschrieben.
Jetzt denkt man sich natürlich, schön, wofür braucht man denn sowas. Das ganze ist halt relativ nett, wenn man eine versteckte Backdoor in den Source einbauen will; ich hab sowas mal bei einem Bot-Source gesehen -- da konnte man dann gezielt einen 4-Byte overwrite triggern, ohne Heap-Overflow.

Bzgl. der Ports usw.: Fahr dir mal rein, wie TCP funktioniert. Du hast das offensichtlich noch nicht verstanden.

--

mwcollect - mein Projekt | oxlog - mein blog | happyhardcore.com Stream - gute Musik

zum Seitenanfang zum Seitenende Profil || Suche
005
10.05.2007, 11:51
Felheart



accept(); lieftert nur INVALID_SOCKET
10022: Ein ungültiges Argument wurde angegeben.

edit: Hier hab ich mal meine accept funktion:
Quellcode:bool ServerSocket::Accept()
{
    int sz = sizeof(addr);
    SOCKET err = accept(sock, (SOCKADDR*)&addr, &sz);

    if(err == INVALID_SOCKET)
        return false;

    sock = err;
    connected = true;
    return true;
    
}
Zu dem Array:

Zitat:
Du meinst nicht int* ar = malloc(5 * sizeof(int)); ?
Doch das mein ich ^^ ups.
Ja, davon kann man die grösse ja ändern mit realloc.

Jetzt frag ich mal andersherum:
Mit " int* ar = malloc(5 * sizeof(int));"
allokier ich ein array aus int mit einer dimension die 5 ints tief ist.

Wie kann ich dann mittels malloc ein array allozieren das mehrere dimensionen hat ?

Beispiel:

int ar[5]; // Static
int* ar = malloc(5 * sizeof(int)); // Dynamic

und

int ar[5][5][5]; // Static
? ? ? // Dynamic ???

--


Dieser Beitrag wurde am 10.05.2007 um 11:56 von Felheart bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
006
10.05.2007, 11:57
oxff



Zwei Möglichkeiten:

Quellcode:int sizeX = 5;
int sizeY = 10;
int sizeZ = 20;
int * array = malloc(sizeX * sizeY * sizeZ * sizeof(int));

// ...

int foo = array[x * sizeY * sizeZ + y * sizeY + z];
oder

Quellcode:int * * * array = malloc(sizeX);

for(int i = 0; i < sizeX; ++i)
{
  array[i] = malloc(sizeY);

  for(int j = 0; j < sizeY; ++j)
    array[j] = malloc(sizeZ);
}

// ...

int foo = array[x][y][z];
Variante I ist speichertechnisch optimaler und schneller zu initialisieren, Variante II ist dafür bei jedem zugriff wesentlich schneller. Den Unterschied wirst du vermutlich aber eh nicht merken.

--

mwcollect - mein Projekt | oxlog - mein blog | happyhardcore.com Stream - gute Musik

zum Seitenanfang zum Seitenende Profil || Suche
007
10.05.2007, 12:24
Felheart



Thx, das funkt.

Aber das mit den Sockets liegt immernoch im argen...

Listen + Accept
-> Client Connected auf den ListenSocket
-> Wird von accept() aangenommen
-> Socket (und nur der Socket) wird auf einen freien clientsocket kopiert
-> Der ClientSocket funktioniert perfekt

-> Der ListenSocket soll wieder verbindungen annehmen können
dazu nehm ich Listen(); dann Accept();

-> Listen schlägt fehl und meldet per GetLastError das der Socket ja schon
connected is und das deswegen jetzt nich geht >_<
(Somit schlägt auch das daruffolgende accept() fehl)

Also wie lösch ich die verbindung vom dem ListenSocket nachdem ich
sie einem ClientSocket übertagen habe ?

edit: Wenn ich vor Listen+Accept den Socket auf 0 setzte kommt das das angegebene Objekt kein Socket ist

edit2: Wenn ich nen neuen Socket haben will (per socket(...)) dann kommt
10022: Ein ungültiges Argumnet wurde angegeben.

--


Dieser Beitrag wurde am 10.05.2007 um 12:28 von Felheart bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
008
10.05.2007, 12:33
oxff



Bist du ein bisschen dumm? :>

Quellcode:int sock = socket(AF_INET, SOCK_STREAM, 0);

// declare and set myAddr here ...

bind(sock, (struckt sockaddr *) myAddr, sizeof(myAddr));
listen(sock, 16);

while(true)
{
  int clientsock = accept(sock, 0, 0);

  send(clientsock, "SUCKER\r\n", 8, 0);
  close(clientsock);
}
Du musst nach einem accept nichts anderes machen, als accept wieder aufzurufen.

--

mwcollect - mein Projekt | oxlog - mein blog | happyhardcore.com Stream - gute Musik

zum Seitenanfang zum Seitenende Profil || Suche
009
10.05.2007, 12:48
Felheart



Ne ich bin ned dumm... es tut nur einfach nich!

Wenn ich es so mache wie du es da hast und nach dem abgreifen der Verbindung einfach wieder accept(); für den ListenSocket aufrufe liefert mir
accept ja auch SOCKET_ERROR zurück >_<

und per GetLastError();

"10022: Ein ungültiges Argument wurde angegeben."

Meine Accpet funktion hab ich oben schon gepostet...

edit:

wenn ich deinen code in nem neuen project ausfühere:

GetLastError: 10038:Ein Vorgang bezog sich auf ein Objekt, das kein Socket ist.

ich vermute weil du einen per closesocket geschlossenen socket nicht mehr
für accept( gebraucen kannst)

edit2:

Ahhhhhhh! Die erleuchtung :D

SOCKET is ja sozusagen blos ein zeiger auf eine Verbindung.
Wenn ich jetzt den Socket kopier (auf den client socket!)
und dann wieder ListenSocket->Listen(); oder ->Accept(); mache
dann bezieht sich der verbundene socket ja immernoch auf
die GLEICHE verbindung!

und weil mein Client gerade mit dem arbeitet / weil er noch connected is,
kann das garned gehen!

D.h. -> in meiner ServerSocker::Listen(); funktion muss also der
alte socket freigegeben werden und ein neues per socket(...) geholt werden.

edit3:
Wenn ich Listen(); so umänder das der alte socket nicht geschlossen wird (darf er ja auch ned, mein client mach ja damit rum)
und mein listen dann einen neuen Socket "beantragt"
und dann bind() und listen() macht

dann... gehts immer noch nich -___-

edit4:
so aber jetzt fast! xD

Jetzt schlägt nur noch bind() beim neuen socket fehl weil der alte port noch
in verwendung ist..
kann aber ganred sein oO
weil ich ja für clientSockets andere Ports benutz als für den listenSocket...

hier soweit mal mein ServerSocket::Listen()

Quellcode:bool ServerSocket::Listen()
{
    sock = socket(AF_INET,SOCK_STREAM,0);
    if(sock == INVALID_SOCKET) // Neuen Socket holen
    {
        printf("Listen:Socket() %d", GetLastError());
        error = true;
        return false;
    }

    int b = bind(sock, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN));
    if(b != 0) // Neuen Socket binden... geht irgenwie ned >_<
    {
        printf("Listen:Bind() %d\n", GetLastError());
        error = true;
        return false;
    }

    int l = listen(sock, 5); // Listen mode halt
    if(l == SOCKET_ERROR)
    {
        printf("Listen:Listen(): %d\n", GetLastError());
        error = true;
        return false;
    }
    return true;
}

--


Dieser Beitrag wurde am 10.05.2007 um 13:36 von Felheart bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
010
10.05.2007, 15:43
theDon



Du hast es immer noch nicht gerafft:

Quellcode:SOCKET err = accept(sock, (SOCKADDR*)&addr, &sz); Im Allgemeinen ist danach sock unveraendert und err != sock, insbesondere fuer err != INVALID_SOCKET ist err ein gueltiges, verbundenes socket.

--

\o tanz den naziprau! o/

And more than ever, I hope to never fall,
Where enough is not the same it was before

zum Seitenanfang zum Seitenende Profil || Suche
011
10.05.2007, 16:35
Felheart



:/
Also brauch ich in meiner ServerSocket Klasse also 2 Sockets.
einen den ich immer mit meinen accepts bedränge und den anderen
von dem ich die Verbindung zu einem client nehm und an einen
ClientThread weitergeb....

Oder ich könnte die Accept funktion der Klasse so umschreiben das sie direkt den neuen Socket returnt (bei nem fehler halt 0)

Wie auch immer, danke fürs Beispiel!

--


Dieser Beitrag wurde am 10.05.2007 um 19:25 von Felheart bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
012
10.05.2007, 19:18
oxff



Erhaeng dich. Du bist dumm.

--

mwcollect - mein Projekt | oxlog - mein blog | happyhardcore.com Stream - gute Musik

zum Seitenanfang zum Seitenende Profil || Suche
013
10.05.2007, 20:19
HammerBlade



Letzter Versuch:

Quellcode:class ClientSocket {
public:
    ClientSocket(SOCKET socket, SOCKADDR addr) {
        mSocket = socket;
        mAddr = addr;
    }
    
    [...]
    
    SOCKET mSocket;
    SOCKADDR mAddr;
};

class ServerSocket {
public:
    [...]
    
    bool Listen(SOCKADDR addr);
    ClientSocket* Accept();
    
    [...]
    
    SOCKET mSocket;
};

bool ServerSocket::Listen(SOCKADDR addr) {
    mSocket = socket(AF_INET, SOCK_STREAM, 0);
    
    if (mSocket == INVALID_SOCKET)
        return false;
    
    int error = bind(mSocket, (SOCKADDR*)&addr, sizeof(SOCKADDR));
    
    if (error == SOCKET_ERROR)
        return false;
    
    error = listen(mSocket, 5);
    
    if(error == SOCKET_ERROR)
        return false;
    
    return true;
}

ClientSocket* ServerSocket::Accept() {
    SOCKET client_socket;
    SOCKADDR client_addr;
    int size = sizeof(SOCKADDR);
    
    client_socket = accept(mSocket, (SOCKADDR*)&client_addr, &size);
    
    if(client_socket == INVALID_SOCKET)
        return NULL;
    
    return new ClientSocket(client_socket, client_addr);
}

int main() {
    [...]
    
    ServerSocket server;
    SOCKADDR addr;
    
    // addr für den ServerSocket initialisieren
    [...]
    
    server.Listen(addr);
    
    while (true) {
        ClientSocket* client = server.Accept();
        
        // Sachen mit dem ClientSocket machen, dem ClientThread geben,
        // was aich immer. Aber nie wieder Listen() auf dem ServerSocket
        // aufrufen
    }
    
    [...]
}

--

"Mit C++ (noch besser mit C) kann man sich _sehr_ leicht in den Fuss schiessen." - theDon
Auspack und freu! - Auszug aus einer, aus dem japanischen übersetzten, Bedienugsanleitung für ein Spielzeugaquarium.
--
Photon Audio Player | Majestic42.net | How To Ask Questions The Smart Way

zum Seitenanfang zum Seitenende Profil || Suche
014
11.05.2007, 15:30
Felheart



Ok, habs verstanden.
alles geht jetzt :)

Bei HammerBlades bespiel ist jetzt der groschen gefallen das ich garned
von 0 bis %maximal_players ports brauch :O

--

zum Seitenanfang zum Seitenende Profil || Suche
015
11.05.2007, 22:30
Felheart



Sie können diesen Post nicht mehr editieren. (Zeitlimit überschritten)
Ich hätte aber trotzdem noch eine Frage


Was ich machen möchte ist eine funktion wie bei CS.
Wenn ein Client nicht mehr reagiert dann soll er gekickt werden.
Beispiel aus CS: Player LAWL left the game: (Connection timed out).

Setzt select() das das error flag auf den socket ?
Oder wird ein "nicht reagieren" garnicht als error betrachtet ?
Müsste ich dann etwa für jeden Client nen Timer einrichten um zu überprüfen
ob er seit 20sec. nix gesendet hat ?

--

zum Seitenanfang zum Seitenende Profil || Suche
016
12.05.2007, 15:32
oxff



Wie soll denn select wissen, wie lange du stillschweigen akzeptierst?

--

mwcollect - mein Projekt | oxlog - mein blog | happyhardcore.com Stream - gute Musik

zum Seitenanfang zum Seitenende Profil || Suche