Предыдущая | Оглавление | Следующая |
Если на твоей системе их нет, то скорее всего они тебе не нужны. Почитай в справке. Под Windows единственный заголовок, который нужно подключить, это #include <winsock.h>.
Вызови setsockopt() с параметром SO_REUSEADDR для слушающего сокета. Пример есть в разделе о bind() и разделе о select().
Используй netstat. Подробнее написано в man, но ты получишь хорошие результаты, написав просто:
$ netstat |
Единственная проблема - с определением, какие программы с ними связаны. :-)
Используй команду route (в каталоге /sbin на системах Linux) или команду netstat -r.
К счастью, практически все машины поддерживают "виртуальное сетевое устройство", которое сидит в ядре ОС и притворяется сетевой картой. (В таблице маршрутов этот интерфейс называется "lo".)
Допустим, твоя машина называется "goat". Запусти клиент в одном окне и сервер в другом. Или запусти сервер в фоне ("server &") и клиент в том же окне. Можешь вызывать client goat или client localhost (так как "localhost" наверняка определен в твоем /etc/hosts) и клиент будет работать с сервером без сети!
А в коде вообще не нужно ничего менять! Обалдеть!
recv() в таком случае вернет 0.
На все вопросы по "сырым сокетам" есть ответ в книгах В. Ричарда Стивенса "Сетевое программирование под UNIX". Посмотри в списке книг.
Удали Windows и поставь Linux или BSD. };-). На самом деле лучше почитай замечания о Windows.
Ошибки компоновщика связаны с тем, что системы Sun не прилинковывают автоматически библиотеки сокетов. Почитай замечания о Solaris/SunOS.
Сигналы заставляют блокирующие системные вызовы возвращать -1, сохраняя EINTR в errno. При установке обработчика сигнала с помощью sigaction(), можно указать флаг SA_RESTART, который должен перезапустить системный вызов после прерывания.
Тем не менее, это почти никогда не работает.
Мое любимое решение - с применением оператора goto. Это бесит профессоров, так что вперед!
select_restart: if ((err = select(fdmax+1, &readfds, NULL, NULL, NULL)) == -1) { if (errno == EINTR) { // нас прервал сигнал, перезапускаем goto select_restart; } // обрабатываем настоящую ошибку: perror("select"); } |
Конечно совсем не обязательно использовать goto в этом случае, можно использовать и другие структуры. Но по-моему goto выглядит гораздо чище и элегантнее.
Используй select()! Он позволяет указать время ожидания тех дескрипторов, из которых ты собираешься читать. Можно и упаковать все в одну функцию, вроде:
#include <unistd.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> int recvtimeout(int s, char *buf, int len, int timeout) { fd_set fds; int n; struct timeval tv; // указываем набор сокетов FD_ZERO(&fds); FD_SET(s, &fds); // указываем таймаут tv.tv_sec = timeout; tv.tv_usec = 0; // ждем данных или таймаута n = select(s+1, &fds, NULL, NULL, &tv); if (n == 0) return -2; // таймаут! if (n == -1) return -1; // ошибка // получены данные, вызываем recv() return recv(s, buf, len, 0); } . . . // Пример использования recvtimeout(): n = recvtimeout(s, buf, sizeof(buf), 10); // ждем 10 секунд if (n == -1) { // ошибка perror("recvtimeout"); } else if (n == -2) { // таймаут } else { // получили данные } . . . |
Обрати внимание, recvtimeout() возвращает -2 при таймауте. Почему не 0? Если ты помнишь, recv() возвращает 0 если удаленная сторона закрыла соединение. Так как -1 уже значит "ошибка", мне пришлось использовать -2.
Можно использовать SSL (secure sockets layer, уровень безопасных сокетов), но они выходят за пределы этого руководства.
Если же ты реализуешь свою собственную систему сжатия или шифрования, тебе нужно всего-навсего пропускать через нее данные на входе и выходе.
И наоборот:
Точно так же выполняется сжатие/распаковка. Можно делать и сжатие, и шифрование! Только сначала нужно сжимать, а потом уже шифровать. :)
Пока клиент выполняет шаги в противоположном порядке, проблем не будет, сколько бы шагов не было в процедуре отправки.
Так что просто найди место между чтением данных и их отправкой в сеть (с помощью send()), и вставь туда код шифрования.
Относится. Почитай раздел о socket(), если интересно.
Для простоты, пусть клиент соединяется, отсылает строку и отсоединяется (т.е. выполняет только одну посылку.)
Псевдокод клиента:
А сервер получает и выполняет данные:
Осторожно! Давать возможность клиенту выполнять любые команды - значит, предоставлять удаленный доступ к системе. Что произойдет, если клиент пошлет "rm -rf ~"? Он удалит все файлы в твоем профиле, вот что!
После чего ты будешь умнее и ограничишь доступ клиента несколькими безопасными утилитами, например утилитой foobar:
if (!strcmp(str, "foobar")) { sprintf(sysstr, "%s > /tmp/server.out", str); system(sysstr); } |
Это все еще небезопасно, ведь клиент может послать "foobar; rm -rf ~". Лучше написать функцию, которая поставит "\" перед всеми не алфавитно-цифровыми символами (включая пробелы, если нужно) в аргументах команды.
Безопасность - очень важная штука, когда сервер выполняет то, что ему говорит клиент.
Скорость ограничивается MTU - максимальным объемом данных, который физический носитель может передать за раз. На локальной машине виртуальная сеть может спокойно передать 8K и даже больше. Ethernet передает по 1500 байт, включая заголовок. Модемное соединение передает по 576 байт (опять-таки с заголовком), так что ограничение еще меньше.
Конечно, нужно наверняка передавать все данные. (Посмотри на функцию sendall().) И так же вызывать recv() в цикле, пока не получишь все данные.
Почитай раздел Применяем инкапсуляцию, где объясняется, как получать пакет за несколько вызовов recv().
Если они где-то и есть, то в библиотеке POSIX, которая может поставляться с компилятором. Поскольку у меня нет Windows, я не могу ответить на этот вопрос, но, помнится, у Microsoft есть уровень совместимости с POSIX и там должна быть fork(). (И, может, даже sigaction.)
Поищи "fork" или "POSIX" в справке по VC++.
Если это никак не работает, забудь про fork() и sigaction и замени их виндовским эквивалентом: CreateProcess(). Я не знаю, как ее использовать - она берет кучу аргументов. Посмотри в справке по VC++.
Посмотри проект OpenSSL.
Увы, назначение файрвола - запретить людям соединяться с машинами за файрволом, так что такая возможность расценивается как брешь системы безопасности.
Но это еще не конец. Зачастую можно все равно соединиться через файрвол, если он использует NAT или еще что-то в этом роде. Разрабатывай программы так, чтобы ты сам начинал соединение, и все будет в порядке.
Если этого недостаточно, попроси админов выделить тебе дырку в файрволе, чтобы с тобой могли соединяться.
Учти, что дырка в файрволе - это не шутки. Убедись, что вредители не получат доступа к внутренней сети. Если ты только начинаешь, разработка безопасных программа намного сложнее, чем тебе кажется.
И не делай так, чтобы твой сисадмин ругал меня. ;-)
Предыдущая | Оглавление | Следующая |