Autor Wątek: [SDL_net]znajdywanie innych klientów UDP w sieci lan  (Przeczytany 1887 razy)

Offline magik6000

  • Użytkownik

# Wrzesień 11, 2012, 18:11:22
Znowu mam problem, znowu z SDL_net, ale dla odmiany z UDP..
Generalnie tworzę coś w rodzaju p2p w sieci lan. Klienty znajdują siebie w dość prosty(czysto teoretycznie dobry) sposób, przy czym wszystko powinno działać ok, ale tak nie jest. Samo wyszukiwanie jest takie:
1. parsuje sobie komendę "ipconfig"(_popen), zapamiętuje adresy wszystkich kart do vectora (działa)
2. inicjuje sobie socket UDP przez SDL_net, na porcie od 34513 do 34513+10(na pierwszym wolnym) (dziala)
3. spamuje do sieci pakietami o ustalonej treści, na adresy ip, które wcześniej zdobyłem, zmieniając ich ostatni człon od 0 do 255, na portach od 34513 do 34513+10 (prawdopodobnie działa(SDLNet_UDP_Send zwraca 1))
4. sprawdzam czy socket był aktywny, jeśli był to odbieram pakiet i dalej się łącze, itp.(problem w tym, że mimo, że funkcja SDLNet_CheckSockets ZAWSZE przepuszcza dalej przez if'a, a nawet jeśli coś powinno być do odebrania, to SDLNet_UDP_Recv zwraca 0(nic do odebrania)).
kod funkcji "spamującej" pakietami:
void spam_net(UDPsocket udp,int intport)
{
    int datasent=0;
    cout <<"spam to "<<rtdips()->size()<<" ips\n";
   
    //rtdips() zwaraca wskaznik na vektor z adresami ipv4 (Uint32)
    //intport to port na ktorym otwarty jest socket udp

    for(int i=0; i<rtdips()->size(); i++)
    {
        for(int j=0; j<256; j++)
        {
            for(int k=0;k<port_range;k++)
            {
                if(k != intport )
                {


                    UDPpacket* spampacket = SDLNet_AllocPacket(4);
                    spampacket->data[0]='M';
                    spampacket->data[1]='O';
                    spampacket->data[2]='S';
                    spampacket->data[3]=net_version;


                    //((Uint32*)&spampacket->data)[1]=(*rtdips())[i];
                    //((Uint16*)&spampacket->data)[4]=first_port;

                    spampacket->len=4;

                    spampacket->address.port=first_port+k;
                    spampacket->address.host=(*rtdips())[i];
                    ((Uint8*)&(spampacket->address.host))[3]=j;

                    //cout << "spamming with data a:"<<(float(i)/rtdips()->size())*100.f<<"%("<<rtdips()->size()<<"), b:"<<(j/255.f)*100.f<<"%\n";

                    if(SDLNet_UDP_Send(udp, -1, spampacket))
                    {
                        datasent+=4;
                    }

                    SDLNet_FreePacket(spampacket);
                }
            }
        }
    }

    cout << "spamed with "<<datasent<<"bytes\n";


}

kod funkcji odbierającej powyższy "spam":
void recv_spam(UDPsocket usock,SDLNet_SocketSet uset)
{

    if(SDLNet_CheckSockets(uset,0))//w socket secie jest tylko 1 socket(usock)
    {

        UDPpacket* spampacket = SDLNet_AllocPacket(400);

        int rcc=SDLNet_UDP_Recv(usock, spampacket);

        if(rcc==1)
        {
            cout << "recived sth.\n";
        }
        else
        {
            if(rcc==-1)
            {
                printf("UDP Recv: %s\n", SDLNet_GetError());
            }
        }

        SDLNet_FreePacket(spampacket);

    }

}

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Dab

  • Redaktor
    • blog

# Wrzesień 11, 2012, 18:33:44
Zaraz, zaraz, zdajesz sobie sprawę że w UDP możesz wysłać broadcast pod 255.255.255.255? :)

Offline magik6000

  • Użytkownik

# Wrzesień 11, 2012, 18:37:53
yyyyyymmm, takie to jest myślenie o 3ciej w nocy, o broadcascie wiedzialem, ale zapomniałem :D, zaraz sprawdzę :)

Offline Super Vegeta

  • Użytkownik
    • SV Games

# Wrzesień 12, 2012, 01:08:06
Uhm, z tego, co widzę, patrząc w dokumentację, to tak:
- SDLNet_UDP_Recv zwraca wektor pakietów, a nie pojedynczy pakiet - więc przekazując tam pojedynczy spampacket, miast tablicy, narażasz się na access violation czy inne cudo
- wyżej wspominiana funkcja zwraca ilość odebranych pakietów, więc jeśli zaspamujesz sieć więcej niż raz, int rcc będzie > 1.

Offline magik6000

  • Użytkownik

# Wrzesień 12, 2012, 16:55:41
 SDLNet_UDP_Recv zwraca 1 pakiet, wskaźnik jest, tylko dla tego, że funkcja musi jakoś do pakietu dane wpisać, a zwraca "Returns: 1 is returned when a packet is received. 0 is returned when no packets are received. -1 is returned on errors.", no chyba, że spojrzałeś się na SDLNet_UDP_RecvV, której nie użyłem, przeżuciem się na broadcast, niedługo powinno już być w stadium działania(kod jest cały, lokalnie działa ok, ale ma problemy w sieci(zapewne jest to kwestia czegoś śmisznego w stylu || zamiast &&))

Offline Super Vegeta

  • Użytkownik
    • SV Games

# Wrzesień 12, 2012, 17:33:27
Tak, mój błąd, pomyliłem. Patrząc na to jeszcze raz, jedyne, co przychodzi mi do głowy, to dodanie >0 przy SDLNet_CheckSockets - być może funckcja zwraca błędy, tj. -1, co jest przeliczane na true?
« Ostatnia zmiana: Wrzesień 12, 2012, 17:35:06 wysłana przez Super Vegeta »

Offline magik6000

  • Użytkownik

# Wrzesień 12, 2012, 22:52:52
już brakuje mi pomysłów, ale mam wrażenie, iż jestem b.blisko, poniżej kody funkcji odpowiedzialnych za znajdowanie i "łączenie" klientów:
bool cl0=false;//otrzymano pakiet broadcastowy
bool cl1=false;//otrzymano pakiet zapraszający

bool recv_spam(UDPsocket usock,SDLNet_SocketSet uset, IPaddress& eip)
{

    if(SDLNet_CheckSockets(uset,0))
    {

        int rcc=1;
        while(rcc)
        {
            UDPpacket* spampacket = SDLNet_AllocPacket(512);
            rcc=SDLNet_UDP_Recv(usock, spampacket);
            if(rcc==1)
            {
                if(spampacket->data[0]=='M'&&spampacket->data[1]=='O'&&spampacket->data[2]=='S'&&spampacket->data[3]==net_version)
                {
                    bool notvalid=false;
                    for(int i=0; i<rtdips()->size(); i++)
                    {
                        if((*rtdips())[i]==spampacket->address.host&&SDLNet_UDP_GetPeerAddress(usock,-1)->port==spampacket->address.port)
                        {
                            notvalid=true;
                        }
                    }
                    if(!notvalid)
                    {
                        cout << "got VALID mos broadcast, resending pair packet\n";
                        IPaddress rcip;
                        rcip.host=spampacket->address.host;
                        rcip.port=spampacket->address.port;

                        //SDLNet_ResolveHost (&rcip, "192.168.0.103", spampacket->address.port);

                        SDLNet_FreePacket(spampacket);
                        spampacket = SDLNet_AllocPacket(4);
                        spampacket->data[0]='M';
                        spampacket->data[1]='O';
                        spampacket->data[2]='A';
                        spampacket->data[3]=net_version;
                        spampacket->len=4;
                        spampacket->address.host=rcip.host;
                        spampacket->address.port=rcip.port;
                        SDLNet_UDP_Send(usock, -1, spampacket);

                        cout << "SNS: "<<spampacket->status<<endl;

                        cl0=true;
                        if(cl1)
                        {
                            eip.host=spampacket->address.host;
                            eip.port=spampacket->address.port;
                            cout << "game begin\n";
                            return true;
                        }
                    }
                    else
                    {
                        cout << "invalid mos packet("<<spampacket->len<<")\n";
                    }
                }
                else if(spampacket->data[0]=='M'&&spampacket->data[1]=='O'&&spampacket->data[2]=='A'&&spampacket->data[3]==net_version)
                {
                    //stop broadcasting, etc.
                    cout << "INVITED TO GAME!!\n";
                    cl1=true;
                    if(cl0)
                    {
                        eip.host=spampacket->address.host;
                        eip.port=spampacket->address.port;
                        cout << "game begin\n";
                        return true;
                    }
                }
            }
            else
            {
                if(rcc==-1)
                {
                    printf("UDP Recv: %s\n", SDLNet_GetError());
                }
            }
            SDLNet_FreePacket(spampacket);
        }
    }
    else
    {
        cout << "idl\n";
    }
    return false;
}


void spam_net(UDPsocket udp,int intport)
{
    int datasent=0;

    //rtdips() zwaraca wskaznik na vektor z adresami ipv4 (Uint32)
    //intport to port na ktorym otwarty jest socket udp

    for(int k=0; k<port_range; k++)
    {
        UDPpacket* spampacket = SDLNet_AllocPacket(4);
        spampacket->data[0]='M';
        spampacket->data[1]='O';
        spampacket->data[2]='S';
        spampacket->data[3]=net_version;

        spampacket->len=4;

        ((Uint8*)&(spampacket->address.host))[255]=255;
        IPaddress addr;
        SDLNet_ResolveHost (&addr, "255.255.255.255", first_port+k);
        spampacket->address.port = addr.port;
        spampacket->address.host = addr.host;

        SDLNet_UDP_Send(udp, -1, spampacket);
        SDLNet_FreePacket(spampacket);

    }

   

}

generalnie na 1-nym kompie wszystko jest ok, ale gdy uruchamiam to na 2 kompach w sieci(lan ofc.) na 1-szym wypisuje "got VALID mos broadcast, resending pair packet", czyli otrzymuje pakiet broadcastowy (zapraszającego nie widzi), a na 2-gim jest tylko "INVITED TO GAME!!", funkcje oczywiście w pętli:
while(!con){
            spam_net(udp,dport);
            con=recv_spam(udp,udpset,p2ip);
            SDL_Delay(2000);
}
ma ktoś jakieś podejrzenia, co może powodować takie zachowanie? (ew mogę jeszcze podesłać pokrojoną binarke samej gry)