LINUX.ORG.RU

Сообщения oleg_2

 

[СИ] Коварный malloc.

[СИ] Коварный malloc.

Язык СИ
ОС UNIX

По совету анонимуса и других людей осваиваю malloc.

Ниже приведена небольшая тестовая программа. Смысл
ее в том, что в функции init_test(); выделяется
память malloc-ом, там же она первично инициируется
пробным текстом, указатель на эту память при
возврате из функции передается через аргумент главной
программе (main), и далее эта память используется
в главной программе.

Как я понимаю, память выделяется в статической памяти,
а не в стеке. И, стало быть, должна быть доступна и
при возврате в main. Выдача программы, как будто,
подтверждает это:

k=init_test()=0
proba malloc(); proba malloc(); proba malloc();
proba malloc() main()

Но сомнения все-же остались. В этом и вопрос:
можно ли выделять память в функции, а потом
использовать ее вне функции?

Кто знает прошу ответить.

 

oleg_2
()

[СИ] Создать большой массив

[СИ] Создать большой массив

Ясык СИ
ОС UNIX

Не получается создать массив больше этого:
int arr[15000000];

Это 60 000 000 байт.
А нужно 500 000 000 байт.
Определен в функции main().
Segmentation fault (core dumped)

ОЗУ 4 Гб.
Вызов k=getrlimit(RLIMIT_DATA , &rlim);
дает RLIMIT_DATA: 536870912/536870912

Top дает строку
Mem: 76M Active, 2733M Inact, 257M Wired, 1264K Cache, 112M Buf, 550M Free

Существует ли способ создать большой массив?

Кто знает прошу ответить.

 

oleg_2
()

[СИ] readdir()

[СИ] readdir()

Язык СИ
ОС UNIX

Вопрос.
Что случится, если во время чтения каталога
(readdir()) этот каталог изменится?

Кто знает прошу ответить.


Пояснение откуда взялся вопрос.

Имеется самодельный копировщик каталога (сырой).
Он рекурсивно обходит дерево и копирует
всё на другой сервер. Использую функцию
readdir(). Каталог большой:
десятки тысяч файлов и общая длина
десятки Гб.

Файлы могут меняться прямо в процессе
копирования (но не слишком часто).
Какой либо синхронизации между копировщиком
и процессами, меняющими файлы, нет.
Но и требования не очень жесткие.
Достаточно скопировать цельный файл, каким он
был до изменения, или после изменения.

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

Затем еще раз эти немногие проверить на дату,
и так до полного удовлетворения.
Учитывая не частое изменение файлов, такой
алгоритм можно считать практически конечным.

Я уже было торжествовал победу, но тут сообразил,
что меняться-то могут не только файлы, но и
каталоги. И я не знаю, как поведёт себя функция
readdir() при этом. Пропустить несколько
только что созданных файлов допускается.
Не беда, если файлы скопированы, а вскоре
их удалили.
Но не случится ли тут чего похуже?

 

oleg_2
()

[СИ] структуры, массивы и sizeof().

[СИ] структуры, массивы и sizeof().

Язык СИ
ОС UNIX

Ниже приведена небольшая тестовая программа
на проверку sizeof().


#include <stdio.h>
#include <stdlib.h>

//   cd /usr/home/test3test/njx
//   gcc test_sizeof.c -o test_sizeof.cgi
//   ./test_sizeof.cgi

#define N  6

//--- структура параметров хоста ---
typedef struct  {
    int   port;
    char  host[100];
} _lin;

//-------------- main --------------

int main()

{
    _lin  lin[N];  //--- массив структур ---
    int k;

    k=funk_1(lin);
    printf("k=%d\n",k);
    exit(0);
}

//-------------- funk_1 --------------

int funk_1(_lin lin[]){
    int k;
    k=funk_2(lin);
    return(k);
}

//-------------- funk_2 --------------

int funk_2(_lin lin[]){
    int k;
    k=sizeof(lin[0].host);
    //  k=sizeof(_lin.host);
    //  k=sizeof(_lin);
    return(k);
}


Во вложенные функции передается массив lin[ ],
вернее указатель на него.
Выдача этой программы
k=100
т. е. длина массива host.
Мне как раз и нужно в нижней вложенной
функции funk_2() получить длину этого массива.

Там ещё есть закомментированная строка, которую
я тоже попробовал, но с ней не компилится.

Вопрос.
Случайность ли это или правило?
Не скомпилирует ли другой «правильный» компилятор
по другому?

Кто знает прошу ответить.

 

oleg_2
()

[СИ] Длина сектора диска

[СИ] Длина сектора диска

Язык СИ
ОС UNIX

База данных и транзакция.
Два вопроса.

Имеется файл строк, каждая строка это отдельная запись БД.
Нужно сделать транзакцию - изменить одну из этих строк.
При этом длина строки не меняется.
Должно выдерживать мягкий сбой (выключение питания).
Винт плохой и при сбое портит весь сектор (или иную минимальную порцию данных).
Значит я должен в журнале сохранить всё то, что может быть испорчено,
т. е. сектор (или секторы) содержащий эту строку.


Вопрос 1.

О длине сектора.
Как узнать длину сектора или иной порции данных,
которая может быть испорчена?

Вопрос 2.

Что если я буду для верности сохранять заведомо
большую порцию, а именнно 8 Кбайт, начало порции
кратно ей самой от начала файла.

Сработает ли такой подход?

 

oleg_2
()

[СИ] База данных

[СИ] База данных

Язык СИ
ОС UNIX

Хотелось бы написать простую специализированную
базу данных.
Под специализированной понимается:
не универсальная, для конкретного приложения.
Отсюда и ожидаемая простота.

Много чего не понимаю. Вот первая тестовая задача:

Задача 1.

Имеется файл-счетчик count.txt малой длины (100 байт).
и некая программа, время от времени наращивающая
этот счетчик.
Требуется: переделать так, чтобы при мягком сбое (отключение питания)
не потерять счетчик.

Думал - думал и ничего лучше не придумал,
кроме следующего.

Создаю два равнозначных файла-счетчика,
дублирующих друг друга.

count_1.txt
count_2.txt

Формат файла такой
count=4; st_tr=36; ks=123345
где
count=4; -основной счетчик;
st_tr=36; -вспомогательный кольцевой счетчик наращиваний,
например, после 99 следующее число 0;
ks=123345 -контрольная сумма.

Наращивание делать так:

-читаем каждый из этих файлов, проверяем контрольные суммы
и совпадение данных в обоих файлах;

Далее по одной из четырех ветвей

-если все в порядке, то изменяем данные и перезаписываем
эти два файла. Дождать, когда они окажутся на диске. Вот и всё.
-если файлы отличаются, и в одном из них правильная ks,
то восстановить, т. е. скопировать правильный в не правильный,
дождать, когда он
окажется на диске (как проверить - не ведомо), затем
нарастить счетчики в обоих файлах.
-если файлы отличаются, и в каждом правильная ks, лучшим из них
считать тот, у которого больше (по кольцу) вспомогательный
счетчик, сделать восстановление, затем нарастить оба.
-другие варианты считать не подлежащими восстановлению.

В чем я заблуждаюсь?

Кто знает прошу ответить.


 

oleg_2
()

[СИ]select и разрешение имен хостов

[СИ]select и разрешение имен хостов

Язык СИ
ОС UNIX

Продолжение темы.
На странице 811 был вопрос о select
и о разрешении имен хостов без подвисания.
Anonymous посоветовал libasyncns,
и я написал там, что все в порядке.

Я погорячился.
Мало того что сложно, так еще, как я понял,
там создается дополнительный процесс
для каждого запроса.
А это противоречит намерениям.

И мыслится подходящим делать прямые запросы
сервера DNS (из тех, что в файле /etc/resolv.conf)
через UDP-сокеты и подключать эти запросы
к центральному select-у.
Трудно только распарсить ответы DNS,
кроме самых простых.
Нет хорошего описания форматов ответов.
Пользуюсь пока этим:
http://www.crossplatform.ru/documentation/tcp_ip/glava14.php
но здесь не доходчивое и не исчерпывающее.

Не посоветует ли кто-нибудь описания получше?

 

oleg_2
()

[СИ]select и разрешение имен хостов

[СИ]select и разрешение имен хостов

язык СИ
ОС UNIX

Пытаюсь написать простой малопроцессный
сервер (однонитевой).
Малопроцессный подразумевает:
один процесс сервера обслуживает несколько клиентов.
Использую TCP-сокеты и select.
Select занимает центральное место, а все
остальное к нему прилажено.
Все функции сокетов, pipe-каналов и файлов
хорошо прилаживаются к select.
Но потребовалось разрешать имена хостов
в ip-адреса, а функция
hp=gethostbyname(serv_name);
которой я раньше пользовался,
не прилаживается.

Существует ли какой-нибудь способ
разрешения имен хостов не подвисая.

Кто знает прошу ответить.

 

oleg_2
()

СИ - структура и выравнивание

СИ - структура и выравнивание

Язык СИ
ОС UNIX

создаю структуру

typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 2 байта
DWORD bfSize; // 4 байта
WORD bfReserved1; // 2 байта
WORD bfReserved2; // 2 байта
DWORD bfOffBits; // 4 байта
} BITMAPFILEHEADER;

BITMAPFILEHEADER bfh;

всего 14 байт.

Ожидал получить sizeof(bfh)=14.
А получилось sizeof(bfh)=16,
напоминает выравнивание.

Далее предполагалось

write(fd, bfh, sizeof(bfh)); //--- заголовок file.bmp (рисунок) ---

Не вышло. Нарушен формат файла.
Пришлось выкручиваться.

Почему не получаю ожидаемую структуру?

Кто знает прошу ответить.

oleg_2
()

bind: Address already in use

bind: Address already in use

язык СИ
ОС UNIX

Имеется программа-сервер (самодельный).

При его перезапуске система не сразу
освобождает адрес локальной привязки сокета.
Вследствие этого ошибка вызова bind().
Порой не удается вновь запустить сервер
несколько минут.
Можно с этим смириться, но всё же неудобство.

Существует ли способ обойти эту трудность.

Кто знает прошу ответить.

oleg_2
()

Переменные окружения. Как избавиться?

Переменные окружения. Как избавиться?

язык СИ
ОС UNIX

Имеется сервер (самодельный).
При переносе на другую машину возникла трудность.
(FreeBSD 6.3-RC2 --> FreeBSD 7.2-RELEASE (GENERIC))

Требуется избавиться от переменных окружения
для того, что бы сформировать новые и передать их
execl-ом другим программам.
Использую функции
void unsetenv(const char *name);
int setenv(const char *имя, const char *значение, int overwrite);


Фрагмент кода:

//--- очищаем переменные окружения ---
n=0;
while(envp[0]!=NULL && n<50){
strncpy(buf,envp[0],sizeof(buf));
j=0;
while(buf[j]!=0 && buf[j]!='='){ j++;}
buf[j]=0;
unsetenv(buf);
//printf(«unsetenv(%s)\n»,buf);
n++;
}

...

//--- новые переменные окружения ---
n=setenv(«REMOTE_ADDR»,ip,1);
n=setenv(«REMOTE_PORT»,port,1);

Конец фрагмента.


На другой машине функция
unsetenv();
не срабатывает, и новые переменные окружения
добавляются к старым.

В чём тут дело?

Кто знает прошу ответить.

oleg_2
()

Вопрос по сокету-2

Вопрос по сокету-2

Язык СИ
ОС UNIX

Имеются «клиент» и «сервер» (самодельные).
Работают поверх TCP.

Фрагмент клиента:

//--- sd_client -сокет, соединенный с сервером ---

k=read(sd_client, buf, sizeof(buf));

Конец фрагмента.

Сервер на запрос клиента посылает данные,
а затем закрывает сокет close(sd_serv) на своей стороне.
При закрытом на сервере сокете (sd_serv),
на стороне клиента вызов read()
возвращает 0, и это признак конца передачи.

В штатном режиме это работает.
Но на сервере иногда случаются ошибки (не доступны
все или часть данных).

Вопрос.
Возможно ли на стороне сервера
так подействовать на сокет (sd_serv),
что бы на стороне клиента вызов read()
вернул бы -1.

Кто знает прошу ответить.


oleg_2
()

Блокировка файла (fcntl)

Блокировка файла (fcntl)

Язык СИ
ОС UNIX - Free-bsd

Нужно прервать процесс, ожидающий блокировку файла.
Процесс, ожидающий блокировку файла,
получает сигнал и почти не реагирует на этот сигнал.
Не могу понять почему.

Вот тестовая программа:



#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>

const char *f_test=«test»;
int fl_int=0, fd;


//---------------------- sigint -------------------------------------

void sigint(int n)
{
printf(«signal\n»);
//close(fd);
fl_int=1;
return;
}

//-------------------------- main -------------------------

int main()

{
int k;
pid_t pid;

fd=open(f_test,O_RDWR);
if(fd<0){ printf(«fd=open(%s)=%d\n»,f_test,fd); exit(0);}

pid=fork();
if(pid<0){ printf(«pid=fork()<0\n»); exit(0);}
if(pid==0){
signal(SIGINT, sigint);
sleep(5);
k=my_lock(fd,F_WRLCK);
printf(«k2=my_lock=%d\n»,k);
sleep(20);
exit(0);
}
if(pid>0){
k=my_lock(fd,F_WRLCK);
printf(«k1=my_lock=%d\n»,k);
sleep(10);
kill(pid, SIGINT);
sleep(10);
exit(0);
}
exit(0);
}


//------------------------------------- my_lock -----------------------------------

int my_lock(int fd,int cmd)

{
int k; struct flock lock;

lock.l_type=cmd;
lock.l_whence=SEEK_SET;
lock.l_start=0;
lock.l_len=0;
k=fcntl(fd,F_SETLKW,&lock);
return(k);
}


(Функция printf() запрещена в обработчиках сигналов,
но поскольку программа простая тестовая и от безысходности)
(состояние процессов удобно смотреть в другом окне утилитой top)


Эта программа не работает так, как я ожидал.

Ожидалось:
0 сек. -запуск программы, процесс (pid>0) блокирует файл;
5 сек. -процесс (pid==0) запрашивает блокировку файла и ждет её;
15 сек. -процесс (pid==0) получает сигнал, ожидание блокировки
прерывается. Вызов k=fcntl(fd,F_SETLKW,&lock); возвращает -1;

На самом деле работает так:
0 сек. -запуск программы, процесс (pid>0) блокирует файл;
5 сек. -процесс (pid==0) запрашивает блокировку файла и ждет её;
15 сек. -процесс (pid==0) прерывается сигналом
(обработчик пишет слово signal), и снова,
как ни в чем не бывало дожидает блокировку.
Дождавшись получает её.

fd -объявлен глобальным потому, что если раскомментировать строку
//close(fd);
в обработчике, то это выход из положения.

Хотелось бы понять почему не работает как задумано.
Кто знает прошу ответить.

oleg_2
()

вопрос о правах доступа.

вопрос о правах доступа.
язык СИ.
ОС UNIX.

Пытаюсь написать прогрмму, которая должна
корректно работать с правами доступа к файлам (ftp-сервер).
Не получается, и не могу понять почему.

краткое содержание:

//--- родительский процесс (root) ---

pid=fork();

if(pid==0){

//--- "дерутизация" ---

pwd=getpwnam(user);
gid=pwd->pw_gid;
uid=pwd->pw_uid;
n=setgid(gid);
n=setuid(uid);

//--- здесь тестовая распечатка ---
//--- uid, gid, euid, egid - всё как ожидалось (user) ---

fp=fopen(file,"r");

//--- ожидал, что файл будет доступен или недоступен
// в соответствии с правами user ---

//--- обработка файла ---

exit(0);

}

Вопреки ожиданиям, программа работает так:

исходный родительский процесс:
uid=0; gid=0

процесс после форк и дерутизации:
uid=1002; gid=1002
euid=1002; egid=1002

Варианты файла:
файл: uid=1004; gid=1004 - работает как ожидалось, т. е. на правах других пользователей.

файл: uid=1001; gid=0 - работает как если бы процесс имел gid=0, т. е. на правах группы.


Кто знает прошу ответить.

oleg_2
()

вопрос по сокету

Язык СИ
ОС UNIX
Пытаюсь написать сервер
подобный описанному сдесь
http://rsdn.ru/article/unix/sockets.xml (листинг 6).

Машина имеет несколько ip-адресов.
Прием запросов со всех имеющихся ip-адресов.
Вопрос: возможно ли узнать на какой ip-адрес
из них пришел запрос клиента?

Краткое содержание:

struct sockaddr_in addr;
struct sockaddr_in addr1;

//--- слушающий сокет sd0 ---
sd0 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

//--- привязать все имеющиеся ip-адреса ---
addr.sin_addr.s_addr = INADDR_ANY;
k=bind(sd0, (struct sockaddr *)&addr, sizeof(addr));
listen(sd0, 5);
while(1){
sd=accept(sd0, (struct sockaddr *)&addr1, &k);
//--- при возврате из accept
// структура addr1 содержит ip-адрес клиента ---

обработка запроса

}

Кто знает, прошу ответить.

oleg_2
()

RSS подписка на новые темы