Male pytanie odnosnie winsock & recv

0

Witam. Napisalem maly program analizujacy wiadomosci na irc, nie jest to spamer. Pomaga mi wyszuac ludzi o odpowiednich kryteriach. Wszystko dziala prawie dobrze... Od czasu do czasu wystepuje blad, tak jakby 2 wiadomosci lacza sie w 1 i sa odebrane na raz co powoduje bug'a. Tu moje pytanie czy moge w ten sposob uzyc funkcji recv?

recv(sServ, buffer, 512, 0);

Nie wiem czy moge ustawic na sztywno dlugosc "buffer" - wyczytalem w RFC irc'a ze maxymalna dlugosc pakietu to 512, normalnie jest to okolo 100 czyli spora czesc jest nie uzywana. Czy to moze powodowac problem? Mysle tez o napisaniu funkcji ktora bedzie odbierala po znaku zanim nie napotka '\r', ale to ostatecznosc. Mam nadzieje ze nie namotalem, pozdro ;)

0

http://msdn.microsoft.com/en-us/library/ms740121%28v=vs.85%29.aspx
czyli Twoje recv, odczyta maksymalnie 512 bajtów, a ile dokładnie wczyta możesz sprawdzić tak:
int n =recv(sServ, buffer, 512, 0);

jeśli koniecznie musisz mieć 512 to możesz zrobić tak: (pisane z ręki więc mogą być błędy)

int br = 0; //ilosc bajtow odebranych
while (br!=512)
{
  int n = recv(sServ, buffer, 512-br, 0);
  br+=n;
}

ale bardziej polecam zrobić pętle odbierającą zawsze np te 512 bajtów, parsowanie odebranych danych i odbieranie danych dalej (w jakimś wątku najlepiej).

zastanów się co rozumiesz przez słowo pakiet, bo recv służy do odbierania danych, a pakiety z tych danych musisz sobie sam uformować.

0

W programowaniu sieciowym jestem laik, wiem wiem ze pakiet powstaje po parsowaniu. Tak myslalem ze sie nie zrozumiemy ale sprobuje jeszcze raz ;p. Nie chodzi mi o to zeby koniecznie odebrac na raz te 512 bajtow, nawet tak nie chce. Chyba zle przedstawilem problem, probuje sie dowiedziec czy jezeli do recv() dam char buffer[512] to istnieje mozliwosc ze znajda sie w niej 2 male pakiety? Czy zawsze jest tak ze recv odbiera tylko jeden pakiet?

0

Dalej się nie rozumiemy. Co rozumiesz poprzez pakiet?
Generalnie obojętnie co odpowiesz na to pytanie, odpowiedź na Twoje brzmi: TAK, może odebrać więcej

0

Przez pakiet rozumiem ciag znakow zakonczony \r\n. Enyłej, otrzymalem odpowiedz i wiem co jest do poprawki. Jednak bede musial odbierac po znaku... Dzieki za pomoc :)

0

nie musisz odbierać po znaku. Możesz zostawić tak jak jest, tylko np zrobić dwa bufory:

  1. na odbieranie (np. ten co juz masz 512bajtow)
  2. na parsowanie (ok. 3x większy od tego wyżej, zakładając że najdłuższa długość linii to 512bajtów)
    w drugim buforze zapisz sobie takie dane:
    początek
    koniec
    i wyjdź z założenia że początek nie zawsze musi być w tym buforze przed końcem, ponieważ do tego bufora powinieneś zapisywać w kółko: (pisane z reki)
char buff[1536];
char buff_odb[512];
char* buff_end = buff+1536;
char* pocz = buff;
char* koniec = buff;
while (!koniecprogramu)
{
int n = recv(sServ, buff_odb, 512, 0);
if (koniec+n>buff_end)
  {
    int dokonca = (int)(buff_end-koniec);
    memcpy(koniec,buff_odb,dokonca);
    memcpy(buff,buff_odb+dokonca,n-dokonca);
    koniec = buff+n-dokonca;
  }
else
  {
    memcpy(koniec,buff_odb,n);
    koniec+=n;
  }
// parsowanie:
char* p= pocz;
while (p!=koniec)
  {
    // tutaj sobie sprawdzasz czy wystapil po kolei ciag \r\n i znak za miejscem tego wystapienia uystawiasz pocz = te_miejsce
    if (p==buff_end)
      p = buff;
  }
}
0

Dzis mam 6h lekcji na komputerze to przeanalizuje Twoj kod. Dzieki za zainteresowanie :)

0
arasso12 napisał(a)

Przez pakiet rozumiem ciag znakow zakonczony \r\n. Enyłej, otrzymalem odpowiedz i wiem co jest do poprawki. Jednak bede musial odbierac po znaku... Dzieki za pomoc :)

Jesli chodzi o Winsock to jestem zielony. Jeśli zachowuje się on inaczej niż sockety POSIXowe, to będę pewnie plótł bzdury i można zignorować ten wpis

Funkcji recv() wisi i powiewa co jest w danych które otrzymuje. Dla niej '\r\n' nie jest żadną informacją o strukturze danych. Sam musisz się zatroszczyć o odpowiedni podział na pakiety tego, co recv() odbierze. Tak, w jednym wywołaniu recv() możesz otrzymać więcej niż jedną linię (dane zakończone '\r\n'). Tak, w jednym wywołaniu recv() możesz otrzymać tylko część linii (brak '\r\n'). Tak, w jednym wywołaniu recv() możesz otrzymać conajmniej jedną pełną linię i część innej. Poczytaj o protokołach strumieniowych, TCP itp.

0

Racja, mialem mylne wyobrazenie pakietu...
@krwq dzieki za kod, ale moje rozwiazanie jest chyba prostsze. Jezeli zawiedzie to przejde do Twojej propozycji.

Wiec zakodzilem cos takiego:

 void serwer::odbierz(char buffer[512])
{
    //recv(sClient, buffer, DL_WIAD, 0);

    char c;
    int t=0;
    do
    {
        recv(sClient, &c, 1, 0);
        buffer[t]=c;
        t++;
    }
    while(c!='\n');

    buffer[t]=char(0);

  
}

Teraz faza testow, jak nie wysypie sie w godzinach szczytu bedzie super ;D. Dzieki za pomoc :)

0

to powinno działać, aczkolwiek możesz w pewnym momencie zacząć czuć, że to muli...
powinieneś jeszcze dodać jako ten ostatni parametr MSG_WAITALL,
sprawdzć czy funkcja zwróciła 1, jeśli nie to znaczy że wystąpił błąd lub połączenie zostało zamknięte

1 użytkowników online, w tym zalogowanych: 0, gości: 1