Модераторы: xvr

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> socket tcp/ip клиент, теряются данные.... 
:(
    Опции темы
admsasha
Дата 31.5.2005, 12:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 28.1.2005

Репутация: 1
Всего: 6



Код

int main() {
    struct sockaddr_in addr;
    int sock;
    char buf[1024];

    addr.sin_family=AF_INET;
    addr.sin_port=htons(9205);
    addr.sin_addr.s_addr=inet_addr("xxx.xxx.xxx.xxx");
    sock=socket(PF_INET,SOCK_STREAM,0);
    connect(sock,(sockaddr *)&addr,sizeof(addr));

    while(read(sock,buf,1024)){
        printf("%s \n",buf);
        sleep(5);
    }

    close(sock);
    return 0;
}


создаю подлючение, всё хорошо, но, если сервер отдает данные во время sleep то данные, теряются, как этого избежать ?
PM MAIL WWW ICQ Jabber   Вверх
Mayk
Дата 31.5.2005, 13:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 5
Всего: 134



Использовать select? Типа того:
Код

while(isConnectionEstablished){
    fd_set fd;
    struct timeval to; //time out
    to.tv_sec = 5, to.tv_usec = 0;
    FD_ZERO(&fd);
    FD_SET(sock, &fd);
    if(select(sock+1, &fd, NULL, NULL, &to)){
        if(recv(sock, buf, 1024, 0) <= 0)
             break; // или isConnectionEstablished=0;
        else
            //сделать что-то страшное с полученными данными
    }
}


PS. Странно, у меня клиент нормально работал и с sleep+read. Правда сервер передает 5 байт каждую секунду, а клиент делает sleep(5). Но все равно - select рулит

Это сообщение отредактировал(а) Mayk - 31.5.2005, 13:48


--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
GrayCardinal
Дата 2.6.2005, 08:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 8
Всего: 58



admsasha
Ничего не понимаю. Нафиг sleep в твоем коде. ? Я так понимаю (и если не ошибаюсь, давно серваки не писал smile) что тама блокировка на вызове read до получения каких-либо данных. Вообще select надо пользовать как выше Mayk сказал или poll

Да и так делать printf нельзя. Что будет если получишь 1024 "N" ?
Цитата
отдает данные во время sleep то данные, теряются

Это как ? smile вроде не должны...
Добавлено @ 08:02
ЗЫ
ИМХО,
char buf[1024]
убери с глаз на... лучше не привыкать так делать...

Это сообщение отредактировал(а) GrayCardinal - 2.6.2005, 08:03


--------------------
PM MAIL WWW   Вверх
admsasha
Дата 2.6.2005, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 28.1.2005

Репутация: 1
Всего: 6



Цитата(GrayCardinal @ 2.6.2005, 08:00)
Да и так делать printf нельзя. Что будет если получишь 1024 "N" ?

я привел самый простой пример, что бы показать код, а не 1000 строк моего истинного кода

кстате, как делать проверку на переполнения буфера ?, и как правильно писать, вместо "printf" ?



Цитата(GrayCardinal @ 2.6.2005, 08:00)
char buf[1024]
убери с глаз на... лучше не привыкать так делать...

а как правильно ?



Цитата(GrayCardinal @ 2.6.2005, 08:00)
Это как ?  вроде не должны...

это значит что если данные посылаю во вреся sleep то нечего в buf не появляется...., а sleep`ом я эмитировал долгую работу.... типа отрабатываются данные 5 секунд...
PM MAIL WWW ICQ Jabber   Вверх
Mayk
Дата 2.6.2005, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 5
Всего: 134



Если данные долго обрабытываются, то
1) здравствуйте, потоки(см. в сторону pthread_create)
2) здравствуй, вилка(см. fork)

Цитата(admsasha @ 2.6.2005, 12:46)
кстате, как делать проверку на переполнения буфера ?, и как правильно писать, вместо "printf" ?

да хотя бы
char buf[1025];
buf[1024]=0;
printf("%s\n",buf);



Только вот вопрос - а ты уверен, что тебе придут 1024 байт? А не два пакета по 512 байт?
У тебя это где нибудь обрабатывается?


ЗЫ. GrayCardinal, чем вызвана твоя нелюбовь к стеку?

Это сообщение отредактировал(а) Mayk - 2.6.2005, 13:34


--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
admsasha
Дата 2.6.2005, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 28.1.2005

Репутация: 1
Всего: 6



Цитата(Mayk @ 2.6.2005, 20:32)
char buf[1025];
buf[1024]=0;
printf("%s\n",buf);


так получается что переполнение будет при 1025 ??


Цитата(Mayk @ 2.6.2005, 20:32)
1) здравствуйте, потоки(см. в сторону pthread_create)
2) здравствуй, вилка(см. fork)

вот распалерирования мне как раз не надо... только пошаговые действия


Цитата(Mayk @ 2.6.2005, 20:32)
Только вот вопрос - а ты уверен, что тебе придут 1024 байт? А не два пакета по 512 байт?

нет не уверен, и так часто бывает, но это обрабатываю.... точнее обхожу неправильным путем....
PM MAIL WWW ICQ Jabber   Вверх
Mayk
Дата 2.6.2005, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 5
Всего: 134



Цитата(admsasha @ 2.6.2005, 14:29)
так получается что  переполнение будет при 1025 ??

Ничуть, если мы будем recv'ить по 1024 байта:
buf[0...1023]: пришедшие байты
buf[1024]: нуль
В итоге printf() скорее завершится даже если тебе придет 1024 букв 'N'.
Цитата(admsasha @ 2.6.2005, 14:29)
вот распалерирования мне как раз не надо... только пошаговые действия

Ну так пускай тогда вторая сторона ждет пока первая сторона не скажет "готово, данные обработаны".

Цитата(admsasha @ 2.6.2005, 14:29)

нет не уверен, и так часто бывает, но это обрабатываю.... точнее обхожу неправильным путем....

Кроме очевидных решений, можно посмотреть в сторону опций сокетов: SO_RCVLOWAT - минимальное кол-во данных в приемном буфере сокете, при наличии который функция select скажет "сокет готов для чтения", а функция read вообще вернется(она заблокируется пока трубеумое кол-во не придет).
По умолчанию SO_RCVLOWAT равен 1.
Разумеется стоит посмотреть, чтобы размер приемного буфера(опция SO_RECVBUF) вмещал требуемое кол-во данных. Только вот - SO_RECVBUF следует устанавливать ДО коннекта, а SO_RCVLOWAT когда хошь.
Этакий "T/TCP - TCP для транзацкций - своими руками" smile

Это сообщение отредактировал(а) Mayk - 2.6.2005, 15:46


--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
admsasha
Дата 2.6.2005, 18:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 28.1.2005

Репутация: 1
Всего: 6



Mayk
можно полный пример ?
Не могу найти в инете про select....
PM MAIL WWW ICQ Jabber   Вверх
Mayk
Дата 2.6.2005, 19:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


^аВаТаР^ сообщение>>
****


Профиль
Группа: Участник
Сообщений: 2616
Регистрация: 22.5.2005
Где: за границей разум а

Репутация: 5
Всего: 134



Хмм, "$ man select". А вообще google
молодец(хоть и на msdn отсылает все время) - вот здесь в кратце описан select и не только.

А пример можно:
Код

#include <stdio.h>      //for printf
#include <sys/socket.h> //for socket,recv, so on
#include <netinet/in.h> //for sockaddr_in
#include <string.h>     //for memset
#include <arpa/inet.h>  //for inet_aton

int main(int argc, char** argv)
{
        int sock = socket(PF_INET, SOCK_STREAM ,0);
        struct sockaddr_in addr;
        char buf[1025];
        int i;
        
        memset( &addr,0,sizeof( addr ) );
        addr.sin_family = AF_INET;
        addr.sin_port = htons(12346);
        inet_aton("127.0.0.1", &addr.sin_addr);
        if(connect(sock, (struct sockaddr*) &addr,sizeof(addr)) < 0)
                return -1;
        while(1){
                fd_set fd;
                struct timeval to; //time out
                to.tv_sec = 5, to.tv_usec = 0;
                FD_ZERO(&fd);
                FD_SET(sock, &fd);
                if(select(sock+1, &fd, NULL, NULL, &to)){
                        if((i=recv(sock, buf, 1024, 0)) <= 0)
                                break;
                        buf[i]=0;
                        printf("%s\n", buf);
                }
        }
}


Вот это вот работает.





--------------------
 Здесь был кролик. Но его убили.
Человеки < кроликов, йа считаю.
PM MAIL WWW ICQ   Вверх
admsasha
Дата 3.6.2005, 04:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 28.1.2005

Репутация: 1
Всего: 6



Цитата(Mayk @ 3.6.2005, 02:46)
Хмм, "$ man select".

не думал что man есть на команды C++ smile



Цитата(Mayk @ 3.6.2005, 02:46)
Вот это вот работает.

у меня тоже работает... но при sleep все равно такой же эффект smile


вот вставь в цикл sleep(5), и шли данные 1,2,3,4,5,6,7,8.... 1000.... и увидешь потерю...
PM MAIL WWW ICQ Jabber   Вверх
GrayCardinal
Дата 3.6.2005, 05:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 8
Всего: 58



Цитата
ЗЫ. GrayCardinal, чем вызвана твоя нелюбовь к стеку

Ничем не вызвана. Просто добрый совет был smile Если у человека будет в каждой функции char buf[1024]... smile
Можно и так, конечно НО лучше бы

Код


char m_buf[1024];
char lp_buf[1024]
char lpsz_buf[1024];

А вообще вот так :
char * m_buf = new char[1024];
bzero (m_buf, 1024);

...

delete [] m_buf;

Цитата
а не 1000 строк моего истинного кода

Извини конечно, но по моему после таких вопросов... Всю тыщу надо будет переписывать smile

Цитата
.... и увидешь потерю

задолбал smile "fflush (stdout)" после "printf" ставить не пробовал ? Еще мне не хватало думать что по TCP есть потеря данных ... и так башка болит smile




--------------------
PM MAIL WWW   Вверх
admsasha
Дата 3.6.2005, 05:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 28.1.2005

Репутация: 1
Всего: 6



Цитата(GrayCardinal @ 3.6.2005, 12:24)
Извини конечно, но по моему после таких вопросов... Всю тыщу надо будет переписывать

не спорю, я только учусь smile


Цитата(GrayCardinal @ 3.6.2005, 12:24)
мне не хватало думать что по TCP есть потеря данных ...

не по TCP, а от неправильного кода...

Цитата(GrayCardinal @ 3.6.2005, 12:24)
"fflush (stdout)" после "printf" ставить не пробовал ?

незнаю что уж она делает, но не помогает...


PM MAIL WWW ICQ Jabber   Вверх
GrayCardinal
Дата 3.6.2005, 06:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Фигасе
****


Профиль
Группа: Завсегдатай
Сообщений: 3039
Регистрация: 9.11.2003

Репутация: 8
Всего: 58



Шоб тебя. Можно "не рабочий" сервак и "не рабочий клиент" в студию ?! или хотябы мне [email protected]


--------------------
PM MAIL WWW   Вверх
admsasha
Дата 3.6.2005, 08:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 28.1.2005

Репутация: 1
Всего: 6



всё, кажется сам разобрался, когда упрощал код, для показа... ну жалко мне исходники показывать smile всё же проект игрухи smile

вот тут ошибка и получалась.
Код

        while(1){
            sprintf(tmpstring,"%i",n);
            write(newsockfd, tmpstring,strlen(tmpstring)+1);
            n++;
            sleep(1);
        }




клиент использовал этот
Код

int main(int argc, char** argv){

    int sock = socket(PF_INET, SOCK_STREAM ,0);
    struct sockaddr_in addr;
    char buf[1025];
    int i;

    memset( &addr,0,sizeof( addr ) );
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9200);
    inet_aton("127.0.0.1", &addr.sin_addr);
    if(connect(sock, (struct sockaddr*) &addr,sizeof(addr)) < 0) return -1;
    while(1){
        fd_set fd;
        struct timeval to; //time out
        to.tv_sec = 5, to.tv_usec = 0;
        FD_ZERO(&fd);
        FD_SET(sock, &fd);
        if(select(sock+1, &fd, NULL, NULL, &to)){
            if((i=recv(sock, buf, 1024, 0)) <= 0){
                break;
            }
            buf[i]=0;
            printf("%s\n", buf);
            sleep(3);
        }
    }
}



сервер:
Код

int main(){
    int sockfd, newsockfd; /* Дескрипторы для слушающего и присоединенного сокет
    socklen_t clilen; /* Длина адреса клиента */
    int n;
    char tmpstring[200];
    struct sockaddr_in servaddr, cliaddr;

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        perror(NULL);
        exit(1);
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family= AF_INET;
    servaddr.sin_port= htons(9200);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(sockfd, (struct sockaddr *) &servaddr,sizeof(servaddr)) < 0){
        perror(NULL);
        close(sockfd);
        exit(1);
    }
    if(listen(sockfd, 5) < 0){
        perror(NULL);
    }
    while(1){
        clilen = sizeof(cliaddr);
        newsockfd = accept(sockfd,(struct sockaddr *) &cliaddr, &clilen);
        if (newsockfd <0){
            perror(NULL);
            close(sockfd);
            exit(1);

        }
        while(1){
            sprintf(tmpstring,"%i",n);
            write(newsockfd, tmpstring,strlen(tmpstring)+1);
            n++;
            sleep(1);
        }

    }
    return 0;
}

Добавлено @ 08:58
Цитата(Mayk @ 2.6.2005, 20:32)
Только вот вопрос - а ты уверен, что тебе придут 1024 байт? А не два пакета по 512 байт?


как сделать один, если не известна длина ?
PM MAIL WWW ICQ Jabber   Вверх
admsasha
Дата 3.6.2005, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 763
Регистрация: 28.1.2005

Репутация: 1
Всего: 6



Цитата(Mayk @ 2.6.2005, 22:44)
Кроме очевидных решений, можно посмотреть в сторону опций сокетов: SO_RCVLOWAT

Цитата
      SO_RCVLOWAT и SO_SNDLOWAT
              Указать  минимальное количество байтов в буфере при
              приеме до  того,  как  сокет  определенного  уровня
              передаст  данные  протоколу  (SO_SNDLOWAT)  или
              пользователю  (SO_RCVLOWAT).  Эти  два  значения
              невозможно  изменить в Linux, и размер их аргумента
              фиксирован: он составляет 1 байт.  getsockopt может
              считывать  их.  setsockopt всегда будет возвращать
              значение ENOPROTOOPT.


Как я понял менять значения нельзя ?
PM MAIL WWW ICQ Jabber   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.0604 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.