Стан перегонів для мережевих даних із пекла
Я писав мережевий клієнт / сервер (Windows XP / C #) для роботи з аналогічним додатком на дійсно старій (Encore 32/77) робочій станції, написаній іншим розробником.
Програма, по суті, полягала в тому, щоб поділитися / маніпулювати певними даними на хості, щоб керувати хост-процесом під керуванням системи за допомогою нашого вишуканого інтерфейсу з сенсорним екраном мультимоніторного ПК на базі ПК.
Це було зроблено за допомогою тришарової структури. Процес комунікації читав / записував дані в / з хоста, робив усі необхідні перетворення формату (нестабільність, формат з плаваючою точкою тощо) і записував / читав значення в / з бази даних. База даних виступала посередником даних між комунікаційними пристроями та інтерфейсами сенсорного екрану. Додаток інтерфейсу інтерфейсу сенсорного екрану генерував інтерфейси сенсорного екрану, залежно від кількості моніторів, прикріплених до ПК (це автоматично виявляло це).
У часові рамки, надіслані пакетом значень між хостом і нашим ПК, можна було надсилати лише 128 значень максимум по дроту за один раз з максимальною затримкою ~ 110 мс за турецьку поїздку (UDP використовувався з прямим ефірним з'єднанням x-over між комп’ютери). Отже, кількість змінних, дозволених на основі змінної кількості прикріплених сенсорних екранів, перебувала під суворим контролем. Крім того, хост (хоча маючи досить складну багатопроцесорну архітектуру із спільною шиною пам'яті, використовуваною для обчислень у режимі реального часу) мав приблизно 1/100-ту потужність обробки мого мобільного телефону, тому йому було поставлено завдання зробити якомога менше обробку, і це сервер / клієнт повинен був бути написаний на зборах, щоб переконатися в цьому (хост виконував повне моделювання в режимі реального часу, на яке наша програма не могла вплинути).
Питання було. Деякі значення при зміні на сенсорному екрані не прийматимуть лише щойно введене значення, а циклично змінюються між цим значенням та попереднім значенням. Це і лише на кількох конкретних значеннях на декількох конкретних сторінках із певною комбінацією сторінок коли-небудь проявлявся симптом. Ми майже повністю пропустили проблему, поки не почали її запускати через початковий процес прийняття клієнта
Для усунення проблеми я вибрав одне з коливальних значень:
- Я перевірив додаток сенсорного екрану, він коливався
- Я перевірив базу даних, коливаючись
- Я перевірив додаток comms, коливаючись
Тоді я вирвав проводку і почав вручну розшифровувати захоплення пакетів. Результат:
- Не коливалося, але пакети не виглядали правильно, було занадто багато даних.
Я сто разів переглянув кожну деталь кодового коду, не виявивши жодних недоліків / помилок.
Нарешті я почав відсилати електронні листи до іншого розробника, докладно розпитуючи, як працює його кінець, щоб побачити, чи щось мені не вистачає. Потім я його знайшов.
Мабуть, коли він надсилав дані, він не змивав масив даних перед передачею, так що, по суті, він просто перезаписував останній буфер, який використовували нові значення, перезаписуючи старі, але старі значення, які не перезаписані, все ще передаються.
Отже, якби значення було в положенні 80 масиву даних, а список запитуваних значень змінювався на менше 80, але це ж значення містилося в новому списку, то обидва значення існували б у буфері даних для цього конкретного буфера в будь-якому заданий час.
Значення, яке зчитується з бази даних, залежало від відрізка часу, коли інтерфейс запитував це значення.
Виправлення було болісно простим. Читайте кількість елементів, що надходять у буфер даних (він фактично містився як частина протоколу пакетів) і не читайте буфер, що перевищує цю кількість елементів.
Уроки:
Не сприймайте сучасні обчислювальні потужності як належне. Був час, коли комп’ютери не підтримували Ethernet і коли промивання масиву можна вважати дорогим. Якщо ви дійсно хочете побачити, як далеко ми зайшли, уявіть систему, яка практично не має форми динамічного розподілу пам'яті. Тобто, виконавчий процес повинен був заздалегідь виділити всю пам'ять для всіх програм для того, щоб жодна програма не змогла вирости за межі цієї межі. IE, виділення програми більше пам'яті без перекомпіляції всієї системи може призвести до масового збою. Цікаво, чи люди поговорять про дні перед вивезенням сміття в одному світлі колись.
Працюючи в мережі з користувацькими протоколами (або взагалі в режимі подання бінарних даних), переконайтеся, що ви прочитали специфікацію, доки не зрозумієте кожну функцію кожного значення, що надсилається через трубу. Я маю на увазі, читайте, поки не болять очі. Люди обробляють дані, маніпулюючи окремими бітами або байтами, мають дуже розумні та ефективні способи вчинити. Відсутність найдрібнішої деталі може зламати систему.
Загальний час на виправлення становив 2-3 дні, більшу частину цього часу витрачав на роботу над іншими речами, коли я розчарувався в цьому.
SideNote: Провідний комп'ютер за замовчуванням не підтримував Ethernet. Картка для заїзду була виготовлена на замовлення та модернізована, а стек протоколів практично не існував. Розробник, з яким я працював, був одним пеклом програміста, він не тільки реалізував зняту версію UDP та мімімальну підроблену стек Ethernet (процесор не був достатньо потужним, щоб обробляти повний стек Ethernet) для системи для цього проекту але він зробив це менше ніж за тиждень. Він також був одним із оригінальних керівників команд проекту, який розробив і запрограмував ОС в першу чергу. Скажемо, все, що він коли-небудь мав поділитися про комп’ютери / програмування / архітектуру, незалежно від того, як давно вийшло або скільки я вже нового, я слухав би кожне слово.