Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Сокеты в си / 25 сообщений из 43, страница 1 из 2
26.10.2015, 09:41
    #39086404
t111к
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Добрый день.

У меня возник вопрос по сокетам в си. Как правильно написать, если сокет за один раз не сможет принять объём передаваемых данных
rc = recv(sock, &buf_lin2, BufferLength,0 ); наверно уже будет не совсем верно?
...
Рейтинг: 0 / 0
26.10.2015, 10:31
    #39086476
mayton
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Код: plaintext
1.
do{ rc=recv(....) } while(..)
...
Рейтинг: 0 / 0
26.10.2015, 10:33
    #39086479
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Проверять по содержимому все пришло или нет. Формат передачи должен предусматривать указание где конкретно расположены данные, т.к. TCP-соединение просто передает поток байт.
Например передаешь сначала размер блока данных, затем сами данные. При получении читаешь размер, затем данные, затем проверяешь все ли данные пришли или еще есть не принятые. Если есть непринятые - ждешь недостающее.
...
Рейтинг: 0 / 0
26.10.2015, 11:21
    #39086564
t111к
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Сделал так, но почему -то не работает первое чтение read отрабатывает а при 2 чтение вылетает из цикла не доходя даже до if(rc < 0)

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
  while(totalcnt < BufferLength)
                                                                	{
                                                                           rc = read(sock, &buf_lin2[totalcnt], (BufferLength - totalcnt));
                                                                   	   if(rc < 0)
                                                                           {
                                                                               perror("Server-read() error");
                                                                               if (flagpervogchten==0)
                                                                               flagoshib=2;
                                                                               break;
                                                                            }
                                                                           else if (rc == 0)
                                                                           {
                                                                        	   if (flagpervogchten==0)
                                                                        	   flagoshib=2;
                                                                               break;
                                                                           }
                                                                           else
                                                                           {
                                                                               totalcnt += rc;
                                                                               flagpervogchten=1;
                                                                               printf("Server-read() is OK\n");
                                                                           }
                                                                           }
                                                                          if (flagoshib==1)
                                                                           obrabwialonretr(buf_lin2, sock);



Да тут за раз всё передалось, но если не за раз как же здесь сделать?
...
Рейтинг: 0 / 0
26.10.2015, 11:43
    #39086609
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
t111кДобрый день.

У меня возник вопрос по сокетам в си. Как правильно написать, если сокет за один раз не сможет принять объём передаваемых данных
rc = recv(sock, &buf_lin2, BufferLength,0 ); наверно уже будет не совсем верно?

0)для начала нужно напомнить, что если сокет не udp, то он потоковый. в нем нет сообщений и блоков.

1) сокеты - это файлы, можно просто читать read ом. посимвольно, построчно. это кстати не будет медленнее.
2) если за один recv не получилось принять, можно еще раз вызвать recv.
...
Рейтинг: 0 / 0
26.10.2015, 11:47
    #39086616
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
t111кСделал так, но почему -то не работает первое чтение read отрабатывает а при 2 чтение вылетает из цикла не доходя даже до if(rc < 0)

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
  while(totalcnt < BufferLength)
                                                                	{
                                                                           rc = read(sock, &buf_lin2[totalcnt], (BufferLength - totalcnt));
                                                                   	   if(rc < 0)
                                                                           {
                                                                               perror("Server-read() error");
                                                                               if (flagpervogchten==0)
                                                                               flagoshib=2;
                                                                               break;
                                                                            }
                                                                           else if (rc == 0)
                                                                           {
                                                                        	   if (flagpervogchten==0)
                                                                        	   flagoshib=2;
                                                                               break;
                                                                           }
                                                                           else
                                                                           {
                                                                               totalcnt += rc;
                                                                               flagpervogchten=1;
                                                                               printf("Server-read() is OK\n");
                                                                           }
                                                                           }
                                                                          if (flagoshib==1)
                                                                           obrabwialonretr(buf_lin2, sock);



Да тут за раз всё передалось, но если не за раз как же здесь сделать?


если вылетает,то это наверное защита памяти, там ничто не может больше проводить к выходу из цикла.
...
Рейтинг: 0 / 0
26.10.2015, 11:56
    #39086626
t111к
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Так вот и непонятно что может быть, и ошибок не выдаёт то ведь просто выход происходит из цикла и процедуры
char buf_lin2[50000];
int BufferLength=50000;
Может как -то по другому написать? Есть правильнее запись этого безобразия?
...
Рейтинг: 0 / 0
26.10.2015, 12:02
    #39086631
t111к
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Нет я ошибся не выход происходит а в цикле while ждёт дальше прихода данных, я не знаю только сколько данных ко мне должно прийти, обычно приходит пакет, который может состоять и 204 байт или кратному быть этому размеру, и обычно вконце 204 байтом идёт символ
strokdan[203] char 64 '@'
strokdan[407] char 64 '@'
...
Рейтинг: 0 / 0
26.10.2015, 12:43
    #39086703
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
t111кНет я ошибся не выход происходит а в цикле while ждёт дальше прихода данных, я не знаю только сколько данных ко мне должно прийти, обычно приходит пакет, который может состоять и 204 байт или кратному быть этому размеру, и обычно вконце 204 байтом идёт символ
strokdan[203] char 64 '@'
strokdan[407] char 64 '@'

Ну я так и думал.
Но тут я ж говорю, тебе никто не поможет, ты должен сам понимать, когда и что ты должен получить.
Это в TCP определяется протоколами высшего уровня -- HTTP, POP3 и так далее.

Лучший выход -- не читать блоками, а читать посимвольно.
Если там не мегабаты данных, то на производительности не скажется.
Ну и можно сочетать -- знаешь, что должен получить большой блок данных -- читай большой блок (я бы читал всё же read-ом),
не знаешь -- читай посимвольно, построчно.
...
Рейтинг: 0 / 0
26.10.2015, 13:42
    #39086805
t111к
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Спасибо.
Попробую вот так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
if(read(sock, &ch, 1)<0) perror("read");
                                printf("Server-read() is OK\n");
                                while( ch != EOF) {
                                	buf_lin2[totalcnt]=ch;
                                	totalcnt++;
                                        if(read(sock, &ch, 1)<0) perror("read");
                                }
                                obrabwialonretr(buf_lin2, sock);
...
Рейтинг: 0 / 0
26.10.2015, 23:17
    #39087448
kolobok0
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
t111к,

Про потоковый подход - уже прозвучало. Обычно в обработчик TCP передают длину. И сам обработчик тупо читает необходимую длину.

Например передали заголовок фиксированной длины - в нём указана длина полезных данных следуемый за ним.

Либо читаете по символьно и как только пришла фраза "ЛЕНИН ЖИВ!!!" то понимаете что дальше у вас идут данные длиной в 1 мегабайт....

Ну и т.д..
(круглый)
...
Рейтинг: 0 / 0
27.10.2015, 07:42
    #39087537
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
t111кПопробую вот так:
...
Тут как минимум надо добавить проверки:
1. выхода за пределы buf_lin2
2. обрыва соединения
...
Рейтинг: 0 / 0
27.10.2015, 08:03
    #39087545
t111к
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Добрый день.
И как это всё учесть? Если можно на конкретном примере, который я привожу. Приведённое выше не подходит так как я получаю набор байтов среди которых может быть и 0. Потом во входящих данных передаются пакеты размер которых я знаю там в байтах их размер и обычно это 204 байта, но мне неизвестно сколько пакетов приходит по 204 байтов, проблема ещё в том, что не передаётся размер общих входящих данных или символы окончания приёма данных.
Пока остановился на таком, больше не знаю, что в данном случае можно ещё сделать. Да, тоже может попасть такой случай что будет кратно 204 и остаток от деления 0, но не всё передал.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
 flagoshib=1;
                               	flagpervogchten=0;
                               	totalcnt=0;
                                while(totalcnt < BufferLength)
                                {
                                  rc =  recv(sock, &buf_lin2[totalcnt], (BufferLength - totalcnt),0);
                                                                          if(rc < 0)
                                                                           {
                                                                               perror("Server-read() error");
                                                                               if (flagpervogchten==0)
                                                                               flagoshib=2;
                                                                               break;
                                                                           }
                                                                           else if (rc == 0)
                                                                           {
                                                                       	   if (flagpervogchten==0)
                                                                       	   flagoshib=2;
                                                                           break;
                                                                           }
                                                                           else
                                                                           {
                                                                           totalcnt += rc;
                                                                           flagpervogchten=1;
                                                                            printf("Server-read() is OK\n");
                                                                            int v1;
                                                                            v1=totalcnt%204;
                                                                            if (v1==0)
                                                                            break;
                                                                           }
                                                                           }
                                                                          if (flagoshib==1)
                                                                           obrabwialonretr(buf_lin2, sock);
...
Рейтинг: 0 / 0
27.10.2015, 08:41
    #39087553
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Может еще быть случай когда придет два сообщения вместе.
t111кво входящих данных передаются пакеты размер которых я знаю там в байтах их размер и обычно это 204 байта, но мне неизвестно сколько пакетов приходит по 204 байтов, проблема ещё в том, что не передаётся размер общих входящих данных или символы окончания приёма данных.
В такой постановке задача нерешаема.
Сформулируй и четко опиши формат передачи. Без слова "обычно", т.к. оно тут означает что иногда может прийти неожидаемый набор данных и все сглючит.

Если каждый пакет 204 байта, то читай в буфер размером 204 байта. Буфер наполнился - пакет получен, обрабатываем, ждем следующий.

PS Если есть возможность править код на второй стороне (которая отправляет), то меняй формат отправки. Например 4 байта размер данных, затем данные. Так будет намного проще.
...
Рейтинг: 0 / 0
27.10.2015, 09:35
    #39087618
t111к
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Будем ориентироваться, что всегда приходят 204. Только сколько таких пакетов по 204 байтов предаётся неизвестно. Я взял BufferLength=50000, с запасом, Менять передающую программу я не могу, не у нас она формируется это WialonRetranslator по этому протоколу к нам поступают данные. Часто приходят 1 пакет по 204 байт, бывает несколько пакетов по 204 байтов. Промежуток при пересылках данных большой, накапливать больше 50000 он может долго, лучше сразу бы обработать, как пришли данные.
А вот если так сделать. Будет ли этот кусочек программы правильно отрабатывать?
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
 char ch[1]="";
                                int prokon;
                                 totalcnt=0;
                                rc=read(sock, &ch, 1);
                                if (rc<=0)
                                	printf("Сервер не прочитал\n");
                                else
                                {
                                printf("Сервер прочитал\n");
                                prokon=ch[0];
                                while(prokon!= EOF)
                                {
                                       	buf_lin2[totalcnt]=ch[0];
                                	totalcnt++;
                                        rc=read(sock, &ch, 1);
                                	 prokon=ch[0];
                                	 if (rc<=0)
                                        break;
                                }
                                obrabwialonretr(buf_lin2, sock); 
...
Рейтинг: 0 / 0
27.10.2015, 10:06
    #39087655
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
t111кБудем ориентироваться, что всегда приходят 204. Только сколько таких пакетов по 204 байтов предаётся неизвестно. Я взял BufferLength=50000, с запасом
Зачем этот запас? Что мешает сделать BufferLength=204 ? Получил сообщение - сразу обработал. Жди следующее. Если оно уже есть, то сразу обработаешь, если нет, то код будет стоять на recv() пока не придет очередное или соединение не порвется.

Если ждать не надо, то c помощью select() можно проверить есть что читать из сокета или нет.
...
Рейтинг: 0 / 0
27.10.2015, 10:19
    #39087676
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Так попробуй
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
#define PACKET_SIZE 204

while(true) {
   int rc;
   char buf[PACKET_SIZE];
   int total = 0;
   while(total < PACKET_SIZE) {
       rc =  recv(sock, &buf[total], PACKET_SIZE - total,0);
       if(rc < 0) {
             perror("Server-read() error");
             break;
       }
   }
   if(rc < 0) break;
   printf("Server-read() is OK\n");
   obrabwialonretr(buf, sock);
}
...
Рейтинг: 0 / 0
27.10.2015, 10:25
    #39087685
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Dima T,

косяк - recv может вернуть 0 при закрытии сокета передающей стороной
...
Рейтинг: 0 / 0
27.10.2015, 10:33
    #39087700
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Точно, не силен в TCP, списал у t111к
тогда заменить на
Код: plaintext
1.
if(rc <= 0) ...


Если не путаю, при открытом соединении recv() никогда 0 не вернет, т.е. будет висеть и ждать данные, если с настройками сокета не баловаться.
...
Рейтинг: 0 / 0
27.10.2015, 12:49
    #39087897
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Dima TМожет еще быть случай когда придет два сообщения вместе.
t111кво входящих данных передаются пакеты размер которых я знаю там в байтах их размер и обычно это 204 байта, но мне неизвестно сколько пакетов приходит по 204 байтов, проблема ещё в том, что не передаётся размер общих входящих данных или символы окончания приёма данных.
В такой постановке задача нерешаема.
Сформулируй и четко опиши формат передачи. Без слова "обычно", т.к. оно тут означает что иногда может прийти неожидаемый набор данных и все сглючит.

Если каждый пакет 204 байта, то читай в буфер размером 204 байта. Буфер наполнился - пакет получен, обрабатываем, ждем следующий.

PS Если есть возможность править код на второй стороне (которая отправляет), то меняй формат отправки. Например 4 байта размер данных, затем данные. Так будет намного проще.

Я только ещё раз хочу напомнить, что никаких "сообщений" и "пакетов" в TCP нет. Приведённые тут эти слова -- это так, для обозначение посылок в общем смысле.
...
Рейтинг: 0 / 0
27.10.2015, 12:58
    #39087917
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
t111к,

Здесь ошибка:

Код: plaintext
1.
2.
3.
4.
5.
6.
char ch[1];
rc=read(sock, &ch, 1);
if (rc<=0)
  ; // ...
prokon=ch[0];
while(prokon!= EOF)



EOF - не уместится в char.
read никогда не формирует EOF. Это ты перепутал с getc
...
Рейтинг: 0 / 0
27.10.2015, 13:06
    #39087937
t111к
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Да нет я разместил EOF в int
int prokon;
...
prokon=ch[0];
while(prokon!= EOF)
...
Рейтинг: 0 / 0
27.10.2015, 13:12
    #39087944
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
t111кДа нет я разместил EOF в int
int prokon;
...
prokon=ch[0];
while(prokon!= EOF)

Ну до этого-то он должен появитсья как-то в ch[0] ...

К тому же на кой тебе фиг массив из заведомо одного элемента, не подскажешь ?
(ну это так, просто чтобы поржать).
...
Рейтинг: 0 / 0
27.10.2015, 13:12
    #39087945
t111к
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Да спасибо. Да действительно, если я только знаю сколько байт приходит в одном пакете первые 4 байта пакета (204 байт), попробую только по одному пакету принимать и обрабатывать. Пробую сейчас так, надеюсь правильно будет работать.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
 float d1;
                                    int chetbiet,nomerbite,nomzapbite, kolbite,r1blok1,i1,c,totalcnt ;
                                    char rasmbl1[4]="";
                                    while (1)
                                    {
                                    rc=recv(sock, &rasmbl1, 4,0);
                                    if (rc<=0)
                                    {
                                   printf("Сервер не прочитал\n");
                                    break;
                                    }
                                    kolbite=0;
                                    for (i1=0;i1<4;i1++ )
                                    {
                                    c=rasmbl1[i1];
                                    if (c<0)
                                    c=c+256;
                                    d1=Power(256,i1);
                                    kolbite=kolbite+c*d1;
                                    }
                                    memcpy(buf_lin2,rasmbl1,4);
                                    totalcnt=0;
                                    while(totalcnt < kolbite)
                                    {
                                    rc=recv(sock, &buf_lin2[4+totalcnt], kolbite - totalcnt,0);
                                    if (rc<=0)
                                    {
                                    printf("Сервер не прочитал\n");
                                    break;
                                    }
                                    totalcnt+=rc;
                                    }
                                    if (totalcnt== kolbite)
                                    obrabwialonretr(buf_lin2, sock);
...
Рейтинг: 0 / 0
27.10.2015, 13:20
    #39087955
t111к
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Сокеты в си
Да если передающая сторона будет отсылать EOF можно было бы его ловить, но наверно передающая сторона и не посылает его
rc=read(sock, &ch, 1);
prokon=ch[0];
Да можно наверно char ch; и вот объявить одно символьную переменную и обращаться к ней
prokon=ch;
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Сокеты в си / 25 сообщений из 43, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]