Задать вопрос
  • Зачем нужно знать о сетевой модели OSI?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Модель OSI, это не конкретная "запчасть", которая может использоваться или не использоваться. Это основополагающий принцип того, как нужно думать о любом стеке любых протоколов, под каким углом на него смотреть )) Она потому и называется открытой моделью межсистемного обмена, (а не паттерном построения стека протоколов), что дает наиболее общую картину того, какие у протоколов в стеке могут быть характерные роли, и предлагает принцип, как это можно структурировать для понимания их взаимодействия друг с другом. И ее не нужно заучивать, ее нужно просто понять, сам принцип, и потом использовать это понимание для понимания других, уже конкретных вещей.
    Ответ написан
    2 комментария
  • Как вывести те поля, где один или два слова?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Если нужен велосипед, то "одно или два слова" означает, "количество пробелов (без учета ведущих и замыкающих) < 2"
    А вообще, в Оракле для таких вещей с незапамятных времен есть REGEXP_LIKE.
    Ответ написан
    Комментировать
  • Работа с объектами в java?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Принципиальная ошибка в понимании, видимо, заключается в формулировке "затем появляется"... Он появляется не "затем" - декларации обоих классов "появляются" во время написания кода и, соответственно, известны компилятору (compile time). А вот объекты, например, в результате выполнения строки A a1 = new A(); появляются во время работы программы (run time). Понимание этой разницы фундаментально важно!

    А дальше все просто и становится на свои места. В строке A a = new B(); (на которую компилятор, кстати, будет ругаться) происходят сразу две вещи: во-первых, создается экземпляр класса B, во-вторых, он приводится по типу к классу А (что возможно, ибо B унаследован от А, и значит, имеет, как минимум, все те же члены класса) и ссылка на него присваивается переменной типа A. Компилятор код проглотит, но будет ругаться именно на то, что это приведение типа происходит неявно. Правильнее было бы указать его явно, вот так: A a = (А) new B(); Если бы В не был унаследован от А, компилятор выдал бы в этом месте ошибку и ничего бы не скомпилировал.

    Чтоб убедиться, правильно ли Вы понимаете это дело, попробуйте теперь ответить на следующий вопрос: я написал, что "B унаследован от А"... Что это конкретно значти и когда это наследование "происходит"?

    Последний вопрос, это про полиморфизм... почитайте вот тут: Почему полиморфизм так работает?
    Ответ написан
    Комментировать
  • С какой стороны подступиться к JAVA EE?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Последовательность изучения по этапам:

    Этап первый и решающий, на котором обучаюшийся осознает, что же именно называется JЕЕ (что речь не столько о конкретной версии каких-то бинарников, которые можно загрузить с сайта Оракла, если случайно кликнуть не на ту кнопку, а о стеке спецификаций, для каждой есть, как минимум, несколько имплементаций и т.д.)
    и по результатам определяется, с чего будет начинать, в свете свалившихся задачь. Скорее всего, начать придется с того, что такое контейнеры, в частности CDI, и провайдеры, в частности persistence API, он же JPA, он же ORM (что это такое, что называют application server, а что servlet-контейнером, или, грубо, в чем разница между, например, Wildfly и Tomcat, каким боком к ним относится Hybernate и нафига придумали Spring), а также, что такое модули и профайлы. Понимание принципиальной архитектуры JEE, хотя бы поверхностное - основа, без которой любое дальнейшее обучение будет бесполезным бубнением непонятных мантр.

    Этап второй, на котором обучающийся выбирает конкретную JЕЕ секту, вступает в нее и переписывает квартиру на имя гуру. Да, да - в JЕЕ все точно, как в жизни. Спецификация одна, но "самых правильных" имплементаций, разумеется, море... С какой-нибудь из них придетя начать (возможно, свалившиеся задачи уже как-то конкретизируют выбор). В любом случае, этап заканчивается загрузкой и установкой (сначала локальной, чтоб потыкать пальчиком, потом на серверах) какого-нибудь сервера/сервлет-контейнера, сервера БД и деплоя и запуска первого HelloWorld JЕЕ приложения по туториалу и с помошью большого количества такой-то матери (ибо придется разбираться с конфигурациями, дескрипторами, правами доступа и прочими настройками, которые все совершенно очевидны, когда уже понял, но похожи на магию, когда наступаешь на них впервые). На этом этапе самый главный вопрос, "почему именно оно заработало".

    Этап третий, наиболее драматический, на котором вопрос "а нафига оно вообще все нужно" может довести обучаюшегося до нервного срыва, когда он пытается "по-быстрому" допилить только что заработавший HelloWorld до нужного ему функционала. На этом этапе вспоминаются всякие JMS, JAX-RS, JAAS и прочие непонятные вещи, мелькавшие на первом этапе, ренее "маловажные нюансы" языка, вроде ClassLoader или сериализации, вдруг оказываются ключевыми и т.д. и т.п. Это наиболее важный и долгий этап обучения. Его можно считать пройденным, когда: А. разросшийся до размеров слона с одной ногой и тремя хоботами HelloWorld сносится, т.к. приходит понимание, что в JEE нельзя просто взять и от балды допилить... даже если кажется, что можно, расплата все равно придет. Б. перепробованы разные базы данных, разные имплементации и апдейты каких-то спецификаций, разные IDE и плагины к ним, и все бесполезно - нигде, даже в платных тулзах нет кнопки "сделать все феншуйно", и, наконец, В. обучающийся понимает, что вся эта ЕЕ хрень придумана с одной единственной целью - предотвратить использование сделанного "так, чтоб как-нибудь заработало", оставив только "сделанное правильно". Победить в этой битве, конечно, нельзя, но зато можно долго и интересно бороться разными хаками, эзотерическими фреймворками и вплоть до инструментализации байткода... предела фантазии нет. В этом и заключается суть обучения JEE - понять, как делать правильно, а как - себе дороже.

    Следующий этап уже, собственно, к обучению не относится - это практика. На нем выжившие начинают с нуля строить архитектуру приложения, выбирать решения в рамках предлагаемого EE набора технологий, постоянно задумываясь над масштабированием, отказоустойчивостью этих решений и т.д. и т.п. Основная мысль на этом этапе: "блин, как я вообще раньше мог делать по-другому"...
    Ответ написан
    5 комментариев
  • Что такое область видимости бина в jsp?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Да, примерно так... вот подробнее.

    На самом деле экземпляры, как таковые, создаются и уничтожаются автоматически, самим JSP. Мы не пишем в своем коде new MyBean(), а просто говорим, что хотим вот тут заюзать экземпляр вот такого класса. А который экземпляр это конкретно окажется, и нужно ли его создавать или он уже был созадан в этой области видимости, зависит, в контексте какой страницы, запроса, сессии, или даже которого запуска нашего приложения мы находимся... да-да! Экземпляры области видимости Application уничтожаются при перезапуске приложения. Соответственно, Page после покидания страницы, Request - после отработки каждого отдельного запроса, а Session - после закрытия сессии. Об этом заботится JSP.
    Ответ написан
    Комментировать
  • Как получить дату начала и конца предыдущей недели?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    import java.util.Locale;
    import java.time.LocalDate;
    import java.time.temporal.WeekFields;
    import java.time.DayOfWeek;
    import static java.time.temporal.TemporalAdjusters.previousOrSame;
    import static java.time.temporal.TemporalAdjusters.nextOrSame;
    
    public class Main {
        
        /**
         * Determines first and last day of previous, current or following week from
         * provided date according to the provided locale.<br/>
         * <br/>
         * <strong>NOTE</strong>: Although international standard ISO 8601 defines Monday as a first
         * day of the week, several countries, including the United States, Canada,
         * and Australia consider Sunday as the start of the week, and several other
         * countries starts the week from Saturday.
         * 
         * @param fromDate from which date the week offset should be calculated
         * @param weekOffset offset in whole weeks, negative - previous, 0 - current, positive - following weeks 
         * @param locale locale defining which day should be considered a first day of week 
         * @return array of length 2, containing the dates of the first and last day of the week
         */
        private static LocalDate[] getLocalizedWeekBoundary(LocalDate fromDate, long weekOffset, Locale locale) {
    
            LocalDate[] result = new LocalDate[]{null,null};
            
            DayOfWeek localizedFirstDayOfWeek = WeekFields.of(locale).getFirstDayOfWeek();
            DayOfWeek localizedLastDayOfWeek = localizedFirstDayOfWeek.plus(6L);
            
            try{
                LocalDate shiftedWeekDate = fromDate.plusWeeks(weekOffset);
                result[0] = shiftedWeekDate.with(previousOrSame(localizedFirstDayOfWeek));
                result[1] = shiftedWeekDate.with(nextOrSame(localizedLastDayOfWeek));
            } catch (Exception ex){
                // Just add a bit more explanation for the possible RuntimeException, 
                // which may be thrown if the provided fromDate/weekOffset combination 
                // cannot be calculated. 
                throw new IllegalArgumentException(String.format("Shift of provided date by %d week(s) not supported!", weekOffset), ex);
            }
            
            return result;
        }
    
        public static void main(String[] args) {
    
            for(Locale locale : Locale.getAvailableLocales()){
                if(! locale.getDisplayCountry().isEmpty()){
                    doTest(locale);
                }
            }
        }
        
        private static void doTest(Locale locale){
            
            LocalDate[] boundary;
            
            String separator = Locale.getDefault().equals(locale) ? 
                    "= = = = = = = = = D E F A U L T = = = = = = = ="
                  : "- - - - - - - - - - - - - - - - - - - - - - - -";
    
            System.out.printf("%n%s%nIn: %s (%s)%nfirst day of week is: %s%n", separator,
                    locale.getDisplayCountry(), locale, WeekFields.of(locale).getFirstDayOfWeek());
            
            LocalDate fromDate = LocalDate.now();
            for (int shift = -1; shift < 2; shift++) {
                boundary = getLocalizedWeekBoundary(fromDate, shift, locale);
                System.out.printf("Shift %+2d => first: %s - last: %s%n", shift, boundary[0], boundary[1]);
            }
        }
        
    }


    Чтоб предупредить вопрос, зачем нужны такие подскоки: Веселые картинки
    Ответ написан
    Комментировать
  • Какие артефакты должны быть у объектно-ориентированного анализа?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Ок с этим все понятно.


    Если с этим все понятно, то не совсем понятно, что же тогда непонятно... В зависимости от того, зачем его, этот анализ, проводят, на выходе может быть все, что угодно - от приказа об увольнении архитектора и вплоть до проработанной модели структурных и поведенческих аспектов разрабатываемой системы, например, в SysML/UML и/или текстовом описании... а может быть и просто идея, как можно взломать эту систему. Короче, как любой прочий анализ, он выделяет элементы для последующего синтеза того, чего нужно ))
    Ответ написан
    Комментировать
  • Правильно ли я создал sql запрос?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Нет, запрос сделан неправильно! Он, дополнительно к тому, что требуется, выберет еще и пользователей, которые написали комментарий, даже если их собственные статьи никто не комментировал... не говоря уже о том, что если нет явной необходимости аггрегирования полей в группе, то использование GROUP BY там, где можно обойтись DISTINCT - дорогое удовольствие (почему - объясню дальше, а пока, просто для сравнения, его план и "стоимость"):
    5ab3f036b072d356066942.png
    Чтобы просто получить нужный результат, его, конечно, можно тупо дополнить еще одним JOIN с article_comment_association, но это все еще очень плохо: во-первых, JOIN с таблицей комментариев там просто лишний, во-вторых, GROUP BY - все то же разбазаривание ресурсов:
    5ab3f0802b299318193006.png
    Вот, для сравнения, стоимость DISTINCT vs. GROUP BY:
    5ab3f08c07b85920446589.png
    (Все эти неправильные варианты приводить не буду, чтоб их случайно не скопипейстили в систему управления ядерным реактором!)

    В этом смысле вариант, предложеный Rsa97 , уже лучше, т.к. дает правильный результат.
    SELECT name FROM users
      WHERE id IN (
        SELECT user_id FROM article
          WHERE id IN (
            SELECT article_id FROM article_comment_association
          )
      );

    Однако, использование subquery в таком порядке, действительно, не позволяет использовать distinct:
    5ab3f109468d6235394789.png
    Фишка в том, что subquery, как правило, создают временную таблицу, обычно, в памяти, но если ее мало, то и на диске. Так что, если есть возможность заменить их на JOIN (а она есть почти всегда!), это нужно делать, не стесняясь.

    А вот феншуйная (она же - правильная, легко читаемая, очевидная и эффективная) версия запроса:
    SELECT distinct users.name from users
      INNER JOIN article ON (article.user_id = users.id)
      INNER JOIN article_comment_association ON (article.id = article_comment_association.article_id)

    ... и ее план:
    5ab3f135365b0576447042.png
    Мораль истории: в реляционной базе данных самый прямой путь к нужному результату, как правило, оказывается наиболее эффективным. Как общее правило - начинать нужно с самого большого множества записей, исключая за раз как можно больше ненужного, и давая оптимизатору использовать индексы.
    Ответ написан
    3 комментария
  • Почему wildfly не работает на нужном мне порту?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Это два РАЗНАХ порта! 9990 для администрирования, а на 8080 стандартно байндится веб-коннектор, т.е. тот, через который пользователь будет получать доступ к веб-прилиожению. В Идее ничего не нужно менять - она изначально сама знает правильные нужные порты сервера.

    Exception в логе сервера говорят всего лишь о том, что у процесса нет прав на запись в ПАПКЕ (/opt/wildfly/standalone/log/), где он должен писать логи. Процесс (Идея и, соответственно, JVM, в которой она запускает Wildfly) стартуют от имени пользователя alex, который в Убунте стандартно не может вот так вот просто писать в /opt, что есть умно и правильно. Соответственно, есть два варианта решения.

    1. Инстанцию WIldfly для разработки развернуть в папке, к которой у пользователя есть доступ на запись, например, в /home/alex/wildfly . (В /opt сервер устанавливается по умолчанию, т.к. предполагается, что он будет использоваться, как боевой).

    2. Перенаправить логи сервера туда, где им, собственно, место в продакшен, например, в /var/log/...

    Который из путей выбирать, решайте сами. Второй вариант, теоретически, более правильный, но т.к. доступ на запись к логам - далеко не единственный аспект настройки безопасности, там дальше еще много чего полезет. Так что для того, чтоб начать знакомство с, собственно, разработкой JEE приложения, первый вариант проще и эффективнее. Например, эту рабочую инстанцию Wildfly всегда можно прибить, заменив чистой копией, чтоб убедиться, что приложение деплоится правильно само по себе, без всяких когда-то случайно сделаных и потом успешно забытых допиливаний сервера.
    Ответ написан
    1 комментарий
  • Можно ли JMS использовать с TomCat?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Идея сделать "общение между пользователями" на сервлетах и JMS, сама по себе, ни о чем не говорит. Сервлеты и JMS - это не способ сделать такое, а просто части JEE, которые (наряду с другими) можно для этого использовать... а можно вообще не использовать JEE, и сделать то же самое на любом другом стеке (Spring, NodeJS, PHP, ASP... да на чем угодно! ), или сделать это на основе других частей JEE. Как лучше и правильнее - зависит только от задачи.

    Но если вдруг задача в том, чтоб покопаться именно с JEE, то в двух словах: сервер Tomcat - это одна, конкретная реализация вебконтейнера (сервлеты). Это только часть JEE. JMS - это другая часть, а еще там множество других частей, и все они, разумеется, совместимы и их реализации можно прикрутить друг к другу с большими или меньшими усилиями. К Tomcat конечно же можно прикрутить JMS, или можно взять сервер "побольше", в котором уже собраны все нужные части JEE, например Wildfly (бывший JBoss). В нем будет и то, и другое, и еще много чего, возможно, даже очень нужного для этой задачи: вебсокеты, DI, persistence, возможно и JSF, и аутентификация...

    Короче, вариантов, как это можно сделать, море, но прежде, чем в него нырять и искать какие-то конкретные примеры не пойми чего, рекомендую тщательнее порыться в интернете и разобраться, что есть что в JEE, определиться, что из этого и зачем конкретно нужно для конкретной задачи... и нужно ли вообще - чтоб не получилось из пушки по воробьям.
    Ответ написан
  • Почему текст выводится 3 раза?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Потому, что:
    А. в программе написано именно так делать, и
    Б. эта программа выполняется под Виндой
    (на Линуксе было бы только два раза).

    Подробности
    Метод read(), сам по себе, читает только один байт из входного потока, если он там есть. Но этот поток к нему попадает только после завершения ввода в него символов, т.е. когда в нем оказывается признак конца потока, которым является конец строки.

    Когда на клавиатуре вводят, например, "а" [Enter], в поток попадают три байта:
    "а" (=97)
    [CR] (=13)
    [LF] (=10)

    Последние два, [Возврат каретки] и [Перевод строки] под Виндой и означают традиционно тот самый "конец строки", после которого метод начинает читать, a под Линуксом это был бы только один байт 10. А дальше программа сравнивает каждый из них (разумеется, предвaрительно приведенный по значению к char) с "q" (=113), и, т.к. ни один из них не равен этому значению, уходит на новую итерацию.

    Вот так станет понятнее, что и почему там происходит:
    public static void main(String[] args) throws Exception {
            char ch;
            do {
                System.out.println("Press a key followed by ENTER: ");
                ch = (char) System.in.read();
                System.out.println("Entered: '" + ch + "' (=" + (int)ch + ")");
            } while (ch != 'q');
        }

    Кстати, ничто не мешает пользователю ввести больше одного символа до того, как он нажмет Enter... попробуйте сами, а потом подумайте, как исправить программу, чтоб она делала именно то, что от нее ожидается ))
    Ответ написан
    Комментировать
  • Высокоуровневый язык программирования?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Потому, что "высоко-/низко-уровневый" это просто условная и достаточно относительная классификация языков по одному конкретному качеству - по уровню абстракции, предоставляемой языком его пользователю. А когда всплывает слово "абстракция", обязательно нужно задуматься над тем, что от чего абстрагируется. В данном случае речь идет об абстрагировании конструкций языка от среды выполнения программы, написаной на этом языке. Например, во всех этих ЯВУ есть такие абстракци, как именованная переменная, тип данных, конструкции управления потоком выполнения или вызов функций системы/стандартных библиотек и т.д. Мы просто пишем int а = 3; или while(flag == true)..., а обо всем остальном заботится язык. Для сравнения, в ассемблере (низкий уровень) нам приходится иметь дело с конкретными регистрами, битами, адресами и jump-ами, и никакой среды, которая пришла бы нам на помощь, там тоже нет. В этом смысле уровень абстракции того же С намного выше.

    Классификация эта (как и любая другая) - условная, т.к. если по этому признаку сравнить, например, те же Яву или Шарп с теми же C++ или Паскаль, то можно бы было сказать, что уровень абстракции первых "несколько выше" - между программой на первых языках и "средой" есть еще промежуточный уровень (байткод/IL), а программы на вторых компилируются прямо в инструкции конкретного процессора. Только смысла в таком утверждении уже не так много, и для указания на эти качества языков проще и полезнее классифицировать их как "компилируемые в инструкции виртуальной машины" и "компилируемые в инстрикции процессора".

    И, наконец, сортировка массива - это уже совсем из другой оперы. К языку тут (если вообще!) относится только абстракция "массив". В большинстве языков есть такое понятие, как стандартная библиотека (JDK, stl, те же модули в пыхе и т.д.). Функции вроде сортировки массива, предоставляются не языком, а именно этой библиотекой (как правило, написанной на этом же языке и/или на более низкоуровневых). А, собственно, языком называется очень-очень маленький набор универсальных семантически однозначных конструкций, типа операторов сравнения, циклов или вызовов функций. Фактически, любой современный язык можно "выучить" за день... остаток жизни уйдет на то, чтоб научиться правильно пользоваться им и его библиотеками для написания нужных программ ))
    Ответ написан
    Комментировать
  • Как записать несколько jpg-файлов в dicom-файл?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Для multiframe примерно так:

    - создать BasicDicomObject, в заголовке которого:
    - наполнить метаданные для patient/study/series, уникальные идентификаторы и пр. лабуду,
    - не забыть выставить modality в SC (secondary capture),
    - указать фотометрические данные изображения (разумеется, они должны быть идентичны для всех вставляемых фреймов) и тайминг (количество, длительность, рекомендованный DisplayFrameRate и т.д.)

    Это будут необходимые метаданные. Для записи всей этой кухни в файл:

    - создать нужный ImageWriter, которому дать стрим для нужного файла,
    - инициировать запись последовательности (prepareWriteSequence), начав с метаданных,
    - потом продолжать записывать отдельные фреймы, при необходимости перекодируя/масштабируя изображения в нужный формат.

    Потом закрыть стрим и наслаждаться результатом.

    П.С. Про танцы с бубном вокруг кодеков, цветовых профилей и компресси с/без потерь и про то, как отправлять в PACS, распространяться не буду, т.к. если пишете в DICOM, то наверняка и сами в курсе, а если еще нет, то впереди Вас ждет много интересного и увлекательного )) Но, в любом случае, мой Вам совет - для уменьшения количества седых волос забудьте про DCM-файлы и смотрите в стророну передачи по сети... тем более, что в dcm4che очень хорошая и удобная имплементация всего, что для этого нужно. А еще там в комплекте где-то есть готовые консольные утилитки, делающие всю эту и другую магию, так что подробности можно посмотреть в их исходниках. По поводу, собственно, записи multiframe файл можно еще глянуть вот сюда.
    Ответ написан
  • Какие знаете эмуляторы для тестирования антенн?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Кроме HFSS еще, как минимум, FEKO, CST ... ну, а, вообще, конечно, нет абсолютно универсального софта - нужно выбирать метод моделирования для конкретных потребностей (вот, например, неплохой список).
    Ответ написан
    Комментировать
  • Для чего в блоке synchronized указан другой монитор (не this)?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Так и есть, причем, у обоих )) Фактически, оба конкуррируют за один ресурс rest.meal, но не "глобально", а раздельно за две разные операции с ним - в первом блоке на чтение, во втором на запись. Блоком synchronize(this) каждый из них вешает монитор на себя, любимого, выполняет чтение и начинает ждать пинка от другого. Вторым же блоком он вешает монитор на другого, выполняет запись и пинает другого. Это можно бы было написать несколько элегантнее и читабельнее с использованием более высокоуровневых абстракций из java.util.concurrent (где под капотом происходило бы почти то же самое), но суть примера, насколько я понимаю, именно в том, чтоб показать, как в такой ситуации целенаправленно синхронизировать два потока друг с другом непосредственно, так, чтоб каждый только один раз читал и один раз писал.

    Обратите также внимание на то, что никто из них не синхронизируется с, собственно, самим ресурсом, что позволяет, например, в перспективе, не блокировать без явной необходимости другие потоки, как-то связанные с этим ресурсом.
    Ответ написан
    Комментировать
  • Частота работы МК и передачи одно и то же?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Тактовая частота МК (ядра) и частота, используемая для передачи данных по какому-нибудь интерфейсу - разные вещи.

    Первая задается либо встроенным RC осцилятором (обычно, ниже максимально возможной и менее стабильна, чем от кварца), либо внешним кварцевым резонатором, а далее преобразуется делителями и/или PLL синтезаторами до нужных для конкретных блоков МК/периферии. Она означает только то, с какой скоростью ядро может выполнять отдельные инструкции или, точнее, сколько времени длится один такт (в некоторых архитектурах выполнение определенных инструкций занимает больше одного такта).

    Вторая задается, собственно, протоколом/стандартом интерфейса. Интерфейс - это не только договоренность о стартовых битах, маркерах и т.д. в передаваемых данных, но и об уровнях напряжений, видах модуляции, допустимых уровнях шумов и, в т.ч. "частотах". Только о последних принято говорить "тайминг", т.к. стандарты задают допустимую точность соблюдения временных интервалов, а уже какие для этого нужны частоты - вопрос производный. А все это, вместе взятое, принято называть интерфейсом. Кроме того, для передачи данных само понятие "частота" вторично - гораздо важнее понятие Baud rate, означающее (упрощенно!) "скорость передачи информации" по определенному протоколу, которая, согласно теореме Шеннона-Хартли, меньше или равна половине той самой реальной "частоты передаваемого сигнала"... кототрой, на самом, деле нет, как таковой. Попробую объяснить, что это значит.

    "Попадание в такт" урегулировано протоколом интерфейса и не зависит от момента, когда включили приемник или передатчик, а только от того, когда передатчик решит начать передачу. Если совсем на пальцах... В простейшем случае кто-то из них (например, передатчик) в какой-то момент времени изменяет уровень на своем выходном пине, например, с LOW на HI. К нему физически подключен входной пин приемника. Он "видит" изменение уровня и этот факт либо отлавливается программой, постоянно опрашивающей состояние этого входного пина, либо, еще лучше, изменение уровня вызывает прерывание, в коде которого принимающая программа может соответствующим образом на это отреагировать... например, принять один бит. А передатчик, тем временем, изменит HI на LOW, и потом все повторится. Минимальное расстояние во времени между такими изменениями, которые, при цифровой передаче происходят совсем не равномерно, (как, например, в радио с амплитудной модуляцией) и будет означать ту самую "частоту передачи". Но в реальности нет никакой конкретной постоянной частоты - есть импульсы разной длительности, т.е. изменения уровня напряжения с высокого на низкий и наоборот, следующие через разные промежутки времени. Так что, при цифровой передаче данных говорить можно только о теоретической максимальной частоте.

    Для того, чтоб приемник и передатчик могли стабильно соблюдать тайминг, определенный стандартом интерфейса (т.е. успевать распознать эти изменения, ничего не пропуская), их собственная тактовая частота должна это в принципе позволять, т.е. быть больше "частоты передачи данных" (если протокол реализован в виде программы для ядра, оно должно, как минимум, успеть выполнить какие-то инструкции прежде, чем может произойти следующее изменение уровня, на которое нужно будет реагировать). Иногда, особенно, в простых МК, она, кроме того, должна быть кратной этой частоте с определенным коэфициентом. Ядро МК может работать на разных тактовых частотах - вплоть до максимальной, ему, собственно, почти безразлично, на какой именно. Но т.к. большинство частот внутри (на входе счетчиков таймеров или других схемотехнических блоков) получаются из основной тактовой, то если она не будет кратной "частоте передачи", в какие-то моменты времени приемник и передатчик будут рассинхронизироваться, т.е. не успевать распознать и прореагировать на какие-то импульсы, т.к. их ядро в этот момент будет занято чем-то другим. Это, конечно, в большинстве случаев будет отловлено и исправлено самим протоколом (для этого их и придумывают), но, на практике будет означать либо медленную, нестабильную передачу, либо вообще невозможность передачи. Таким образом, для простеньких МК, если они должны работать с UART, особенно, на больших скоростях, подойдет не всякий кварц с частотой меньше или равной максимальной, а только с определенными частотами. (А если они, например, должны максимально стабильно отсчитывать календарное время без синхронизации с внешним источником точного времени, подойдет другой кварц с т.н. "часовыми" частотами...) Короче, в определении того, какая конкретно тактовая частота МК будет достаточной/необходимой в каждом конкретном случае, нет никакой магии - только простая арифметика и внимательное изучение даташитов и application notes.

    В современных МК периферия, реализующая стандартные интерфейсы (типа простых UART, USB, I2C, CAN и т.д.) давно уже отвязана от ядра. Именно для того, чтоб освободить пользователя, т.е. программиста МК, от всех этих заморочек... но "внутри" там все то же самое, только, конечно, сложнее, а в протоколах, типа Ethernet или Bluetooth, под чисто цифровым уровнем скрывается еще и навороченный физический, со всякими модуляциями и поляризациями, где понятие "частоты передачи" имеет прямой смысл... только туда без, хотя бы, поверхностных знаний физики, электро- и радиотехники, лучше вообще не соваться ))

    Однако, наличие в МК готовой периферии не исключает возможность взять и самостоятельно реализовать некоторые из этих протоколов, для которых достаточно тактовой частоты МК, в виде программы для ядра... например, для того же UART. Сделать это совсем не сложно, но совершенно необходимо для понимания их устройства. На эту тему есть тонны статей, туториалов и разжеванных примеров (от использования периферии, и вплоть до самостоятельной реализации).
    Ответ написан
    1 комментарий
  • У всех мониторов соотношение 1.7, если ширину делить на высоту?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Подробный ответ на вопрос:

    раз

    два
    Ответ написан
    Комментировать
  • Для чего нужны в CPP системные методы _exit, _open, _read, _write, _lseek, _fstat, _link, _unlink, _stat, _close, _execve, _fork, _getpid, _isatty...?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Вот интересно, для кого товарищ Стефано Оливери старался писать комментарий? Там же все черным по-английскио написано. Это - минимальная имплементация функций, которые libc ожидает от системы. Подробнее: раз, два, и уж совершенно конкретно, три. Последнее находится в три клика по ссылке из комментария ))
    Ответ написан
    1 комментарий
  • Чем отличается nat от proxy? чем отличается proxy от vpn?

    pi314
    @pi314
    Президент Солнечной системы и окрестностей
    Тот факт, что все они "гонят трафик через себя" - совершенно бесполезное обобщение, приводящее к странному вопросу. В сетях абсолютно все "гонит трафик через себя"... почему тогда не спросить, "чем отличается nat от витой пары, а она - от адаптера WiFi"? Тем и отличаются, что это разные вещи, предназначенные для решения разных задач, и "отличий" можно придумать, сколько угодно. Например, nat отличается от proxy по определению местом, где происходит магия. nat происходит на границе сети, т.е. в маршрутизатое (железном или софтовом), в то время, как proxy может находиться где угодно. Но, по сути, никто не запрещает доступаться к proxy через vpn, работающую поверх nat... в подавляющем большинстве случаев это именно так и происходит )))
    Ответ написан