Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.79/58: Рейтинг темы: голосов - 58, средняя оценка - 4.79
0 / 0 / 0
Регистрация: 26.02.2012
Сообщений: 26

Сокеты, одновременная работа с несколькими клиентами !!!

26.02.2012, 21:31. Показов 12236. Ответов 52
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет, совсем запутался с сокетами. Нужно такое приложение, которое будет обрабатывать сразу много клиентов. Причем в такой схеме может возникнуть ситуация, что сервер может начать работать с одним клиентом, потом начать со вторым в другом потоке, закончить работу со вторым и вернуть ему результат, и потом закончить работу уже с первым и вернуть ему свой результат.
Какой тип сокетов мне использовать?

Схема работы сервера такая:
он должен получать все сообщения от множества клиентов и добавлять их в очередь, далее после каждого добавленного сообщения в очередь вызывается функция на проверку есть ли свободные потоки, и если есть то передать свободному потоку id клиента и его запроса, далее этот поток должен обработать запрос, вернуть клиенту результат, снова вызвать функцию на проверку очереди и самозавершиться. Если с потоками разобрался, то с сокетами беда вообще.

Возможно существует какой-нибудь простой класс для сокитов под линукс, чтобы можно было создать сокет, добавить к нему функцию обрабатывающую событие поступления нового сообщения от клиентов, и функцию ответа клиенту по его id номеру.

В си новичок, просьба не пинать. Спасибо!
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
26.02.2012, 21:31
Ответы с готовыми решениями:

Работа QTcpServer с несколькими клиентами
Имеется сервер который напрямую общается с бд(sqlite). К нему одновременно и постоянно подключаются и отключаются(после завершения работы с...

Одновременная работа с несколькими ST-LINK/V2 в IAR
Отлаживаю 3 отдельных устройства, который работают в одной связке. Соответственно запущено 3 IAR-a, в которых правится разный код. Прошить...

сессии и одновременная работа под несколькими пользователями
Возникла необходимость сделать чтобы с сайтом можно было работать под несколькими зарегестрироваными пользователими одновременно в...

52
0 / 0 / 0
Регистрация: 26.02.2012
Сообщений: 26
28.02.2012, 16:39  [ТС]
Студворк — интернет-сервис помощи студентам
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
 
$fp = fsockopen("127.0.0.1", 44550, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";
} else {
    $out = "SELECT ALL \n";
    fwrite($fp, $out);
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }
    fclose($fp);
}
 
echo '<br />CONNECTION CLOSED';
 
?>
Просто через браузер в двух вкладках жму 127.0.0.1 и первая 10с, вторая 20с.
Возможно это из за того, что сокеты открываются по идеи через сам php, а это одно приложение? Как же тогда работает тот же редис или mysql ... там одновременно много подключений делается.
0
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
28.02.2012, 20:20
проведи тест с telnet`ом, и отпишись о результате.
0
0 / 0 / 0
Регистрация: 26.02.2012
Сообщений: 26
29.02.2012, 02:37  [ТС]
Подскажи какой командой проверить можно? Файл сервера висит в процессах, называется server

Добавлено через 1 час 25 минут
Еще выявил такой косяк, код твой полностью, отправляет клиент сообщение вида "STROKA TEST" обрабатывает и отвечает. При втором соединении клиент отправляет сообщение вида "TEST". После завершения чтения при попытке сделать message.get() получаем сообщение "TESTOKA TEST". Тоесть я так понимаю он буфер не очищает. Совсем запутался как работает вся эта система, как такое может быть если message внутри on_accept_handler как локальная переменная создаётся?
0
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
29.02.2012, 05:01
Цитата Сообщение от Kirm Посмотреть сообщение
Подскажи какой командой проверить можно?
> telnet 127.0.0.1 44550


Цитата Сообщение от Kirm Посмотреть сообщение
отправляет клиент сообщение вида "STROKA TEST" обрабатывает и отвечает. При втором соединении клиент отправляет сообщение вида "TEST". После завершения чтения при попытке сделать message.get() получаем сообщение "TESTOKA TEST".
какие-то чудеса у тебя происходят)
код показывай.
0
0 / 0 / 0
Регистрация: 26.02.2012
Сообщений: 26
29.02.2012, 14:54  [ТС]
Через телнет проверил, многопоточность работает, но через php никак не хочет. В чем же дело?

Вот код. У меня два потока вручную задано. Отправляю первое сообщение "TEST". Все ок принимает правильно. Отправляю второе "TES", принимает как надо. Отправляю третье "TE", четвертое и т.д. получаем в message.get() что-то вроде "TE0?(". Иногда такая картина наблюдается уже со второго сообщения.
Свои функции закомментировал.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
#include <iostream>
#include <string>
#include <map>
//#include "hiredis.h"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include <boost/thread.hpp>
 
#include <boost/tokenizer.hpp>
 
/***************************************************************************/
 
#define count_checkbox 1000
 
// максимальная длина принимаемого сообщения.
static const size_t message_len = 10000;
 
typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;
 
// начало приема запросов на подключение.
void start_accept(
   boost::asio::ip::tcp::acceptor* acceptor
);
 
// создаем асинхронную операцию аксепта.
void on_accept(
   boost::asio::ip::tcp::acceptor* acceptor,
   socket_ptr socket
);
 
// вызовется при подключении.
void on_accept_handler(
   boost::asio::ip::tcp::acceptor* acceptor,
   socket_ptr socket,
   const boost::system::error_code& error // объект ошибки
);
 
// вызовется при завершении асинхронной записи.
void on_async_read(
   socket_ptr socket,
   boost::shared_array<char> message, // shared_array мы сюда передаем для
                                      // того, чтоб не дать ему удалить данные которыми он
                                      // владеет до завершения асинхронной записи.
   const boost::system::error_code& error // объект ошибки
);
 
void on_async_write(
  const boost::system::error_code& error,
  std::size_t bytes_transferred
);
 
boost::asio::io_service ios;
 
/***************************************************************************/
 
//redisContext *c;
//redisReply *reply;
 
//Поисковая база
int count = 0;
 
typedef struct {
        unsigned int id;
        unsigned short *interests;
        unsigned int bithday;
        bool male;
} one_element;
 
 
typedef std::map <std::string, one_element> search_elements;
 
std::map <unsigned int, search_elements> search_elements_sort;
 
std::map <unsigned int, unsigned int> sort_elements;
 
 
std::string int2str(int i) {
 
    std::stringstream ss;
    ss<<i;
    std::string str;
    ss>>str;
    return str;
}
 
/*
std::vector<std::string> explode(char *sep, std::string src)
{
    std::vector<std::string> output;
    boost::char_separator<char> separator(sep);
    boost::tokenizer<boost::char_separator<char> > tokens(src, separator);
    boost::tokenizer<boost::char_separator<char> >::iterator token_iter;
 
    for (token_iter = tokens.begin(); token_iter != tokens.end(); token_iter++)
    output.push_back(*token_iter);
 
    return output;
}
 
std::string implode(char sep[1], std::vector<std::string> src)
{
    std::ostringstream output;
    std::vector<std::string>::iterator src_iter;
 
    for (src_iter = src.begin(); src_iter != src.end(); src_iter++) {
        output << *src_iter;
        if (src_iter != src.end()-1) {
            output << sep;
        }
    }
    return output.str();
}
 
 
 
void load_data_from_redis() {
 
 
 
    reply = (redisReply*)redisCommand(c, "FLUSHALL");
    freeReplyObject(reply);
 
    int all_insert = 10000;
    redisCommand(c, "SET users:count %i", all_insert);
    for (int i=1; i<=all_insert; i++) {
        int sort = (rand() % 501) + 100;
        int bithday = 100000;
        int male = rand() % 2;
        std::vector<std::string> v;
        for (int g = 1; g <= count_checkbox; g++) {
            if(rand() % 30 == 0) {
                v.push_back(int2str(g));
            }
        }
        std::string interests = implode((char*)" ! ", v);
        char buf[interests.length()];
        std::strcpy(buf, interests.c_str());
 
        redisCommand(c, "HMSET users:info:%i id %i sort %i status 1 bithday %i male %i interests \"%s\"", i, i, sort, bithday, male, buf);
 
    }
 
 
    reply = (redisReply*)redisCommand(c, "GET users:count");
    int all_count_check = atoi(reply->str);
    freeReplyObject(reply);
    for (int i=1; i <= all_count_check; i++) {
        reply = (redisReply*)redisCommand(c, "HGETALL users:info:%i", i);
        if (reply->elements > 0) {
            int j_s = reply->elements;
            int sort;
            int status;
            one_element tmp;
            for (int j=0; j<j_s; j+=2) {
                if (reply->element[j]->str == (std::string)"id") {
                    tmp.id = atoi(reply->element[j+1]->str);
                } else if (reply->element[j]->str == (std::string)"sort") {
                    sort = atoi(reply->element[j+1]->str);
                } else if (reply->element[j]->str == (std::string)"interests") {
                    std::string interests = reply->element[j+1]->str;
                    std::vector<std::string> v = explode((char*)" ! ",  interests.substr(1, interests.length()-2));
                    std::vector<std::string>::iterator src_iter;
                    tmp.interests = (unsigned short*)malloc(sizeof(unsigned short)*v.size());
                    int c = 0;
                    for (src_iter = v.begin(); src_iter != v.end(); src_iter++) {
                        std::string str = *src_iter;
                        tmp.interests[c] = atoi(str.c_str());
                        c++;
                    }
                } else if (reply->element[j]->str == (std::string)"status") {
                    status = atoi(reply->element[j+1]->str);
                } else if (reply->element[j]->str == (std::string)"bithday") {
                    tmp.bithday = atoi(reply->element[j+1]->str);
                } else if (reply->element[j]->str == (std::string)"male") {
                    if (reply->element[j+1]->str == (std::string)"1") {
                        tmp.male = true;
                    } else {
                        tmp.male = false;
                    }
                }
            }
            if (status == 1) {
                count++;
                search_elements_sort[sort][int2str(tmp.id)] = tmp;
                sort_elements[tmp.id] = sort;
            }
            free(tmp.interests);
        }
        freeReplyObject(reply);
    }
 
}
 
 
std::vector<std::string> make_search() {
 
    std::vector<std::string> result;
    std::map <unsigned int, search_elements> :: iterator cur;
    search_elements :: iterator cur_in;
 
    for (cur = search_elements_sort.begin(); cur != search_elements_sort.end(); cur++) {
        for (cur_in = cur->second.begin(); cur_in != cur->second.end(); cur_in++) {
            if (cur_in->second.male == true) {
                result.push_back(cur_in->first);
            }
        }
    }
 
    return result;
}
 
*/
std::string execute_command(int type, std::string message) {
 
    std::string result;
    /*
    //Здесь обработка я ее закоментировал
    if (type == 1) {
        std::vector<std::string> search = make_search();
        std::vector<std::string> :: iterator cur_r;
        for (cur_r = search.begin(); cur_r != search.end(); cur_r++) {
            result += *cur_r;
            if (cur_r != search.end()-1) {
                result += ",";
            }
        }
    }
    */
    sleep(10);
    return result;
 
}
 
 
int main() {
 
    /* Коннект к редису, и загрузка данных */
/*
    struct timeval timeout = { 1, 500000 }; // 1.5 seconds
    c = redisConnectWithTimeout((char*)"127.0.0.1", 6379, timeout);
    if (c->err) {
        printf("Connection to Redis error: %s\n", c->errstr);
        exit(1);
    }
 
    printf("Start data loading from Redis...\n");
 
    load_data_from_redis();
 
    printf("Data is loaded, now you can send commands...\n");
 
*/
 
    /* Открываем сокеты и формируем пул-потоки */
   static const char* ip = "127.0.0.1";
   static const boost::uint16_t port = 44550;
 
   // объект реализующий "вечную задачу".
   boost::shared_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(ios));
 
   // определяем кол-во ядер.
   size_t cpu_count = 2;//boost::thread::hardware_concurrency();
 
   // создаем кол-во рабочих потоков равное кол-ву ядер.
   boost::thread_group work_threads;
   for ( size_t idx = 0; idx < cpu_count; ++idx ) {
      work_threads.create_thread(boost::bind(&boost::asio::io_service::run, &ios));
   }
 
   // объект представляющий адрес для TCP соединений.
   boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(ip), port);
 
   // объект акксептора соединений.
   boost::asio::ip::tcp::acceptor acceptor(ios, endpoint);
 
   // запускаем асинхронный прием запросов на подключение
   start_accept(&acceptor);
 
 
   // сбрасываем "вечную задачу".
   work.reset();
 
   // работаем пока не завершаться все потоки.
   work_threads.join_all();
 
   // завершаемся.
   return 0;
}
 
/***************************************************************************/
 
// создаем асинхронную операцию аксепта
void start_accept(
   boost::asio::ip::tcp::acceptor* acceptor)
{
 
    std::cout << "WAIT NEW CONNECTION... \n";
   // создаем объект сокета который будет связан с принятым подключением.
   socket_ptr socket(new socket_ptr::element_type(acceptor->get_io_service()));
 
   // создаем операци. асинхронного аксепта.
   acceptor->async_accept(
      *socket,
      boost::bind(
         &on_accept_handler,
         acceptor,
         socket,
         boost::asio::placeholders::error
      )
   );
}
 
 
 
// вызовется при приеме нового подключения.
void on_accept_handler(
   boost::asio::ip::tcp::acceptor* acceptor,
   socket_ptr socket,
   const boost::system::error_code& error)
{
   if ( !error ) {
      // создаем shared_array который должен жить вплоть до окончании асинхронного чтения.
      // для этого, message передаем как аргумент в функциональный объект, для того, чтоб инкрементировать счетчик ссылок.
 
      boost::shared_array<char> message_read(new char[message_len]);
      //message_read.reset(new char[message_len]); - пробовал очищать буфер, толку никакого
 
      // для принятого соединения запускаем операцию асинхронного чтения.
 
      boost::asio::async_read(
         *socket,
         boost::asio::buffer(message_read.get(), message_len),
         boost::asio::transfer_at_least(2),
         boost::bind(
            &on_async_read,
            socket,
            message_read,
            boost::asio::placeholders::error
         )
 
       );
 
 
 
   } else {
      std::cout << "on_accept_handler() error: " << error.message() << std::endl;
   }
   // снова запускаем асинхронный прием запросов на подключение
   start_accept(acceptor);
}
 
/***************************************************************************/
 
// вызовется при завершении асинхронного чтения.
 
// примечание: аргумент message и socket, разрушаться при выходе из функции.
void on_async_read(
   socket_ptr socket,
   boost::shared_array<char> message_read,
   const boost::system::error_code& error)
{
   if ( !error ) {
    std::cout << "received message: " << message_read.get() << std::endl;
 
    std::string answer = execute_command(1, message_read.get());
 
       boost::asio::async_write(
         *socket,
         boost::asio::buffer(answer, answer.length()),
         &on_async_write
      );
 
   } else {
      std::cout << "on_async_read() error: " << error.message() << std::endl;
   }
}
 
 
void on_async_write(const boost::system::error_code& error, std::size_t bytes_transferred) {
 
///
 
};
 
/***************************************************************************/
На всякий случай если нужно, hiredis тут лежит
https://github.com/antirez/hiredis
0
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
29.02.2012, 16:17
Цитата Сообщение от Kirm Посмотреть сообщение
int2str
http://www.boost.org/doc/libs/... _cast.html

Цитата Сообщение от Kirm Посмотреть сообщение
Отправляю первое сообщение "TEST". Все ок принимает правильно. Отправляю второе "TES", принимает как надо. Отправляю третье "TE", четвертое и т.д. получаем в message.get() что-то вроде "TE0?(". Иногда такая картина наблюдается уже со второго сообщения.
посмотри мой код на предыдущей странице. обрати внимание на on_async_read()
1
0 / 0 / 0
Регистрация: 26.02.2012
Сообщений: 26
29.02.2012, 16:59  [ТС]
Проблему с передаваемым текстом решил. Теперь осталось решить вопрос как запускать одновременные подключения из под php приложения. Не подскажешь?
0
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
29.02.2012, 17:08
Цитата Сообщение от Kirm Посмотреть сообщение
подскажешь?
думаю..

Добавлено через 3 минуты
твой скрипт, отправляет два запроса одновременно? или сначала первый до получения ответа, а потом второй?
0
0 / 0 / 0
Регистрация: 26.02.2012
Сообщений: 26
29.02.2012, 17:19  [ТС]
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
 
// создаем сокет
$sh = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// определяем ip хоста
$ip = '127.0.0.1';
 
//socket_set_nonblock($sh);
// открываем сокет
socket_connect($sh, $ip, '44550');
// формируем http-заголовки
$headers  = "TEST MESSAGE";
 
// записываем данные в сокет
socket_write($sh, $headers, strlen($headers));
// читаем данные из сокета
$result = '';
while ($r = socket_read($sh, 1024)) $result .= $r;
 
echo $result;
echo '<br />CONNECTION CLOSED!!!';
 
?>
Если убрать комментарий от socket_set_nonblock($sh); то вообще ответа не дожидается и сразу закрывается, вывод пустой ответ. С комментарием нормально работает.
НО когда я элементарно создаю в браузере две вкладки 127.0.0.1/connect.php и почти одновременно жду обновить, в первой ответ приходит через 10с, во второй через 20с. В самом сервере также видно что он сначала принимает первого клиента, и только после закрытия соединения принимает второго.

Добавлено через 22 секунды
Как это php-шное ограничение можно обойти?

Добавлено через 4 минуты
Мне надо в итоге получить такую связку, чтобы несколько одновременных запросов от разных посетителей сайта сервер обрабатывал, и вот тут пхп этого не дает сделать(
0
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
29.02.2012, 17:41
Цитата Сообщение от Kirm Посмотреть сообщение
В самом сервере также видно что он сначала принимает первого клиента, и только после закрытия соединения принимает второго.
да нет же. это запросы идут последовательно.

Цитата Сообщение от Kirm Посмотреть сообщение
Как это php-шное ограничение можно обойти?
я не силен в php..

Цитата Сообщение от Kirm Посмотреть сообщение
вот тут пхп этого не дает сделать
все что приходит в голову - это гуглить..
0
0 / 0 / 0
Регистрация: 26.02.2012
Сообщений: 26
29.02.2012, 18:01  [ТС]
А как это дело организовать через php-extension? там же можно только функции свои добавить, будет ли там работать неблокирующий режим?
0
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
29.02.2012, 18:03
Цитата Сообщение от Kirm Посмотреть сообщение
php-extension
с вопросам и по пхп - тебе явно в другой раздел.
0
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
02.03.2012, 12:41
Kirm, ну что, разобрался?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
02.03.2012, 12:41
Помогаю со студенческими работами здесь

Одновременная работа с XML файлом несколькими людьми
Как одновременно работа с XML файлом нескольким людям? (и как это по научному называется?) И второй вопрос который интересует меня...

сервер чата с несколькими клиентами
вот код чата //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner)...

Совет по работе с несколькими TCP клиентами
Всем привет. У меня возникло некоторое недопонимание как работать с несколькими TCP клиентами. Может просто дико туплю. В общем есть...

Программа синхронизации папок по сети с несколькими клиентами
Здравствуйте! Помогите,пожалуйста с задачей. Мне нужно написать программу синхронизации папок по сети с несколькими...

Одновременная запись в файл несколькими потоками
Всем привет! Продолжаю разбираться с многопоточностью. Собственно вопрос в теме. Программа пишет лог. Каждый поток в ходе выполнения...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
53
Ответ Создать тему
Новые блоги и статьи
Перемещение выделенных строк ТЧ из одного документа в другой
Maks 30.03.2026
Реализация из решения ниже выполнена на примере нетипового документа "ВыдачаОборудованияНаСпецтехнику" с единственной табличной частью "ОборудованиеИКомплектующие" разработанного в конфигурации КА2. . . .
Functional First Web Framework Suave
DevAlt 30.03.2026
Sauve. IO Апнулись до NET10. Из зависимостей один пакет, работает одинаково хорошо как в режиме проекта так и в интерактивном режиме. из сложностей - чисто функциональный подход. Решил. . .
Автоматическое создание документа при проведении другого документа
Maks 29.03.2026
Реализация из решения ниже выполнена на нетиповых документах, разработанных в конфигурации КА2. Есть нетиповой документ "ЗаявкаНаРемонтСпецтехники" и нетиповой документ "ПланированиеСпецтехники". В. . .
Настройка движения справочника по регистру сведений
Maks 29.03.2026
Решение ниже реализовано на примере нетипового справочника "ТарифыМобильнойСвязи" разработанного в конфигурации КА2, с целью учета корпоративной мобильной связи в коммерческом предприятии. . . .
Автозаполнение реквизита при выборе элемента справочника
Maks 27.03.2026
Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. При выборе "Спецтехники" (Тип Справочник. Спецтехника), заполняется. . .
Сумматор с применением элементов трёх состояний.
Hrethgir 26.03.2026
Тут. https:/ / fips. ru/ EGD/ ab3c85c8-836d-4866-871b-c2f0c5d77fbc Первый документ красиво выглядит, но без схемы. Это конечно не даёт никаких плюсов автору, но тем не менее. . . всё может быть. . .
Автозаполнение реквизитов при создании документа
Maks 26.03.2026
Программный код из решения ниже размещается в модуле объекта документа, в процедуре "ПриСозданииНаСервере". Алгоритм проверки заполнения реализован для исключения перезаписи значения реквизита,. . .
Команды формы и диалоговое окно
Maks 26.03.2026
1. Команда формы "ЗаполнитьЗапчасти". Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. В качестве источника данных. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru