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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Непонятки с приемом у сокета, Получает несколько сообщений как одно 
:(
    Опции темы
Athlon
Дата 14.6.2006, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 15.1.2006
Где: Украина:: Запорож ье

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



Есть у меня две программы которые общаются строками через сокеты. Для этого создал два класса производных от CSocket и отправляю стороки с помощью Send(), а в OnReceive() принимаю. Вроде бы  проще некуда, но когда начал тестировать обнаружил интересный баг - клиент иногда принимает несколько строк как одну.
Что бы это могло быть и как с этим явлением бороться  smile  ????? 
PM MAIL ICQ   Вверх
Romikgy
Дата 14.6.2006, 13:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: нет
Всего: 146



Имхо буфер сокета набирает данные и когда он (буфер) переполняется он его выпихивает в сокет (в сеть) , в твоем случае делать принудительное выталкивание данных, что то типа как для файла flush или делать задержки между отправкой сенд (таймауты),
и второй вариант забить на все это, и вставлять в строке, символ конца строки (свой допустим "+") , а при выводе на экран заменять этот символ на перевод строки 


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
Athlon
Дата 14.6.2006, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 15.1.2006
Где: Украина:: Запорож ье

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



Romikgy, вариант с разделителем строки конечно интересный, но ты лучше подскажи как сделать
Цитата
 принудительное выталкивание данных
 
PM MAIL ICQ   Вверх
Romikgy
Дата 14.6.2006, 14:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: нет
Всего: 146



Цитата(Athlon @  14.6.2006,  11:38 Найти цитируемый пост)
CSocket

Чье это счастье , что за среда , VC? 
хелпнадо смотреть найду его подскажу чтото  


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
Athlon
Дата 17.6.2006, 16:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 15.1.2006
Где: Украина:: Запорож ье

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



После утомительных поисков нашел выход - отключить алгоритм Нейгла (который по возможности объединяет мелкие сообщения до размера сегмента). Отключаю его следующим способом:
Код

bool opt = true;
int res = s_sock[*index]->SetSockOpt(TCP_NODELAY, &opt, sizeof(bool), IPPROTO_TCP);
if(res == 0)
{
//обработка ошибки
}

Но все равно сообщения которые я отправляю клиенту в цикле, например так:
Код

while(log->not_empty())
{
    CString* comment = log->get_head();
    comment->Insert(0,"c");
    s_sock[index]->Send(*comment, comment->GetLength());
    delete comment;
}

все также с приходят то по отдельности то вместе. Может есть еще вариант заставить сокет отправлять сообщения немедленно или я что-то делаю неправильно?

P.S. Romikgy, речь идет о CSocket из MFC, а среда разработки MS VC 6.0  
PM MAIL ICQ   Вверх
Romikgy
Дата 19.6.2006, 14:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: нет
Всего: 146



Можно еще посоветовать
SO_SNDBUF    поставить в 1
и с SO_SNDTIMEO    поигратся
Цитата(Athlon @  17.6.2006,  15:39 Найти цитируемый пост)
речь идет о CSocket из MFC, а среда разработки MS VC 6.0  

У меня этого нет так что ничего не подскажу, да и лично я не люблю VC и его MFC имхо тупой он.
+Имхо лучше сделать с разделителями строк!

да еще можешь попробывать ставить задержки
Цитата(Athlon @  17.6.2006,  15:39 Найти цитируемый пост)
s_sock[index]->Send(*comment, comment->GetLength());

после этого , допустим на 10 мсек, может поможет 


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
ptr
Дата 19.6.2006, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 661
Регистрация: 31.5.2006
Где: Новосибирск

Репутация: 9
Всего: 14



Athlon выложи код приёма, отправки сообщений. 


--------------------
Единственный способ определить границы возможного - это выйти за эти границы, в невозможное.
Артур Кларк.
PM MAIL ICQ   Вверх
Athlon
Дата 19.6.2006, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 15.1.2006
Где: Украина:: Запорож ье

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



Я в принципе уже решил вопрос вводом разделителя строки, и почитав умную книгу понял что это самый правильный способ (http://www.syt.edu.severodvinsk.ru/znai/megabook/internet/tcp-ip/gl3/gl3.html - совет 15). Но если интересно могу выложить.
Серверный сокет наследуется от CSocket и отправляет строковые сообщения функцией предка Send
Код

//s_sock[index] - указатель на сокет сервера
while(log->not_empty())    
{    
    CString* comment = log->get_head();    
    comment->Insert(0,"c");
    comment->Insert(comment->GetLength(), limiter);    
    s_sock[index]->Send(*comment, comment->GetLength());    
    delete comment;    
}

а клиент принимает сообщения в обработчике OnReceive - вот код клиентского сокета:
Код

class CClientDlg;

class CClientSocket : public CSocket  
{
protected:
    CClientDlg* pdlg;  //диалоговое окно используется для вывода
public:
    CClientSocket(CClientDlg* m_dlg);
    virtual ~CClientSocket();
    virtual void OnClose(int nErrorCode);
    virtual void OnReceive(int nErrorCode);
};

void CClientSocket::OnReceive(int nErrorCode) 
{
    char buffer[4096];
    int nRead = Receive(buffer,4096);
    if(nRead == SOCKET_ERROR)
    {
        AfxMessageBox("ClientSocket :: OnReceive ERROR !!!");
        return;
    }
    buffer[nRead] = '\0';
    CString message = buffer;
    while(message != "")
    {
        //отделяю префикс от сообщения
        char msg_type = message[0];        
        int index = message.Find(limiter);
        if(index == -1)
        {
            message = buffer;
            pdlg->receive_question(message);
            break;
        }
        CString fragment = message.Left(index);
        fragment.Delete(0, 1);
        message.Delete(0, index+1);
        switch(msg_type)
        {
            case 'l':
            {
                pdlg->show_base_list(fragment);
                break;
            }
            .......
            case 'c':
            {
                pdlg->receive_comment(fragment);
                break;
            }
            default:
            {
                pdlg->receive_question(fragment);
            }
        }
    }
    pdlg->scroll_list();
    CSocket::OnReceive(nErrorCode);
}

в начальной версии не было цикла while для разбивки на строки по разделителю.

P.S. Только не над лекций о том что нужно всеми правдами и неправдами избегать switch.  smile  
PM MAIL ICQ   Вверх
Romikgy
Дата 19.6.2006, 16:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: нет
Всего: 146



И че не работает так как надо ? 


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
Artemon
Дата 7.7.2006, 18:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


а ты мне нравишься
***


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

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



Чего следует избегать, так это посылки строк.
Самый надежный вариант посылать буфер.
 


--------------------
Контроль топлива на топливозаправщиках, мониторинг автотранспорта, расчет зарплаты водителей www.rscat.ru
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




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


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

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