Страницы

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

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

суббота, 11 апреля 2020 г.

Ошибка при копировании больших объемов данных (Ubuntu)

#windows #ubuntu #кодировка #сеть

                    
Возникла такая проблема, копирую файлы с винды по локальной сети, около 1 млн файлов
весом в 200Гб (простым способом, наутилусом).
После того как скопировалось 411242 файлов 26,6Гб (это последняя попытка) система
зависает, и выдает какие-то кракозябры на черном экране, среди которых можно найти
sdb1 - это сам винт (4Тб HDD). Смонтирован он в /mnt/sdb1/, фс ext4. Почем так происходит?
Ведь если копировать понемногу то все работает нормально. 

ЛОГИ dsmeg и syslog: http://rghost.ru/6Mqrjp4PN
    


Ответы

Ответ 1



возможно, в файловой системе закончились inode. посмотреть ситуацию по ним можно для всех примонтированных файловых систем командой df -i. пример вывода (в пятом столбце — процент использованных inode): $ df -i Filesystem Inodes IUsed IFree IUse% Mounted on /dev/dm-0 920272 207134 713138 23% / udev 497545 440 497105 1% /dev tmpfs 499982 769 499213 1% /run tmpfs 499982 3 499979 1% /dev/shm tmpfs 499982 7 499975 1% /run/lock tmpfs 499982 14 499968 1% /sys/fs/cgroup /dev/sda1 124496 335 124161 1% /boot tmpfs 499982 9 499973 1% /run/user/1000 для конкретной файловой системы можно указать точку монтирования (у автора — /mnt/sdb1): $ df -i /mnt/sdb1 или, даже если файловая система не примонтирована, с помощью команды sudo tune2fs -l /dev/sdb1 | grep -i inode. пример вывода: Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize Inode count: 920272 Free inodes: 713166 Inodes per group: 8144 Inode blocks per group: 509 First inode: 11 Inode size: 256 Journal inode: 8 First orphan inode: 1863 Journal backup: inode blocks обратить следует внимание на inode count и free inodes. к сожалению, после создания файловой системы ext* уже невозможно изменить количество inode в ней. надо пересоздавать файловую систему (предварительно сохранив куда-нибудь всё её содержимое), указав, например, другой тип использования файловой системы. задать тип можно параметром -T usage-type программы mkfs.ext4. список типов можно посмотреть в /etc/mke2fs.conf. очень большое количество inode будет создано, например, для типа news (чем меньше inode_ratio, тем больше inode будет создано, а файловая система будет разбита на большее количество «кусочков» меньшего размера). а можно, не указывая тип использования, передать программе mkfs.ext4 непосредственно желаемый inode_ratio с помощью параметра -i. например, так: $ sudo mkfs.ext4 -i 4096 /dev/sdb1 предупреждение: только не увлекайтесь уменьшением inode_ratio: каждый inode «отбирает» несколько байт (задаётся с помощью inode_size, который лучше самому не изменять) «полезной ёмкости» для «служебной» информации.

четверг, 9 апреля 2020 г.

Как получить IP и MAC адреса в сети? Работа с arp cache в linux(android)

#linux #android #сеть #arp

                    
Два дня пытаюсь понять как заполнить arp cache? Мне нужно получить ip и mac адреса
всех устройств в домашней сети для одного приложения под android. Порылся в разных
ресурсах. Как я понял нужно сделать широковещательный запрос в подсеть и ждать.
Ситуация такая:
Я подключен через WiFi к сети домашнего маршрутизатора. ip адрес моего устройства
192.168.0.71, а широковещательный адрес 192.168.0.255, маска подсети 255.255.255.0(то
есть 254 хостов может быть как я понял).
Смотрю arp cache:

 
arp -a
 

Только адрес маршрутизатора 192.168.0.1, а в сети на самом деле как минимум 6 устройств.

Делаю широковещательный пинг

 
ping -c 1 -b 192.168.0.255
 

Пишет что 100% потеря пакетов, лол

Вновь смотрю arp cache - ничего нового.
Пытался под root и не под root.
Есть ли какие нибудь другие пути получить ip и mac адреса в сети?
Помогите плиз! По сетям не силен!
    


Ответы

Ответ 1



Либо ставить nmap на android, либо fping. В общем общая схема такая: пинговать каждый хост в подсети (вне зависимости от его доступности), а потом уже делать arp -a | grep Для nmap будет что-то типа: nmap -sP 192.168.0.* Для fping fping -g 192.168.0.0 192.168.0.255

Ответ 2



Чтобы linux отвечал на широковещательный пинг, надо его включить (на каждом хосте): # echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts При чём -c1 приведёт к тому, что ping завершится после приёма первого пакета и не станет ждать других устройств. Лучше ограничить время 1 секундой: ping -w 1 -b 192.168.0.255 Сканировать подсеть перебором всех адресов можно так (под рутом результат лучше): # nmap -sP -n -T5 192.168.1.0/24

вторник, 31 марта 2020 г.

Как узнать IP-адреса подключенные к локальной сети? [закрыт]

#java #сеть #ip


        
             
                
                    
                        
                            Закрыт. Этот вопрос необходимо уточнить или дополнить
подробностями. Ответы на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Добавьте больше подробностей
и уточните проблему, отредактировав это сообщение.
                        
                        Закрыт 2 года назад.
                                                                                
           
                
        
Как узнать IP-адреса подключенные к локальной сети?
    


Ответы

Ответ 1



Если требуется именно на java, то ответ есть здесь https://stackoverflow.com/questions/3345857/how-to-get-a-list-of-ip-connected-in-same-network-subnet-using-java. Примерно так: public static void checkHosts(String subnet) throws IOException { int timeout = 100; for (int i = 1; i < 255; i++) { String host = subnet + "." + i; if (InetAddress.getByName(host).isReachable(timeout)) { System.out.println(host + " is reachable"); } } } public static void main(String[] arguments) throws IOException { checkHosts("192.168.1"); }

вторник, 17 марта 2020 г.

Windows 7: проблема с беспроводной сетью

#windows #windows_7 #wifi #сеть


ЗдравствуйтеИмеется странная необъяснимая проблема с машиной под Windows 7. Переустановка
системы крайне нежелательна, а творятся странные вещи. Симптомы и факты:не работает
всё что связано с внешней сетью, включая DNSвнутренняя сеть работает, так я могу обратиться
к сетевому диску или роутеру;ping на внешние ресурсы не проходит, на внутренние работает;явление
непостоянное, но очень частое, возникает периодически;все другие устройства во время
таких затупов работают отлично, нагрузка на роутер обычная, расход ресурсов обычный;сначала
я подумал, что неисправен wifi-адаптер, но когда я его сменил, то с другим симптомы
такие же;при загрузке на этой машине под Linux указанная проблема не возникает, стало
быть проблема вероятно не связана с железом;все настройки в норме, пробовал пересоздавать
соединение, переключать разные флажки настроек, но ничего не помогает;по неизвестной
причине на какое-то время помогает перезагрузка wifi-роутера, однако, как я уже говорил
выше, все дургие устройства (ноутбук на Win7, ноутбук на Linux, два телефона на Android)
прекрасно работают с этим же роутером в то самое время, как на проблемной машине проявляется
проблема;простое переподключение сети, переподключение устройства, перезагрузка компьютера
не помогает, так что перезагрузка роутера является на данный момент единственным воркэраундом;проблема
затрагивает не только DNS: если я обращаюсь по внешнему точному адресу, то просто не
удаётся соединиться так будто пакеты просто теряются.Такое ощущение, будто нарушается
какая-то таблица маршрутов или что-то такое, что приводит к потерям пакетов, направленных
именно наружу, но я понятия не имею как диангостировать такие неполадки под win.Видел
описание аналогичной проблемы на форуме инфолана, но там не было ответа. Если есть
какие-то идеи, буду рад любой помощи.    


Ответы

Ответ 1



Включенный на роуторе (да и на компе) firewall объясняет то, что эффект имеет периодический характер. Вы забываете про интеллектуальные системы обнаружения вторжений. Ну а если Вы используете Avast или Nod32, то тут вообще всё понятно.

Ответ 2



Была похожая проблема на ноутбуке с WIndows 7. Проблема крылась в средствах безопасности, а ля антивирус Касперского и брандмауэр Windows. Необходимо проверить, чтобы домашняя сеть была указана в антивирусе и настройках сетевых подключений именно как "Домашняя" или "Доверенная".

Ответ 3



Я бы сделал так:посмотрел бы таблицу маршрутизации - на WindowsXP+ - netstat -rnпосмотрел бы что с ифейсами - ipconfig /allпосмотрел бы на таблицу arp - arp -aпосмотрел бы tcpdump - для винды есть утилитка соответствующая (которую надо ставить отдельно, в состав системы не входит)Думаю, что в купе эта информация покажет вам "слабое звено"

Ответ 4



Такое же было. Модем в роутере 2е 7ры днс и тп, проблемы с интернетом. На одном из компьютеров поставил 8ку, работает шикарно и без предыдущих проблем. Кстати, при 7ке и ХР тоже проблем таковых не возникало.

пятница, 13 марта 2020 г.

Передача данных с минимальной задержкой

#c_sharp #cpp #алгоритм #сеть #аудио


Есть потребность в программе, которая позволит джемовать музыкантам по сети, и есть
желание ее написать. Для этого требуется, чтобы доставка аудио (массивов байтов, размером
около 1 кб) осуществлялась с минимальной задержкой (не больше 10 мс). Возможно ли добиться
такого? Если да, то как? (Протокол передачи, сжатие, тип сети (p2p или сервер-клиент)
и т.д.)  Писать хотелось бы на C# или C++.

UPD: интересует еще такой момент. Для уменьшения задержки думаю запаковывать данные
в GZip. Скажите, пожалуйста, имеет ли это смысл? Я имею в виду, что не быстрее ли будет
просто отсылать незапакованные данные, чем сначала запаковывать, отсылать, а потом
распаковывать?
    


Ответы

Ответ 1



Сначала отвечу на вопросы, потом с позволения выскажу свое мнение по поводу затеи. Добиться задержек в 10 мс можно например при подключении точка-точка или в простой локальной сети. Но в вашем случае это почти не реально. Например, прямо сейчас у меня пинг до шлюза 75-80 мс. Кроме того что пакеты будут теряться, так еще они и доставляться будут с непостоянным временем, то есть будет джитер. Транспортный протокол однозначно UDP. Хотя есть еще CSTP, но у него ограниченная поддержка со стороны провайдеров, велика вероятность, что найдется узел который будет резать все что не UDP и не TCP. А в Виндоуз он вообще бедный родственник. По прикладному уровню рекомендую ознакомится с RTP. P2P как в битторенте, вам не поможет в случае если городская сеть жестко централизованна, что часто бывает в небольших городах. То есть если у провайдера один шлюз на всех и к нему централизованно сходятся все каналы от обывателей. Получится, что между участниками будет по одному каналу и битторент будет скорее проигрывать т.к. у него свои накладные тоже есть. Битторент нуждается в избыточных каналах тогда появляется возможность параллельной передачи, в чем и состоит его суть. Можно попробовать организовать P2P как в скайпе. Например, если среди трех участников окажется что 2 выгоднее быть посредником между 1 и 3, то можно назначить 2 сервером для 1 и 3. Тогда он должен будет передавать для 1: себя и 3, а для 2: себя и 1. Для большего количества участников понадобится подбирать посредников для каждого канала. То есть это задача на максимальный поток. Сжимать однозначно надо пробовать, но только не зипом, а аудио-кодеком. Велика вероятность что сжатие\разжатие можно будет делать аппаратно. Теперь мнение про затею. Почему вы вообще решили что задержки в 10 мс будет достаточно, музыка это тонкая вещь. Большим оркестром обычно управляет дирижер потому что музыканты просто не слышат друг-друга. Рекомендую вам присмотреться к радио.

Ответ 2



Я конечно может не до конца разобрался в вопросе! Но тобы отправить данные которые не помещаются в один пакет UDP(TCP) c минимальными задержками и минимальной нагрузкой на сеть можно воспользоваться технологией отправки пула пакетов (SendQueue), реализованной в WinPcap(LibPcap). Вот здесь все популярно объяснено и с примерами на C# https://pcapdotnet.codeplex.com (раздел https://pcapdotnet.codeplex.com/SourceControl/latest#PcapDotNet.DevelopersPack/src/SendingPacketsUsingSendBuffer/Program.cs).

воскресенье, 8 марта 2020 г.

Раздать интернет в локальную сеть

#linux #сеть


У меня есть домашняя сеть на два компьютера. Первый (c linux mint 17.2 64 bit) -
это тот, который подключен к интернету через кабель, и от него же идет кабель ко второму
(с windows).

Сетевые карточки определились, интернет есть и сеть тоже есть, но я не могу раздать
интернет. На компьютере с windows написано "без доступа к Интернету", хотя на линуксовом
пишет, что подключение есть.

Как мне раздать интернет на оба компьютера?
    


Ответы

Ответ 1



копия моего ответа на идентичный по сути, но иной по форме вопрос: если на компьютерах в подсети шлюзом по умолчанию указано использование того самого сервера, который вы настраиваете, то достаточно: разрешить на этом сервере передачу пакетов между интерфейсами: $ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward для того, чтобы эта настройка применялась и после перезагрузки, раскомментируйте (или добавьте, если нет) строку в /etc/sysctl.conf: net.ipv4.ip_forward=1 проконтролировать, что эти пакеты не искажаются и не блокируются netfilter-ом (см. вывод $ sudo iptables-save). добавить правило netfiler-а для подмены адреса отправителя у пакетов, поступивших с «внутреннего» интерфейса, и уходящих на внешний интерфейс: $ sudo iptables -t nat -A POSTROUTING -o внешний_интерфейс -j MASQUERADE если же на этих компьютерах шлюзом по умолчанию служит другая машина (или вообще таковой не задан), то, в дополнение к разрешению передачи пакетов между интерфейсами, вам ещё придётся эти пакеты «искажать». как минимум потребуется подмена адреса источника у пакетов, поступивших на «внешний» интерфейс, и адресованных компьютерам подсети, а также обратная подмена адреса назначения у «ответных» пакетов. оба данных действия может выполнять директива netfilter-а под названием snat (source nat). пример её добавления с помощью программы iptables: $ sudo iptables -t nat -A POSTROUTING -o внутренний_интерфейс -j SNAT --to-source ip-адрес где ip-адрес — адрес, закреплённый за «внутренним» интерфейсом. для того, чтобы не вводить упомянутые выше одну или две команды (iptables ...) после каждой перезагрузки настраиваемого сервера, их можно добавить, например, в конец файла /etc/rc.local, но до строки exit 0, которая там обычно присутствует (если нет — просто добавляйте в конец файла). добавка sudo, конечно, в этом файле не нужна.

Ответ 2



Нужно сделать интернет шлюз. Например: На Linux машине sudo echo 1 > /proc/sys/net/ipv4/ip_forward sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o ppp0 -j MASQUERADE 192.168.1.0/24-домашняя подсесть. В windows в свойствах протокола TCP/IP4 прописывается в первой строке IP домашней подсети например 192.168.0.2, во второй Маска подсети например 255.255.255.0 , Основной шлюз 192.168.0.1

среда, 4 марта 2020 г.

Сколько максимально одновременных подключений может держать сервер?

#сеть


В стать https://habrahabr.ru/post/50028/ говориться что были сервера способные держать
1 000 000 пользователей. А как такое возможно если портов всего 2^16?
    


Ответы

Ответ 1



Соединение характеризуется следующей конструкцией из 5 элементов: IP клиента, Порт клиента, IP сервера, Порт сервера, Протокол Например: 10.0.0.1:1234 192.168.0.1:80 TCP 10.0.0.1:1235 192.168.0.1:80 TCP 10.0.0.1:1236 192.168.0.1:80 TCP ... 10.0.0.2:1234 192.168.0.1:80 TCP 10.0.0.2:1235 192.168.0.1:80 TCP 10.0.0.2:1236 192.168.0.1:80 TCP ... Последние 3 элемента имеют фиксированное значение, а вот первые 2 изменяются и в комбинации могут давать огромные значения. С одного IP может подключиться до 64k клиентов, с другого ещё столько же и т.д. Таким образом, теоретическое максимальное число соединений может быть равно число клиентских IP адресов * число портов на клиенте (64k). С практической же точки зрения, ресурсы сервера (RAM, CPU, I/O) ограничены, и в зависимости от реализации сервера, он может обрабатывать лишь какое-то N-ное число одновременных соединений, которое меньше теоретического IP*64k. Чем эффективнее написан сервер (т.е. чем эффективнее он использует ограниченные ресурсы железа), тем больше соединений он сможет держать. Самые неэффективные реализации создают по процессу на каждое входящее соединение, более эффективные используют один процесс и создают по потоку (thread) на соединение, а ещё более эффективные умеют обходиться фиксированным числом процессов и потоков, выполняя асинхронную обработку запросов.

Ответ 2



Порты не имеют никакого отношения к одновременному колличеству подключений. Порт - это просто место, куда приходит запрос\подключение. Что именно обработает запрос на этот порт - вот это уже важно. И там говорится не про сервера, а про функциональный язык программирования Erlang, на котором можно написать проект, максимально задействующий ресурсы машины, что в свою очередь может дать до миллиона одновременных коннектов. Итак, ответ на ваш вопрос - дело вообще не в портах.

воскресенье, 1 марта 2020 г.

Какова методология работы клиента с сервером на android

#java #android #сеть


Я работаю на .Net C#. Сейчас появилась необходимость мигрировать на android. И задача
в написании именно клиента, так как сервер на C# написан и работает на десктопе.  

На C# взаимодействие клиента с сервером выглядело достаточно логично: 

  connect = new MyConnect(address, port);   
  ....    
  connect.Send("select ......... ;");  // SQL запрос  
  Object obj = connect.Receive();      
  ....      


На Java коннект с сервером происходит только в отдельном потоке. Сразу вопрос: а
как мне в основном потоке указать что мне надо передать на сервер и как потом получить
ответ? Все примеры, которые я нагуглил, сначала пишут что-то на сервер, потом читают
ответ (это все в отдельном потоке) и закрываются. А если мне, в зависимости от ответа
сервера, надо отправить серверу другой запрос - надо снова открывать сокет? Вообщем,
честно, пока не понимаю, как работать с сетью, не убивая на передачу и чтение половину
времени и кода...
На Java я пытаюсь перейти в течении чуть больше недели, но при знакомстве с работой
в сети создается впечатление, что она заточена для написания чего-то типа чатов - отправил
сообщение, получил ответ, плюхнул на форму, ждем входного сообщения или своего исходящего.
В моем случае - инициатором общения с сервером является только клиент: запроc клиента
- ответ сервера - и все.    

Вкратце, задача состоит в написании приложений для терминалов сбора данных (ТСД).
Хилые возможности данных девайсов делают предпочтительной отправку запросов на сервер
 и получение от него уже готовых ответов, не используя локальную базу данных.
    


Ответы

Ответ 1



Мне кажется в вашем случае имеет смысл запустить Service в котором уже будет открыто соединение. И общатся с сервисом по средствам Broadcast. Таким образом вам не нужно закрывать соединение каждый раз.

Ответ 2



Используйте Retrofit 2 для работы с API пруф. А то что в другом потоке это нормально для Android, чтобы UI не ждал ответа сервера и не было сообщения ANR.

Ответ 3



Почему я решил ответить на свой же вопрос? Во-первых, потому, что принятый мною ответ оказался достаточно тяжеловесным. Все-таки, это не та задача, как мне кажется, для решения которой надо писать отдельную службу. Тем не менее, большое спасибо Anton111111 ! Во-вторых, потому, что многократный поиск в Google ответа так и не дал - все решения давались исключительно для общения приложения с веб-сайтами, а для работы терминала сбора данных с сервером базы данных по локальной сети не подходили. В конце концов, решил таки я свою проблему. Решается она посредством AsyncTask. Вот "выжимка" из класса для открытия и закрытия соединения, и для передачи и приема данных. Если кому-то пригодится - буду рад! Кодировка UTF_16 выбрана исключительно из-за особенностей моего внутреннего протокола - в начале каждого пакета передается количество байт в пакете. Кодировка UTF8 в моем случае не подходит. По сути, это первый мой код, потому прошу, не судите строго :) public class dbClient { private String chSet = "UTF_16LE"; private Socket mSocket = null; private int mPort = 11963; public boolean isConnected = false; public String strSend; public boolean isDone = false; public dbClient() {} public void openDB(String _user, String _ip, int _port) { mUser = _user; mIP = _ip; mPort = _port; try { AsyncOpenConnection at = new AsyncOpenConnection(); at.execute(); at.get(); isConnected = true; } catch (Exception e) { close(); } return; } public void send(String _str) { strSend = _str; try { AsyncSend at = new AsyncSend(); at.execute(); at.get(); } catch (Exception e) { close(); } return; } public boolean recv() { boolean ret = false; try { AsyncRecv at = new AsyncRecv(); at.execute(); at.get(); ret = true; } catch (Exception e) { close(); } return ret; } public void close() { isConnected = false; try { AsyncCloseConnection at = new AsyncCloseConnection(); at.execute(); at.get(); } catch (Exception e) { } return; } //---------------- Классы AsyncTask ----------------------- // Класс AsyncTaskOpenConnection class AsyncOpenConnection extends AsyncTask { @Override protected void onPreExecute() { super.onPreExecute(); isConnected = false; isDone = false; } @Override protected Boolean doInBackground(Void... params) { try { openConnection(); isConnected = true; isDone = true; } catch (Exception e) { e.printStackTrace(); } return isConnected; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); } } // Класс AsyncSend class AsyncSend extends AsyncTask { @Override protected void onPreExecute() { super.onPreExecute(); isDone = false; } @Override protected Boolean doInBackground(Void... params) { try { sendData(strSend.getBytes(chSet)); isDone = true; } catch (Exception e) { e.printStackTrace(); } return isDone; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); } } class AsyncRecv extends AsyncTask { @Override protected void onPreExecute() { super.onPreExecute(); isDone = false; } @Override protected Boolean doInBackground(Void... params) { try { recvData(); isDone = true; } catch (Exception e) { e.printStackTrace(); } return isDone; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); } } class AsyncCloseConnection extends AsyncTask { @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected Boolean doInBackground(Void... params) { try { closeConnection(); } catch (Exception e) { e.printStackTrace(); return false; } return true; } @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); } } public void sendData(byte[] data) throws Exception { if (mSocket == null || mSocket.isClosed()) { throw new Exception("Невозможно отправить данные. Сокет не создан или закрыт"); } try { /* Отправка данных */ mSocket.getOutputStream().write(data); mSocket.getOutputStream().flush(); } catch (IOException e) { throw new Exception("Невозможно отправить данные: " + e.getMessage()); } } public void recvData() throws Exception { byte[] buf = new byte[1024 * 8]; try { int cnt = mSocket.getInputStream().read(buf, 0); } catch (IOException e) { throw new Exception("Невозможно считать данные: " + e.getMessage()); } } private void openConnection() throws Exception { closeConnection(); try { mSocket = new Socket(mIP, mPort); } catch (IOException e) { throw new Exception("Невозможно создать сокет: " + e.getMessage()); } } private void closeConnection() { if (mSocket != null && !mSocket.isClosed()) { try { mSocket.close(); } catch (IOException e) { Log.e(LOG_TAG, "Невозможно закрыть сокет: " + e.getMessage()); } finally { mSocket = null; } } } }

пятница, 28 февраля 2020 г.

android.os.NetworkOnMainThreadException при использовании потока

#java #android #сеть


Есть обработчик нажатия кнопки. При нажатии должен выполнится сетевой запрос. 
Написал по уроку простой метод для отправки http-запросов. Получил эту ошибку
android.os.NetworkOnMainThreadException Почитал, что это связано с тем, что запрос
выполняется в UI потоке. Ладно. Создал отдельный поток. 

public void reportSend(View v)
{
         th =   new Thread(new Runnable() {
                @Override
                public void run() {
                    Log.i("TAG","MSG");

                    HttpURLConnection connection = null;
                    StringBuilder sb = new StringBuilder();
                    try {

                        connection = (HttpURLConnection) new URL ("http://spaces.ru").openConnection();

                        connection.connect();


                        if(connection.HTTP_OK == connection.getResponseCode())
                        {
                            BufferedReader input = new BufferedReader(new InputStreamReader(
connection.getInputStream(), "cp1251"));


                            String line;
                            while ((line = input.readLine()) != null)
                            {
                                sb.append(line);
                                sb.append("\n");
                            }

                        }

                    }
                    catch (Exception cause) {
                        cause.printStackTrace();
                        //  Toast.makeText(MainActivity.this, cause.getMessage().toString(),
Toast.LENGTH_LONG).show();
                    }
                    finally {
                        if(connection != null)
                            connection.disconnect();
                    }


                    Log.i("NET",  sb.toString());
                }
            });

            th.run();
}


Ошибка тем не менее сохранилась прежняя. 
Как выйти из положения?
    


Ответы

Ответ 1



Метод Thread.run() выполнит код синхронно, в том же потоке, замените на start()

Как сгенерировать ASCII для сетевых протоколов в консоли?

#python #сеть #tcp #протоколы


Есть какая-нибудь консольная утилита, которая позволяет просматривать ASCII-диаграммы
для сетевых протоколов непосредственно в консоли?
    


Ответы

Ответ 1



Да, есть консольная утилита protocol, написанная на python, которая позволяет взглянуть на стандартные заголовки сетевых протоколов прямо в консоли, без необходимости искать информацию в интернетах. Для установки инструмента выполните: git clone https://github.com/luismartingarcia/protocol.git сd protocol sudo ./setup.py install Собственно, всё! Проверим как работает, выполним: protocol ethernet Получаем ASCII-диаграмму для ethernet: Более подробная информация здесь.

вторник, 25 февраля 2020 г.

Хороший и краткий учебник по компьютерным сетям [закрыт]

#сеть #книги


        
             
                
                    
                        
                            Закрыт. На этот вопрос невозможно дать объективный ответ.
Ответы на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы на него можно было дать ответ, основанный на фактах и цитатах, отредактировав его.
                        
                        Закрыт 4 года назад.
                                                                                
           
                
        
Доброго времени суток.
Прошу совета по кратким пособиям по компьютерным сетям. Я - программист, но вот с
пониманием работы сетей и протоколов у меня плоховато. Хочу подтянуться.
Не нужны учебники на 1к листов, я хочу почитать связный материал и быстро узнать
что такое DHCP, DNS, WINS, Шлюзы, DNS-суффиксы и так далее. Я конечно мог бы просто
пройтись по википедии и почитать определения, но это было бы не совсем связно, я хочу
узнать что происходит от момента втыкания патчкорда в сетевую карту и до момента доступа
к интернету, что ОС делает сама, а что иногда приходится делать в ручную. Если таковые
встречали - посоветуйте пожалуйста.
Заранее большое спасибо!    


Ответы

Ответ 1



Э. Таненбаум "Компьютерные сети"

Ответ 2



Самая короткая из знакомых мне полезных - Й.Снейдер "Эффективное программирование TCP/IP" - примерно 300 страниц. А вообще, очень хорошо разжеванный материал - Д. Камер "Сети TCP/IP" - тут уже страниц 800, но кто мешает выбрать отдельно интересующие главы, в частности в начале книги очень хорошо и доступно описан механизм работы сетей с нуля, этих глав Вам на первое время будет достаточно.

суббота, 15 февраля 2020 г.

В чем отличие между HTTP методами HEAD и OPTIONS?

#веб_программирование #сеть #http #веб_сервер


В чем отличие между HTTP методами HEAD и OPTIONS? я знаю лишь что в ответ на OPTIONS
сервер должен отдать Allow со списком поддерживаемых методов. Есть ли еще какие либо
концептуальные/технические отличия?
    


Ответы

Ответ 1



У этих запросов разное назначение: HEAD - служит для проверки существования ресурса, он полностью аналогичен GET, но без возврата тела ответа OPTIONS - служит для получения параметров для ресурса или для сервера в целом и при этом сам ресурс ни как не затрагивается (то есть это более дешевая операция по сравнению с HEAD) OPTIONS возвращает параметры в заголовке. Список параметров зависит о ресурса и/или сервера. Обычно это заголовок Allow, который описывает какие методы доступны для ресурса.

Ответ 2



HEAD Данный метод по своей сути похож на GET, но сервер отвечает на запрос одним лишь заголовком. (Отсюда и название метода.) Применяется, например, чтобы узнать, существует ли в сети тот или иной URL и не произошло ли каких-нибудь изменений. OPTIONS Метод представляет запрос информации об опциях соединения, доступных в цепочке запросов/ответов, идентифицируемой запрашиваемым URI (Request-URI). Этот метод позволяет клиенту определять опции и/или требования, связанные с ресурсом, или возможностями сервера, но не производя никаких действий над ресурсом и не инициируя его загрузку.

Ответ 3



Отличие этих методов - в том, что HEAD запрашивает информацию о ресурсе, а OPTIONS запрашивает информацию о методах доступа к ресурсу. Более подробно. Заголовки, возвращаемые методом HEAD, обязаны соответствовать заголовкам, возвращаемым методом GET. При этом, метод HEAD не имеет никакого отношения к методам POST, PUT, DELETE и прочим. В то же время, настройки доступа, возвращаемые методом OPTIONS, имеют отношение сразу ко всем методом ресурса - GET, POST, PUT, DELETE и пр. Если говорить о применении, то метод HEAD может использоваться чтобы получить информацию о странице без скачивания самой страницы. Метод OPTIONS же используется, в основном, механизмом Preflight request в CORS или для обнаружения поддерживаемых сервером фич в WebDAV.

пятница, 14 февраля 2020 г.

Что за IP вида 10.658941?

#сеть #ip #tcp_ip


ping 10.658941


Даёт такой IP:


  PING 10.658941 (10.10.13.253) 56(84) bytes of data.


Объясните, пожалуйста, что значит .658941, и почему именно в таком формате? И для
чего вообще это нужно?
    


Ответы

Ответ 1



ip - это 32-х разрядное число. На 4 байта его делят, грубо говоря, для разделения уровня сетей, а выводят с разделением точками - для удобства восприятия. 10.13.253 = 10*256*256 + 13*256 + 253 = 658941 Можно вообще весь адрес записать как 168431101 или 0x0A0A0DFD

четверг, 13 февраля 2020 г.

Как открыть порт 27015?

#сеть #порты


Пытаюсь открыть порт 27015 на Win 7 Ultimate. 2ip.ru пишет, что порт закрыт, при
выключенном антивирусе (Kaspersky).  IP-динамический. 2ip.ru и команда nslookup в командной
строке выдают разные IP, соответственно IP - внутренний (правильно определил?). В брандмауэре
всё открыто. Звонил провайдеру, говорят что они никаких портов кроме 21-го не закрывают.
Так как же мне всё таки открыть этот порт?!
    


Ответы

Ответ 1



Наверное вы за NATом, поэтому порт и будет закрыт извне. Тут ничего не сделаешь, пока не появится возможность организовать "белый" ip-адрес.

Ответ 2



Закажите у провайдера услугу выделенный ip адрес(0,5-1$ в месяц обычно). Обычно в винде всего лишь надо подтвердить запрос при первом запуске сервера на выход в сеть.

Ответ 3



Попробуйте для исключения ошибок, проверить в локальной сети открытость порта, сделать прверку из сети между компьютерами. Если всё отлично, посмотрите настройки браундмаера, так же не занят ли этот порт кем то, если роутер - то просто проброс. На Linux это делается одной строчкой.

воскресенье, 9 февраля 2020 г.

Выделить ещё ядер на обработку сети(sysctl)

#linux #сеть #kernel


При нагрузке на сеть(много соединений и дудос) у меня нагружается только ядро №5.
 Как можно распределить нагрузку на все ядра?(настраивал sysctl, irqbalance нет)
    


Ответы

Ответ 1



Для начала, тебе нужно узнать, работает ли на твоем сервере механизм ядра, называющийся RPS: watch -n1 cat /proc/softirqs Если NET_RX и NET_TX прерывания идут только на одно ядро, значит RPS не включен, и его необходимо сконфигурировать, с помощью установки битовых масок в: /sys/class/net/DEVICE/queues/QUEUE/rps_cpus Битовые маски, в HEX формате означают, на каких cpu будут обрабатываться сетевые прерывания, и для каждой системы они будут разные. Статья с примером установки таких масок: https://habrahabr.ru/company/flant/blog/332432/ Подробнее об RPS можно прочитать тут: https://github.com/torvalds/linux/blob/v3.13/Documentation/networking/scaling.txt#L138-L164

среда, 5 февраля 2020 г.

Как работает протокол TCP/IP?

#сеть #tcp_ip


Привет.

Вопрос по сетям (стек протоколов TCP/IP). Если человек вводит url-адрес в строку
адреса в браузере и жмет энтэр, то:


Браузер смотрит, а есть ли на компе в таблице соответствия доменных имен логическим
адресам данное доменное имя. Например, его нет в таблице и отправляется DNS-пакет-запрос
на DNS-сервер подсети... потом приходит ответ.
Айпи адрес получателя теперь известен и начинается установка соединения по протоколу
TCP - трехкратное рукопожатие.


...

Мне не понятно, ГДЕ все эти правила записаны (где эта последовательность действий
задана) - "посмотри, есть ли соответствие "доменное имя - айпи" на компе, если нет,
отправь, днс-запрос серверу днс, жди ответ, потом устанавливай соединение по протоколу
айпи, котом пакеты лови (хттп и тсп-пакеты) и посылай подтверждение о получении, закрывай
соединение"? Это какой-то протокол? Везде пишут про ОПИСАННУЮ ВЫШЕ последовательность
действий, но мне не понятно КАКАЯ ПРОГРАММА ЭТО ВСЕ ДЕЛАЕТ И ГДЕ ЭТО "ЗАШИТО".
    


Ответы

Ответ 1



Работа с сетью - это одна из частей многоуровневой системы ввода/вывода в операционной системе. Если вникать глубже, когда вы инициализируете запрос к устройству, этот запрос обслуживает диспетчер ввода-вывода, который передаст его куда нужно, и вернет в процесс данные, которые нужны от устройства. Во всех современных сетях используется так называемый стек протоколов для наслоения различных протоколов друг на друга. На каждом уровне решаются разные вопросы. Например, на самом нижнем уровне протоколы определяют, как сообщить в потоке битов, где начинаются и где заканчиваются пакеты. На более высоком уровне протоколы занимаются прокладыванием маршрутов для пакетов по сложным сетям от источника к месту назначения. И на еще более высоком уровне они обеспечивают надлежащую доставку всех пакетов в многопакетном сообщении в нужном порядке. Пользовательский процесс генерирует сообщение и выдает системный вызов для его отправки по предварительно установленному TCP-соединению. Стек протоколов, находящийся в ядре, добавляет в начало сообщения TCP-заголовок, а затем IP-заголовок. Затем сообщение поступает к драйверу сети Ethernet, который добавляет Ethernet-заголовок, направляющий пакет к маршрутизатору в сети Ethernet. После чего этот маршрутизатор внедряет пакет в Интернет. Чтобы установить соединение с удаленным хостом (или хотя бы отправить ему дейтаграмму), необходимо знать его IP-адрес. Поскольку оперировать списками с 32-битными адресами людям неудобно, была изобретена система под названием DNS (Domain Name System — система доменных имен), представляющая собой базу данных, которая отображает ASCII-имена хостов на их IP-адреса. Браузер запрашивает у DNS IP-адрес, соответствующий имени DNS в ответ выдает IP Браузер устанавливает TCP-соединение с портом 80 на хосте с IP-адресом Затем он отправляет запрос на файл index.html Сервер отправляет файл index.html Отображение файла TCP-соединение разрывается. Естественно, установление соединения, запрос IP по имени происходит через API операционной системы, операционная система пересылает ваш запрос DNS службе, которая сканирует файл hosts, и если там есть запись - выдает ее, иначе обращается к серверу или собственному кешу. Рекомендую Вам почитать "Современные операционные системы" Э. Таненбаум., книга большая, но знаний от нее получите по архитектуре и работе операционной системы массу.

суббота, 1 февраля 2020 г.

Непонятки с функцией connect и accept

#c #сеть


Ребят, у меня тут назрело два вопроса:




Функция connect (int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);)
принимает во второй аргумент адрес сервера, тогда зачем мне указывать какое семейство
адресов у сокета этого сервера в приложении клиенте (addr.sin_family=AF_INET;)? Почему
нельзя просто айпишник и порт указать?





В строке socket2=accept(socket1,(struct sockaddr*)&client,(socklen_t*)&len_client);
во втором аргументе указана структура, в которую записывается адрес сокета клиента.
Вопрос, откуда он берет этот адрес? Я же не передаю его никак в функцию connect.

    


Ответы

Ответ 1



зачем мне указывать какое семейство адресов у сокета этого сервера(addr.sin_family=AF_INET;)? Почему нельзя просто айпишник и порт указать? Потому, что один и тот же порт, зачастую, может работать как с UDP, так и с TCP. Например: 25 порт - SMTP: UDP/TCP Может принимать пакеты на UDP порт и соединения на TCP порт. откуда он берет этот адрес? Согласно "RFC 791 — Протокол IP" в заголовке любого пакета IP должны присутствовать как адрес получателя (т.е. алрес Вашего сервера) так и адрес отправителя - клиента, пытающегося работать с Вашим сервером.

Ответ 2



Интересный вопрос (особенно первая часть -- "...зачем мне указывать какое семейство адресов у сокета этого сервера?", побудившая меня перечитать manpages) В самом деле, если мы посмотрим на вызов socket(), то увидим, что в аргументе domain задаются те же константы (AF_INET и т.п.), что и в поле sockadr.sin_family в вызове connect(). На первый взгляд кажется, что и в самом деле это поле избыточно при вызове connect(). Однако, оно используется по крайней мере для достижения двух целей. Во-первых, это проверка целостности (не противоречивости) данных. При вызове connect() происходит проверка, что семейство адресов, задаваемое в поле .sin_family адреса сервера соответствует допустимым протоколам сокета (address_families), которые были заданы в аргументе domain при его создании. А второй возможный ответ кроется вот в этом абзаце из man connect: Generally, connection-based protocol sockets may successfully connect() only once; connectionless protocol sockets may use connect() multiple times to change their association. Connectionless sockets may dissolve the association by connecting to an address with the sa_family member of sockaddr set to AF_UNSPEC (supported on Linux since kernel 2.2). более конкретно, в словах: "Connectionless sockets may dissolve the association......with the sa_family member of sockaddr set to AF_UNSPEC" Т.е. для сокетов типа SOCK_STREAM (а именно с ними мы в основном используем connect) поле .sin_family (если отбросить проверки непротиворечивости) избыточно, но оно нужно (очевидно, не часто) для использования connect с SOCK_DGRAM сокетами (обычно мы вообще не используем connect(), работая с ними, а задаем адрес получателя непосредственно в вызове sendto). Что касается второй части вопроса об адресе клиента в серверном вызове accept() --"откуда он берет этот адрес? Я же не передаю его никак в функцию connect", то ответ следующий: accept() срабатывает на стороне сервера в ответ на connect() у клиента. ОС на стороне сервера записывает во второй аргумент accept() адрес клиента. Само значение своего адреса клиент либо задает сам, вызывая bind перед вызовом connect(), либо (если bind() не использовали) оно формируется ОС в ходе вызова connect() из первичного адреса сетевого интерфейса, который алгоритмы роутинга выбирают для данного соединения и свободного динамического номера порта (см. тут (обычно где-то от 65535 до 49000)). Далее этот адрес передается во всех IP-пакетах (включая первый пакет с запросом соединения), которыми обмениваются клиент с сервером.

Как проверить изменился ли файл?

#сеть #delphi #файлы


Для проекта необходимо в реальном времени отслеживать изменение файла на сетевом
диске, и сразу загружать последнюю версию.

Сейчас все делаю через таймер и FileDateToDateTime(). Клиентов не больше 20ти, но
меня все же мучает вопрос - не скажется ли такой метод на производительности и надежности
сетевого хранилища? Насколько вредны постоянные запросы?

Как этот же функционал можно реализовать более правильно?

p.s.: Вариант с клиент-серверным приложением самый-самый крайний, т.к. для него в
офисе нет отдельной машины, да и начальство не будет в восторге от такой идеи.

Update
После многочисленных экспериментов решил отказаться от идеи отслеживания файлов в
пользу UDP Broadcast. Т.к. изменение файлов происходит в приложениях-клиентах, то я
сразу отправляю пакет другим клиентам. Пока что отправляю только уведомление, что что-то
поменялось, но, в последствии, переделаю с указанием точного адреса файла.
    


Ответы

Ответ 1



Я считаю, что самый лучший вариант в данном случае, это сверять хэш файла. Я делал приложение такое на шарпе. Был сервер, на котором хранился файл программы, который постоянно обновлялся. И было порядка 10-ти машин, на которых приходилось постоянно обновлять файл. Решил облегчить себе работу, и всё это автоматизировать. Идея была следующей: у каждого клиента, в трее висит программа, которая через определённый интервал времени должна была каким - то образом проверять, не изменился ли файл. Изначально, мысль была сделать проверку по дате изменения файла, но сказать честно, этот вариант отпал сразу, ибо не всегда при замене(программно во всяком случае) файла, меняется дата его последнего обновления. Решил сделать следующим образом: Программа при первом запуске записывала в ini файл хеш нужного файла, и в последствии, через какой - то интервал времени сравнивала текущий хэш файла, с тем, что был записал в ini файл. ) Если изменений нет - молчим. Если есть - выводим сообщение, где пользователю предлагается обновить файл. ) Работает отлично. Бегать больше не приходилось. )

Ответ 2



SMB кеширует запросы к статистике файла, в том числе к mtime, так что сильно переживать за нагрузку не надо :)

Ответ 3



Если надо получать точные сведения - какой файл или папка изменён, какие изменения с ним произошли и в какой последовательности - для этого надо применять механизм, построенный на вызовах функций: CreateFile(), ReadDirectoryChangesW(), CloseHandle(). Пример использования на Delphi можно найти здесь.

Ответ 4



Могу предложить еще вариант: Монтировать сетевую папку как диск и попробовать отслеживать изменения как в локальной директории. Но за работоспособность не ручаюсь.

Ответ 5



А почему бы не использовать FileSystemWatcher из System.IO из .NET. Можно отслеживать изменение файла и каталога хоть по сети. Тем более есть Delphi.NET

Пакеты склеиваются

#c_sharp #java #сеть


public class NetCon extends Thread {

    String address = "127.0.0.1";
    int port = 3458;

    private DataInputStream in;
    private DataOutputStream out;

    public ArrayList queue;

    public Boolean Connect()
    {
        try {
            InetAddress ipAddress = InetAddress.getByName(address);
            Socket socket = new Socket(ipAddress, port);

            InputStream sin = socket.getInputStream();
            OutputStream sout = socket.getOutputStream();

            in = new DataInputStream(sin);
            out = new DataOutputStream(sout);

            queue = new ArrayList();
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public void SendText(String s) {
        try {
            out.write(s.getBytes("UTF-8"));
            out.flush();
        } catch(Exception e) {
            System.out.println(e);
        }
    }

    @Override
    public void run() {
        for(int i = 0; i < queue.size(); i++) {
            //System.out.println(queue.get(i)); //если убрать коммент. то ок
            SendText(queue.get(i));
        }
    }

}

В queue находится две строки "test1", "test2". Запускаю поток, идёт отправка на сервер.
Проблема в том, что иногда получаю 2 пакета как и положено, первый пакет со строкой
"test1", второй с "test2", а иногда проскакивает что получаю пакет "test1test2". Если
перед отправкой на сервер выводить на экран, то получается маленькая задержка и работает
тогда всегда правильно. Почему между пакетами нужна эта пауза? Как сделать нормально?
Вот фрагмент кода сервера C# (TcpClient)
NetworkStream ns = client.GetStream();
byte[] buffer = new byte[1024];

int count;
while ((count = ns.Read(buffer, 0, buffer.Length)) > 0)
{
   Console.WriteLine(BitConverter.ToString(buffer, 0, count));
   Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, count));
   ns.Flush();
}
    


Ответы

Ответ 1



Скорость сокета - непредсказуемая штука. Бывает, что пакет пришел ещё не весь, а программа уже читает буфер - пакет получен не весь, а следующий искажен. Бывает, что программа не дернула буфер сокета вовремя, и пришел ещё один или больше пакетов. Программа дергает буфер - и получает склеившиеся пакеты. Всё дело в устройстве TCP/IP, и вытекающем из него устройстве сокета и его буфера. Сетевые пакеты ни как не обозначают свою длину, если програмист не позаботился об этом. В сокет приходит байт, и он сразу помещается в конец своего буфера. Не имеет значения, пришел один байт или миллион. Когда программа вызывает метод чтения, если не указана читаемая длина - возвращается весь буфер в обратном порядке, а если указана - то байты от нулевого до указанного в обратном порядке. Таким образом программист сам обязан обозначивать размер или диапазон байтов в пакете. Решений несколько. От самых неправильных к наиболее подходящему: 1) Фиксировать размер пакета. Встречал несколько раз в чужом коде. Наличествует ещё и свой буфер, в который до нужного заполнения сливают данные буфера сокета, и читают нужными порциями. Стоит ли говорить, что вещь ужасно хардкодная? 2) В пакете означают его конец, к примеру каким-нибудь сочетанием 00-FF-00-FF. Встречал 2 раза. Велосипедизм. Возможны ложные срабатывания детектора конца пакета. 3) Первыми двумя (или четырьмя, если пакет планируется длинным) байтам обозначают либо размер всего пакета, либо размер "полезной части. Программа в цикле ждет 2 байта в буфере сокета, и читает их. Далее программа ждет появления N байтов или больше в сокете, где N - цифра, прочтенная из первых двух байтов. Далее программа читает N байт в свой буфер, и обрабатывает их. Цикл входит в новую итерацию. Помогать конкретным кодом не стану, если автор не попросит этого прямо. Я пропагандирую самостоятельное развитие ума с возможными подсказками. Добавлено: Вспомнил, что встречал ещё одну разновидность велосипедизма, похожую на ответ ниже. В первых 4 байтах передавался идентификатор пакета (обычный int), он передавался в обработчик пакетов, где свитчем выбирался нужный, создавался экземпляр этого пакета, в конструкторе читалось нужное количество байтов, и пакет обрабатывался. Самое смешное, что такой велосипед присутствует в одном, довольно известном и, пожалуй, знаменитом, приложении. Сообщить название продукта и производителя не могу по причине NDA. В принципе, такой метод вполне жизнеспособен, и, возможно, полностью пропитан духом ООП, но мне он кажется через чур странным... Ведь одио из основных негласных принципов ООП является отсутствие хардкода, а в таком решении размер пакета захардкожен.

Ответ 2



Нужен протокол, собственно софтверная его часть, скажем в самом примитивном исполнении так: public class MyProtocol { final String beginner="$BEGIN$"; String data; final String terminator="$END$" } Тогда вы точно будете знать где начало и где конец ваших данных и не будете зависеть от капризов сокетов.

Ответ 3



Я сталкивался с взаимодействием сервер-клиент по сокету. Там была четко разработана структура пакета, он имел строго определенный размер и разметку, первые 12 символов отвечали за назначение пакета(##-так пакет начинался, далее шла служебная информация о id пользователя и тп), далее шла информация которая предназначалась пользователю, а на конце последние два значения отвечали за целостность строки (CRC, если строка не проходила проверку, запрос повторялся 3 раза) Я к тому что нужно объединить несколько методов контроля данных Фиксировать размер пакета. Встречал несколько раз в чужом коде. Наличествует ещё и свой буфер, в который до нужного заполнения сливают данные буфера сокета, и читают нужными порциями. Стоит ли говорить, что вещь ужасно хардкодная? В пакете означают его конец, к примеру каким-нибудь сочетанием 00-FF-00-FF. Встречал 2 раза. Велосипедизм. Возможны ложные срабатывания детектора конца пакета. - Только тут надо обозначить не конец, а начало строки.

воскресенье, 26 января 2020 г.

C# Файлы, сеть, многопоточность

#c_sharp #многопоточность #сеть #fileupload #очередь


Оговорюсь сразу, использую .NET 4.0. Это в случае будущих рекомендаций в пользу async-await =)

Изначальная постановка задачи - имеется несколько однотипных приложений, функция
которых одна - записывать файлы определенного формата заранее известной длины (например,
10 минут приложение пишет файл, постоянно его увеличивая, по прошествии этого времени
оно закрывает файл и открывает новый). По завершению записи очередного файла оно отправляет
моему приложению TCP сообщение (в качестве TCP сокета использую класс Ipdaemon от ipWorks
от nSoftware) с именем файла, которое оно только что закончила писать. Размер этого
файла может составлять более полутора гигабайт. Задача моего приложения - раз в 10-15
секунд переписывать очередную порцию того, что накатало то приложение, на сетевой диск
и по получению TCP сообщения о завершении - удостовериться в том, что файлы совпадают
по содержимому.

Я написал класс для решения этой проблемы и вот его ключевой метод для перекидывания
(в среднем, его исполнение занимает от 90мс до 8000мс - StopWatch, но теоретически
может и больше):

private void ArrayCopyFile()
    {
        //http://stackoverflow.com/questions/1246899/file-copy-vs-manual-filestream-write-for-copying-file
        //http://stackoverflow.com/questions/995320/file-writeallbytes-causes-error-insufficient-system-resources-exist-to-complete#995320
        const int bufferSize = 1024*1024;
        var headerBytes = new byte[_headerManager.HeaderSize()];
        FileStream src = new FileStream(SrcFile, FileMode.Open, FileAccess.Read,
FileShare.ReadWrite);
        FileStream dst = new FileStream(DstFile, FileMode.OpenOrCreate, FileAccess.Write,
FileShare.ReadWrite);
        try
        {
            // выясним, увеличился ли исходный файл
            if (src.Length > _currPos)
            {
                // чтение заголовка файла
                src.Read(headerBytes, 0, headerBytes.Length);
            }
            else 
            {
                Trace("Исходный файл '{0}' не изменился со времени последней синхронизации",
                    SrcFile);
                return;
            }
            if (!CheckDstDirectory())
            {                    
                return;
            }
            if (_currPos > 0)
            {
                // записываем заголовок
                dst.Write(headerBytes, 0, headerBytes.Length);
                // резервируем место
                dst.SetLength(src.Length);
                // устанавливаем позицию на такую же, как у исходного файла ДО считывания
очередной порции байт
                dst.Seek(_currPos, SeekOrigin.Begin);
            }
            src.Position = _currPos;
            int bytesRead;
            byte[] bytes = new byte[bufferSize];
            while ((bytesRead = src.Read(bytes, 0, bufferSize)) > 0)
            {
                dst.Write(bytes, 0, bytesRead);
                _currPos += bytesRead;
            }
        }
        finally
        {
            src.Dispose();
            dst.Dispose();
        }
    }


Для каждого объекта этого класса создается свой объект System.Threading.Timer с интервалом
10 секунд.

Для проверки идентичности использую такой метод:

public static bool CompareFiles(string filePath1, string filePath2)
    {
        long fileLength;
        if((fileLength = new FileInfo(filePath1).Length) != new FileInfo(filePath2).Length)
            return false;
        bool filesAreEquals = true;
        const int size = 1024*1024; //0x1000000;
        int countIteration = (int)Math.Ceiling(fileLength / (double)size);
        Parallel.For(0, countIteration, x =>
        {
            if(!filesAreEquals) return;
            var start = x * size;
            if (start >= fileLength) return;
            int realSize = (int) (x == countIteration - 1 ? fileLength - start : size);
            using (FileStream file = File.OpenRead(filePath1))
            using (FileStream file2 = File.OpenRead(filePath2))
            {
                var buffer = new byte[realSize];
                var buffer2 = new byte[realSize];
                file.Position = start;
                file2.Position = start;
                int count = file.Read(buffer, 0, realSize);
                file2.Read(buffer2, 0, realSize);
                for (int i = 0; i < count; i++)
                    if (buffer[i] != buffer2[i])
                    {
                        filesAreEquals = false;
                        return;
                    }
            }
        });
        return filesAreEquals;
    }


После приемки TCP сообщения оно помещается в очередь:

class QueueTasks : IDisposable
{
    private readonly Queue _tasks = new Queue();
    readonly object _syncObj = new object();
    private readonly AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
    private readonly ManualResetEvent _exitEvent = new ManualResetEvent(false);
    private bool _isRunning;

    public bool IsRunning
    {
        get { return _isRunning; }
        private set
        {
            _isRunning = value;
            if(!_isRunning) OnQueueTasksStopped();
        }
    }

    public delegate void QueueTasksStoppedEventHandler(object sender);
    public event QueueTasksStoppedEventHandler QueueTasksStopped;
    protected virtual void OnQueueTasksStopped()
    {
        var handler = QueueTasksStopped;
        if (handler != null) handler(this);
    }

    public delegate void TaskReceivedEventHandler(object sender, T eventArgs);
    public event TaskReceivedEventHandler TaskReceived;
    protected virtual void OnTaskReceived(T eventArgs)
    {
        var handler = TaskReceived;
        if (handler != null) handler(this, eventArgs);
    }

    public void Stop()
    {
        _exitEvent.Set();
        _autoResetEvent.Set();
    }

    public void Start()
    {
        if(IsRunning) throw new InvalidOperationException("Очередь задач уже работает");
        IsRunning = true;
        _autoResetEvent.WaitOne();
        _exitEvent.WaitOne();
        new Thread(Work) { Name = "Очередь задач" }.Start();
    }

    public void Add(T data)
    {
        SafeAdd(data);
    }

    void SafeAdd(T data)
    {
        lock (_syncObj) _tasks.Enqueue(data);
        _autoResetEvent.Set();
    }

    T SafeRemove()
    {
        lock (_syncObj)
            if (_tasks.Count > 0)
                return _tasks.Dequeue();
        return default(T);
    }

    void Work()
    {
        while (!_exitEvent.WaitOne(0, false))
        {
            _autoResetEvent.WaitOne();
            while (_tasks.Count != 0)
                OnTaskReceived(SafeRemove());
        }
        IsRunning = true;
    }

    public void Dispose()
    {
        Stop();
    }
}


На событии из этой очереди я анализирую список текущих обрабатываемых файлов, если
нахожу объект класса с именем файла, который совпадает с сообщением, я останавливаю
внутренний таймер для него, проверяю, увеличился ли исходный файл, и если да, докопирую
оставшееся.

Теперь, после всей этой возможно неинтересной лабуды, возможно уже решавшейся и не
раз, задаю вопрос:

Если файлов больше 100, то в очереди начинают копиться сообщения о завершении/начале
записи файлов. Серверная машина, на которой этот софт запускается, имеет 8 ядер чистого
интела и 32 гб оперативной памяти. Пиковая загрузка процессора не выше 80%, оперативная
память - занято около 2-3 гигабайт. Загрузка на сетевом адаптере - не более 55% от
гигабитной сети. Сетевой диск - SSD. В каком месте мое приложение, перекидывающее файлы,
можно и нужно оптимизировать?
    


Ответы

Ответ 1



Parallel.For(0, countIteration, x => Параллельное чтение файлов - это почти всегда плохая идея. Просто читай их в одном потоке последовательно достаточно крупными кусками. И нет смысла каждый раз создавать новый буферный массив - создай по одному на файл и используй. int count = file.Read(buffer, 0, realSize); file2.Read(buffer2, 0, realSize); for (int i = 0; i < count; i++) А это вообще на баг похоже. Stream не обязан прочитать ровно столько байтов, сколько ты ему передал, поэтому Не факт, что файлы одинаковы, если твоя функция так говорит Например, могли сравниться только префиксы блоков. Не факт, что файлы различны, если твоя функция так говорит Например, из первого файла было прочитано больше, чем из второго.