Страницы

Поиск по вопросам

Показаны сообщения с ярлыком сетевое-программирование. Показать все сообщения
Показаны сообщения с ярлыком сетевое-программирование. Показать все сообщения

понедельник, 30 марта 2020 г.

Как в TCP определить, что кабель отключен?

#tcp #передача_данных #сетевое_программирование


При работе сетевого приложения сервер-клиент может произойти обрыв кабеля или его
вытащат на клиенте. TCP протокол никак не реагирует на это событие, иногда даже ОС
не сразу показывает, что кабель отключен. 
Мое приложение работает почти в реальном времени и пользователь должен знать, что
соединение прервалось.

Как в приложении определить, что канал связи перестал работать?
    


Ответы

Ответ 1



Протокол TCP по модели OSI отделен от физической среды передачи, потому ему не нужно знать, что там произошло. Не поможет просто периодически записывать пустой пакет в сокет, операция send просто копирует данные в буфер ОС, а ОС сама их уже отправляет. При этом если с первого раза не дошло TCP отправляет еще несколько раз (до 15), в итоге о том что отправка не удалась вы узнаете через 5 минут или чуть раньше. Я решил этот вопрос на уровне протокола приложения. Эти решения предназначены только для обработки случая с потерей связи на физическом уровне. Вариант 1 "Клиент-маяк" Это случай, когда клиенту не важно работает сервер или нет, и установкой соединения управляет сервер. Сервер сам подключает своих клиентов и решает, когда разорвать соединение. Проверка реализована на стороне сервера. На сервере: Подключиться к клиенту. Принять сообщение "пакет жизни" или другое сообщение от клиента. Установить время для таймера ожидания следующего сообщения 4 сек. Проверять истекло ли время ожидания или пришло сообщение. 4.1. Если Время истекло, то разорвать соединение с клиентом принудительно (считаем нет связи). 4.2. Если пришло сообщение, то шаг 3. На клиенте: Установить соединение к серверу. Отправлять "пакеты жизни" каждые 2 сек без ожидания ответа. Вариант 2 "Взаимный активный контроль" Если нужно оперативно реагировать на отсутствие связи и это два равноправных узла взаимодействующие по каналу связи, например видеозвонок между абонентами. В этом случае каждый из участников выполняет мониторинг состояния соединения самостоятельно. Используется активный периодический опрос. На каждой стороне: Установить соединение с ответной стороной. Отправить запрос PING, установить время ожидания для таймера ответа 4 сек. Проверять наличие ответа и окончание времени ожидания ответа. 3.1 Если пришел ответ PONG или сообщение, то сбросить таймер ожидания ответа, затем подождав 2 сек выполнить шаг 2. 3.2 Если время истекло, то разорвать соединение принудительно (считаем нет связи). Второй участник выполняет мониторинг таким же образом. Вариант 3 (упрощенный вариант 2, активный контроль) Если один из участников сервер и все клиенты подключаются к нему. Протокол приложения должен поддерживать модель "запрос-ответ". В этом случае только клиенты всегда подключаются к серверу. На клиенте: Подключиться к серверу. Выполнить запрос PING, установить время ожидания для таймера ответа 4 сек. Проверять наличие ответа и окончание времени ожидания ответа. 3.1. Если Время истекло, то разорвать соединение принудительно (считаем нет связи). 3.2. Если пришло сообщение, то подождать 2 сек, затем шаг 3. На сервере: Принять соединение клиента. Ожидать 4 сек получения запросов от клиента. Если запрос получен, то шаг 2. Если время ожидания вышло, то разорвать соединение принудительно (считаем нет связи).

понедельник, 6 января 2020 г.

Объединения (пример из сетевого программирования)

#c #объединение #сетевое_программирование


Я, видимо, не совсем понимаю, как работают union в Си, поэтому просьба прокомментировать
мои вопросы по следующему небольшому коду. (Чтобы сократить код, приведу только функцию
main())

int main(void)
{
    int sockfd; 
    socklen_t size = 2000;

    union {
       struct sockaddr sa;
       char mas[2000];
    }un;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    getsockname(sockfd, (struct sockaddr*)un.mas,&size);
    printf("%d\n\n", un.sa.sa_family);


    return 0;
}


1) Я ведь даже не заполняю структуру struct sockaddr sa, почему printf() печатает
правильный ответ?

2) Если я вместо union напишу struct, то ответ будет неправильный.

3) Если переменные не будут находиться в union или struct, то вылезает предупреждение
sa.sa_family’ is used uninitialized in this function. 

Помогите, пожалуйста, разобраться
    


Ответы

Ответ 1



Неудобный пример. Представьте что у вас есть юнион: typedef union { struct { int value; // 4 байта }; struct { char a; // 1 байт char b; // 1 байт char c; // 1 байт char d; // 1 байт }; } Test; Первое поле - int - объединяет в себе последующие char поля. В этом концепция union-ов. Вот трейс: Test test; test.value = 0; // value = { 00000000 00000000 00000000 00000000 } test.a = 1; // value = { 00000000 00000000 00000000 00000001 } test.b = 2; // value = { 00000000 00000000 00000010 00000001 } test.c = 3; // value = { 00000000 00000011 00000010 00000001 } test.d = 4; // value = { 00000100 00000011 00000010 00000001 } Видно, что меняя одно из мелких char полей меняется и большое int поле с именем value. По сути, наш union - это int число, но, для удобства, мы разделили это число на 4 байта a,b,c,d. Можем работать как со всеми 4 байтами сразу - value, так и с каждым отдельным байтом - a,b,c,d. В вашем случае всё аналогично. Есть struct sockaddr sa, далее, его представляют как массив из char длинной в 2000 байт. 1.) Заполняете. getsockname(sockfd, (struct sockaddr*)un.mas,&size); // передаёте указатель на начало массива char.Данные пишутся туда, как видно из моего примера с int числом, заполняя a,b,c,d мы меняем value. Здесь так же. Заполняя массив, мы меняем sa. 2.) И это логично, структура - это структура, юнион - это юнион. Не путайте их. 3.) Неужели даже так не получается? struct sockaddr sa; sockfd = socket(AF_INET, SOCK_STREAM, 0); getsockname(sockfd, (struct sockaddr*)&sa,&size); printf("%d\n\n", sa.sa_family);

пятница, 8 февраля 2019 г.

Объединения (пример из сетевого программирования)

Я, видимо, не совсем понимаю, как работают union в Си, поэтому просьба прокомментировать мои вопросы по следующему небольшому коду. (Чтобы сократить код, приведу только функцию main())
int main(void) { int sockfd; socklen_t size = 2000;
union { struct sockaddr sa; char mas[2000]; }un;
sockfd = socket(AF_INET, SOCK_STREAM, 0); getsockname(sockfd, (struct sockaddr*)un.mas,&size); printf("%d

", un.sa.sa_family);
return 0; }
1) Я ведь даже не заполняю структуру struct sockaddr sa, почему printf() печатает правильный ответ?
2) Если я вместо union напишу struct, то ответ будет неправильный.
3) Если переменные не будут находиться в union или struct, то вылезает предупреждение sa.sa_family’ is used uninitialized in this function.
Помогите, пожалуйста, разобраться


Ответ

Неудобный пример. Представьте что у вас есть юнион:
typedef union { struct { int value; // 4 байта }; struct { char a; // 1 байт char b; // 1 байт char c; // 1 байт char d; // 1 байт }; } Test;
Первое поле - int - объединяет в себе последующие char поля. В этом концепция union-ов. Вот трейс:
Test test; test.value = 0; // value = { 00000000 00000000 00000000 00000000 } test.a = 1; // value = { 00000000 00000000 00000000 00000001 } test.b = 2; // value = { 00000000 00000000 00000010 00000001 } test.c = 3; // value = { 00000000 00000011 00000010 00000001 } test.d = 4; // value = { 00000100 00000011 00000010 00000001 }
Видно, что меняя одно из мелких char полей меняется и большое int поле с именем value. По сути, наш union - это int число, но, для удобства, мы разделили это число на 4 байта a,b,c,d. Можем работать как со всеми 4 байтами сразу - value, так и с каждым отдельным байтом - a,b,c,d.
В вашем случае всё аналогично. Есть struct sockaddr sa, далее, его представляют как массив из char длинной в 2000 байт.
1.) Заполняете.
getsockname(sockfd, (struct sockaddr*)un.mas,&size); // передаёте указатель на начало массива char.Данные пишутся туда, как видно из моего примера с int числом, заполняя a,b,c,d мы меняем value. Здесь так же. Заполняя массив, мы меняем sa.
2.) И это логично, структура - это структура, юнион - это юнион. Не путайте их.
3.) Неужели даже так не получается?
struct sockaddr sa; sockfd = socket(AF_INET, SOCK_STREAM, 0); getsockname(sockfd, (struct sockaddr*)&sa,&size); printf("%d

", sa.sa_family);