Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
Пример P2P клиента по UDP. Обсуждаем тонкости работы по UDP
|
|||
|---|---|---|---|
|
#18+
Делюсь своим творчеством, может кому-то поможет. В аттаче исходники для MSVC2008, думаю под линуксом тоже соберется, не тестил, но копипастил из проекта собирающегося в линуксе и по максимуму использовал стандартный Си: udp_dialog.h - заготовка для асинхронного обмена по UDP с приоритетом чтению входящих пакетов. Это основа на которой работает все ниже перечисленное. udpeer_server.cpp - простейший сервер для обмена адресами двух клиентов и для замера скорости передачи на сервер. udpeer.cpp - простейший клиент для p2p обмена. Два клиента обмениваются адресами через сервер и дальше шлют данные друг-другу напрямую. udp_speed.cpp - замер скорости отправки на сервер Понимаю что многие считают меня изобретателем велосипеда, когда уже есть libevent, boost::asio, ZMQ и т.д. и т.п. Перечисленные изучал, кое что с их использованием написал. В итоге пришел к выводу что лучше сделать самому с нуля, тем более что задача у меня достаточно простая: дать клиентам возможность в онлайне обмениваться короткими сообщениями и иногда пересылать файлы 10-200 кб, желательно напрямую, а не через сервер. И протокол UDP элементарный, чем удобен и понятен: либо пришел пакет, либо не пришел, но весь пакет целиком, а не какой-то кусок TCP-потока. Хочу услышать критику по основе всего обмена (в сервере и клиенте). Большого опыта разработки на Си нет, поэтому мог и накосячить по незнанию. udp_dialog.h Код: 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. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. Принцип работы вкратце следующий: чтобы не потерять ничего входящего, создается массив буферов, куда все входящие пакеты сохраняются. Когда читать нечего запускается парсер принятого, когда парсить нечего запускается опрос того что надо отправить. На мегауниверсальность не претендую, все родилось из моей задачи, где надо: 1. ответить коротким сообщением на короткое сообщение 2. послать файл Соответственно в первом случае при разборе сообщения (parse_udp_message()) в тот же буфер который парсится пишется ответ и возвращается размер, при необходимости можно сменить получателя, по дефолту уйдет тому кто прислал. Во втором случае (send_udp_message()) дается буфер, который наполняется данными и задается получатель. Получилась схема изолирующая транспорт от данных. Вся работа с сокетом собрана в udp_dialog.h, а в коде его использующем только обработка и подготовка данных. Пример: udp_speed.cpp Код: 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. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. Не три строчки, но в асинхронных приложениях всегда мозг взрывается. Нерешенные вопросы: 1. Какой взять максимальный размер пакета? Максимальный размер 65507 байт, больше не отправится, по некоторым инет-каналам доходит нормально, но не по всем. Из тестов размера (просто слал разными каналами разного размера пакеты и смотрел сколько теряется) пришел к размеру 1372 байта - это максимум для L2TP с MTU 1400. Делаешь 1373 и больше половины пакетов теряется. Другие тесты показывают что уменьшение размера пакета никакой пользы не дает, там где проходит 90 из 100 пакетов по 1024 байта, с той же скоростью так же проходит 90 из 100 по 10 байт. Т.е. важен предел размера, а не размер как таковой. 2. Каким алгоритмом контроля потерь слать? Как выше написал, наблюдаю прямую зависимость потерь от скорости отправки и независимую от размера (пакеты по 10 и 1000 байт теряются одинаково). По предварительным тестам получается что слать надо с частотой половина времени отклика получателя (послать одиночное сообщение получателю, получить ответ). Т.е. пока планируемая стратегия отправки такова: замер времени по запросу-ответу, а дальше один пакет в половину этого времени, получатель периодически сообщает о потерях, на основании чего скорость уменьшается или увеличивается (если потерь нет). Как показала практика отклик одного и того же узла меняется на порядок от 2 мс до 28 мс. Это полноценный проводной инет, что будет с GSM-модемами еще не тестил. Классическая стратегия окон тоже не подходит, т.к. при быстрой отправке даже 10 пакетов половина может потеряться. PS Много букав получилось :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 16.03.2014, 20:14 |
|
||
|
Пример P2P клиента по UDP. Обсуждаем тонкости работы по UDP
|
|||
|---|---|---|---|
|
#18+
В udp_dialog.h есть глобальный косяк: забыл сбросить флаг пустой очереди, в результате она теряет все что принимает и не успевает обработать. надо вставить эту строчку в udp_dialog.h Код: plaintext 1. 2. 3. 4. 5. 6. В целом самодельная очередь оказалась слабоедущим велосипедом, поэтому лучше заменить ее на простое увеличение буфера ОС. udp_dialog.h Версия 2.0просто замените код udp_dialog.h на этот Код: 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. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. и еще один маленький баг в udpeer_server.cpp Код: plaintext 1. 2. 3. 4. заменить на Код: plaintext 1. Все исходники с исправлениями в архиве ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2014, 19:43 |
|
||
|
|

start [/forum/topic.php?fid=57&gotonew=1&tid=2019606]: |
0ms |
get settings: |
7ms |
get forum list: |
14ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
56ms |
get topic data: |
8ms |
get first new msg: |
6ms |
get forum data: |
2ms |
get page messages: |
77ms |
get tp. blocked users: |
1ms |
| others: | 293ms |
| total: | 470ms |

| 0 / 0 |
