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

Клиент-серверное приложение. Одновременный запрос клиентов

27.08.2017, 21:57. Показов 1675. Ответов 4

Студворк — интернет-сервис помощи студентам
Приложения нормально работают с одним клиентом при не слишком частых запросах (интервал между запросами более 10-50 мс). А также с несколькими клиентами, если они делают запросы в разное время.
Однако при одновременном запросе от двух клиентов только один получает ответ от сервера, в то время как второй безрезультатно ждет ответа.
На стороне сервера в логах я вижу ошибку "Client: Ошибка получения сообщения от клиента: ", this_client_ip, ". recv() Error: ".
Но я не могу понять, что конкретно не так с сервером.
Сервер разрабатывается на C++ Builder в Embarcadero xe3
сервер

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
void TcpThread( void *);
//--------------------------------------------------------------------------
//структура для передачи данных в нить клиента
struct net_info
{
    SOCKET socket_client;
    char* this_client_ip;
};
 
//---------------------------------------------------------------------------
#define MAX_ARRY 100
//Единичная нить работы с клиентом
void ClientThread( void *arg )
{
    SOCKET sock;
    net_info *ni;
    char* this_client_ip;
 
    char buf[MAX_ARRY] = "", buf_in[MAX_ARRY] = "", buf_out[MAX_ARRY] = "";
    int len_recv = 0, cnt=0, ret_code;
 
    fd_set rfd;
    struct timeval tv;
 
    ni = (net_info*)arg;
    this_client_ip = ni->this_client_ip;
    sock = ni->socket_client;
 
//if( ( am.flag ) 
 
        while( len_recv != -1 )
        {
            //Приготовления select()
            FD_ZERO (&rfd);
            FD_SET (sock, &rfd );
            tv.tv_sec = 5;         //5 сек макс ожидание приема
            tv.tv_usec = 0;
 
            ret_code = select( 1+sock, &rfd, 0, 0, &tv);       //Ждем прием
 
            if( ret_code == 0 )
            {
 
                AddErrorToLogFile(h_errno, "%s%s%s",  "Client: Ошибка ожидания сообщения от клиента: ", this_client_ip,  ". select() Error: ");
                break;
            }
            else
            {
                AddExtraStringToLogFile("%s%s%s\n", "Client: Ожидание сообщения от клиента: ", this_client_ip,  ". select() OK" );
            }
 
            len_recv = recv( sock, buf, MAX_ARRY, 0 );       //Получить сообщение
 
            if( len_recv == -1 )
            {
                AddErrorToLogFile(h_errno, "%s%s%s",  "Client: Ошибка получения сообщения от клиента: ", this_client_ip,  ". recv() Error: " );
                break;
            }
            else
            {
                 AddExtraStringToLogFile("%s%s%s%s\n", "Client: Сообщение от клиента: ", this_client_ip,  " получено успешно. recv() OK. Полученное сообщение: ", buf );
                 if( (cnt+len_recv) < MAX_ARRY )
                 {
                    strncpy( &buf_in[cnt], buf, len_recv );
                    cnt+=len_recv;
                 }
                 else
                 {                  
                    break;
                 }
            }
 
            //ответ для клиента
            if( strcmpi( buf_in, "ask" ) == 0 )
            {               
                send( sock, (char *)&am, sizeof(am), 0 );
                AddExtraStringToLogFile("%s%s%s\n", "Client: Сообщение клиенту: ", this_client_ip,  " отправленно успешно. send() OK. Отправленное сообщение: структура данных для клиета" );
                break;
            }
            //ответы для telnet-а
            else if( ( strcmpi( buf_in, "dvt" ) == 0 ) || ( strcmpi( buf_in, "?" ) == 0 ) )
            {
                 sprintf(buf_out, "Qw = %6.2f\t AS = %04.3f\t Zx = %04.1f\n",  am.Qw, am.AS, am.Zx );
                 send( sock, buf_out, strlen(buf_out), 0 );
                 AddExtraStringToLogFile("%s%s%s%s", "Client: Сообщение клиенту: ", this_client_ip,  " отправленно успешно. send() OK. Отправленное сообщение: ", buf_out );
                 break;
            }
            else if( ( strcmpi( buf_in, "qw" ) == 0 ) )
            {
                 sprintf(buf_out, "%6.2f\n",  am.Qw );
                 send( sock, buf_out, strlen(buf_out), 0 );
                 AddExtraStringToLogFile("%s%s%s%s",  "Client: Сообщение клиенту: ", this_client_ip,  " отправленно успешно. send() OK. Отправленное сообщение: ", buf_out );
                 break;
            }
            else if( ( strcmpi( buf_in, "as" ) == 0 ) )
            {
                 sprintf(buf_out, "%04.3f\n",  am.AS );
                 send( sock, buf_out, strlen(buf_out), 0 );
                 AddExtraStringToLogFile("%s%s%s%s", "Client: Сообщение клиенту: ", this_client_ip,  " отправленно успешно. send() OK. Отправленное сообщение: ", buf_out );
                 break;
            }
            else if( ( strcmpi( buf_in, "zx" ) == 0 ) )
            {
                 sprintf(buf_out, "%04.1f\n",  am.Zx );
                 send( sock, buf_out, strlen(buf_out), 0 );
                 AddExtraStringToLogFile("%s%s%s%s", "Client: Сообщение клиенту: ", this_client_ip,  " отправленно успешно. send() OK. Отправленное сообщение: ", buf_out );
                 break;
            }
        }
 
    closesocket( sock );
 
    //return;
    _endthread();
}
 
//---------------------------------------------------------------------------
//Нить выполнения функций сервера
void TcpThread( void *ptrarg)
{
 while (1)
 {
    WSADATA wsd;
    SOCKET s_server, s_client;
    struct sockaddr_in server_addr, client_addr;
    int ret_code;
    int client_addr_size;
 
    //Зарегистрироваться в библиотеке Windows Socket
    if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)      
    {
        AddMessageToStatusbar( "Tcp: Ошибка регистрации WSAStartup" );
 
        AddErrorToLogFile(h_errno, "%s",  "Tcp: Ошибка регистрации в библиотеке Windows Socket. WSAStartup() Error: " );
 
        Sleep(2000);
        continue;
        //return;
    }
    else
    {
        AddExtraStringToLogFile("%s\n", "Tcp: Регистрации в библиотеке Windows Socket успешна. WSAStartup() OK" );
    }
 
    // Создание TCP-сокета, возвращает дескриптор сокета
    s_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 
    if ( s_server  == INVALID_SOCKET )          //протокол IPv4, тип потоковый сокет, транспортный протокол по умомлчанию
    {
        AddMessageToStatusbar ("Tcp: Ошибка создания TCP-сокета");
 
        AddErrorToLogFile(h_errno, "%s",  "Tcp: Ошибка создания TCP-сокета. socket() Error: " );
 
        WSACleanup();                           // Деиницилизация библиотеки Winsock
        Sleep(2000);
        continue;
        //return;
        //exit(EXIT_FAILURE) ;
    }
    else
    {
        AddStringToLogFile("%s\n", "Tcp: Создание TCP-сокета успешно. socket() OK" );
    }
 
    //bind() //Привязывание сокета к прослушиваемому порту
    memset( &server_addr, 0 , sizeof( struct sockaddr_in ));    // очистить  &server_addr
    server_addr.sin_family = AF_INET;                       // семейство протоколов
    server_addr.sin_port = htons(atoi(SERVER_PORT ));       // порт
    server_addr.sin_addr.s_addr = htonl( INADDR_ANY );      // IP – адрес
 
    ret_code = bind( s_server, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in));
 
    if(ret_code )
    {
        AddMessageToStatusbar( "Tcp: Ошибка привязывания сокета к порту" );
 
        AddErrorToLogFile(h_errno, "%s", "Tcp: Ошибка привязывания сокета к прослушиваемому порту. bind() Error: ");
 
        closesocket(s_server);          // закрываем сокет
        WSACleanup();
        Sleep(2000);
        continue;
        //return;
    }
    else
    {
        AddExtraStringToLogFile("%s\n", "Tcp: Привязывание сокета к прослушиваемому порту успешно. bind() OK" );
    }
 
    // listen() //подготавливание привязываемого сокета к принятию входящих соединений
    ret_code = listen( s_server, 0x100);            
 
    if(ret_code  )
    {
        AddMessageToStatusbar( "Tcp: Ошибка подготовки к принятию входящих соединений" );
 
        AddErrorToLogFile(h_errno, "%s",  "Tcp: Ошибка подготовки привязываемого сокета к принятию входящих соединений. listen() Error: " );
 
        closesocket( s_server );
        WSACleanup();
        Sleep(2000);
        continue;
        //return;
    }
    else
    {
        AddExtraStringToLogFile("%s\n", "Tcp: Подготовка привязываемого сокета к принятию входящих соединений успешна. listen() OK" );
    }
 
    //цикл извлечения запросов на подключение из очереди
    client_addr_size=sizeof(client_addr);
 
    while(1)
    {
         s_client = accept( s_server, (struct sockaddr *)&client_addr, &client_addr_size);
 
         char string_temp[200] = "";
 
         client_ip =  inet_ntoa(client_addr.sin_addr);
          
         if(s_client == -1 )
         {
            AddMessageToStatusbar( "Tcp: Ошибка входящего соединения" );
 
            AddErrorToLogFile(h_errno, "%s%s%s",  "Tcp: Ошибка входящего соединения от клиента: ", client_ip, ". accept() Error: " );
 
            closesocket( s_server );
            WSACleanup();
            return;
         }
         else
         {
            AddExtraStringToLogFile("%s%s%s\n", "Tcp: Входящеее соединение от клиента: ", client_ip, " успешно. accept() OK");
         }
 
         //заполнение структуры данных для отправки в нить клиента
         net_info ni;
         ni.socket_client = s_client;
         ni.this_client_ip = client_ip;
 
        
        //время запроса от клиента
        SYSTEMTIME st;
        GetLocalTime(&st);
        sprintf( client_time, "%02d:%02d:%02d", st.wHour,
                                                st.wMinute,
                                                st.wSecond);
                                              //.%03d"       st.wMilliseconds  );
         //заполнение массива информацией о подключенных клиентах
        for (int j=0; j < clients_name_values; j++)
        {
            //если ip адрес есть в списке клиентов
            if ( strcmpi(client_ip_arr[j], client_ip ) == 0 )
            {
                clients_count_connect[j]++;
                strcpy(client_time_arr[j], client_time);
 
                if ( strcmpi (client_name_arr[j], "Unknown") == 0 )
                {
                    sprintf(string_temp, "%s%s", "Клиент: ", client_ip_arr[j]);
                }
                else
                {
                    sprintf(string_temp, "%s%s", "Клиент: ", client_name_arr[j]);
                }
 
                AddMessageToStatusbar( string_temp );
                
                break;
            }
            else
            {
                //если ip адрес нет в списке клиентов
                if ( (  j == clients_name_values - 1 ) && clients_name_values < MAX_CLIENTS)
                {   
                    strcpy(client_time_arr[clients_name_values], client_time);
                    strcpy(client_name_arr[clients_name_values], "Unknown"); //hst->h_name); //"Unknown");
                    strcpy(client_ip_arr[clients_name_values], client_ip);
                    clients_count_connect[clients_name_values]++;
 
                    sprintf(string_temp, "%s%s", "Клиент: ", client_ip_arr[clients_name_values]);
 
                    AddMessageToStatusbar( string_temp );
 
                    clients_name_values ++;
                    break;
                }
            }
        }
        
        //если нет списка клиентов
        if ( clients_name_values == 0 )
        {
            strcpy(client_time_arr[0], client_time);
            strcpy(client_name_arr[0], "Unknown"); //hst->h_name); //"Unknown");
            strcpy(client_ip_arr[0], client_ip);
            clients_count_connect[0]++;
 
            sprintf(string_temp, "%s%s", "Клиент: ", client_ip_arr[0]);
 
            AddMessageToStatusbar( string_temp );
 
            clients_name_values ++;
        }
 
        //Запустить нить работы с единичным клиентом
        _beginthread( ClientThread, 0 , &ni );//&s_client );
 
 
    }
  }
}


клиент

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
#define T_1_2_TCP       "m_1_2_tcp"
#define IP_ADDRESS      "192.168.0.180"
#define TCP_PORT        "1024"
#define REQUEST_TIME    1
 
#define QW              data_out->sof[0].code
#define AS              data_out->sof[1].code
#define ZX              data_out->sof[2].code
#define 1_STATUS        data_out->sof[3].code
#define 2_STATUS        data_out->sof[4].code
 
struct data_float *data_out;
int size_out;
 
static char *flag_name = { T_1_2_TCP };
static char *flag_ip_address = { IP_ADDRESS  };
char *flag_ip_port = TCP_PORT;
 
short flag_debug = ON;
 
int my_receiver , my_params;
 
fd_set rfd;
struct timeval tv;
 
//массив имен параметров
const char *name_par_out[]=
    {
            "Qw",
            "AS",
            "Zx",
            NULL
    };
 
//структура ответа с сервера
 struct ask_measurer {
                        float Qw;
                        float As;
                        float Zx;
                        bool flag_1_status;
                        bool flag_2_status;
                        //short crc;
                    };
 
struct ask_measurer am;
 
int main(int argc, char *argv[]) {
 
    int sockfd;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    int optional;
 
    int ret_code = 0;
    
    /* Анализ командной строки */
    while( ( optional = getopt( argc, argv, "dI:p:" ) ) != -1 )
    {
        switch(optional)
        {
            case 'd':
                flag_debug = ON;
                break;
            case 'I':
                flag_ip_address = optarg;
                break;
            case 'p':
                flag_ip_port = optarg;
                break;
        }
    }
 
    //Найти my_params
    if ((my_params = name_open( T_MY_PARAMS, NAME_FLAG_ATTACH_GLOBAL))== -1 )//id my_params
    if ((my_params = name_open( T_MY_PARAMS, 0))== -1 )
    {
        printf( "%s: No name_locate my_params\n",flag_name);
        exit(EXIT_FAILURE);
    }
 
    //Найти my_receiver
    if ((my_receiver = name_open(T_MY_RECEIVER, NAME_FLAG_ATTACH_GLOBAL )) == -1)
    if ((my_receiver = name_open(T_MY_RECEIVER, 0 )) == -1)
    {
        printf("%s: No receiver name_open()\n",flag_name);
        exit(EXIT_FAILURE);
    }
 
 
    PmPrepSendValues( my_params, name_par_out, &data_out, &size_out );// Подготовить массив нa отправку знaчений пaрaметров в receiver
 
    for(;;)
    {   
 
         // Создание TCP-сокета
        sockfd = socket(AF_INET, SOCK_STREAM, 0);//протокол IPv4, тип потоковый сокет, транспортный протокол по умолчанию
        if (sockfd < 0)
        {
            perror("ERROR opening socket");
            //exit(1);
            //return(-1);
            continue;
        }
    
        server = gethostbyname(flag_ip_address);
        if (server == NULL) {
            fprintf(stderr,"ERROR, no such host\n");
            //exit(0);
            continue;
        }
    
        bzero((char *) &serv_addr, sizeof(serv_addr));//очистить
        serv_addr.sin_family = AF_INET; //Семейство адресов
        bcopy((char *)server->h_addr,
                (char *)&serv_addr.sin_addr.s_addr,
                server->h_length); // IP – адрес
        serv_addr.sin_port = htons(atoi(flag_ip_port)); // порт
    
        /* Now connect to the server */
        if (connect(sockfd,(const struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0)
        {
            if( flag_debug == ON )
            {
                printf("m_1_2_tcp: recv() Error %d\n");
            }
            //exit(1);
            continue;
        }
        //else if( flag_debug == ON )
            //printf("tcp: recv() OK %d\n");
    
        if ( ret_code == -1)
        {
            printf("ERROR opening socket %d\n");
            //exit(1);
            continue;
        }
 
        //посылаем запрос
        ret_code = send( sockfd, "ask", 20, 0 );
    
        if ( ret_code == -1)
        {
            printf("m_1_2_tcp: send ERROR %d\n");
            //exit(1);
            continue;
        }
        //else if( flag_debug == ON )
                //printf("tcp: Send OK %d\n");
    
        //Приготовления select()
        FD_ZERO( &rfd );
        FD_SET( sockfd, &rfd ); //добавить файловый дескриптор sockfd в rfd
    
        tv.tv_sec = 5;          // Set a 5 second timeout.
        tv.tv_usec = 0;
    
        ret_code = select( 1 + sockfd, &rfd, 0, 0, &tv );
    
        if(ret_code <= 0 )
        {
            if( flag_debug == ON )
            {
                printf("m_1_2_tcp: No receive() message from server in 5 sec\n" );
            }
            close(sockfd);
            //exit(1);
            continue;
        }
    
        //memset(buf, 0, MAX_BUF );
    
        //Чтение данных
        ret_code = recv( sockfd, &am, sizeof(am) , 0 );
    
    
        if ( ret_code == -1 )
    
        {   
            if( flag_debug == ON )
            {
                printf("m_1_2_tcp: recv() Error %d\n");
            }
            close(sockfd);
            //exit(1);
            continue;
        }
        else
        {
                QW = am.Qw;
                AS = am.As;
                ZX = am.Zx;
            
 
            //Отправить в receiver
            PmSendValues( my_receiver, data_out, size_out );//// Выполнить отправку знaчений пaрaметров из receiver           
            
            delay(REQUEST_TIME);
        }
        
        close(sockfd);      
    }
 
    return EXIT_SUCCESS;
}
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
27.08.2017, 21:57
Ответы с готовыми решениями:

Клиент-серверное приложение
С помощью каких компонентов или функций можно разработать клиент-серверное приложение?

Клиент-серверное приложение
Здравствуйте. Подскажите пожалуйста. С клиент-серверными приложениями сталкиваюсь впервые. Нужно разработать простенькое приложение в...

Клиент серверное приложение не работает
клиент void __fastcall TForm1::ClientSocket1Connect(TObject *Sender, TCustomWinSocket *Socket) { ...

4
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
31.08.2017, 12:25
Может лучше попробовать использовать Indy ?
0
0 / 0 / 0
Регистрация: 19.03.2014
Сообщений: 5
31.08.2017, 15:07  [ТС]
Я хочу создать приложение без использования посторонних компонентов.

оффтоп:
Как перенести тему в другой раздел (C++ и сети)? Думаю, там к месту будет.
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
31.08.2017, 15:28
Indy давно уже не сторонние компоненты.
(Тем более для C++ Builder в Embarcadero xe3)

Не по теме:

Если хотите можете посмотреть мои обвертки над WinSoks:
https://github.com/Avazart/Bic... n/WinSocks

1
0 / 0 / 0
Регистрация: 19.03.2014
Сообщений: 5
31.08.2017, 19:00  [ТС]
Avazart, спасибо, посмотрю.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
31.08.2017, 19:00
Помогаю со студенческими работами здесь

Клиент-серверное приложение средствами IPC
Всем доброго времени суток. Нужно написать 2 приложения: Клиент и Сервер Клиент должен используя Pipe просто передавать текстовые...

Клиент-серверное приложение посредством ClientSocket и ServerSocket
В общем, задание таково: Клиентская программа оправляет на сервер последовательность из k целых чисел (значения чисел задаются через...

Клиент-серверное приложение, сохранение переписки в файл
Здраствуйте!):) У меня есть два приложения: одно-клиентская часть, второе-серверная часть. Передача сообщений между ними по IP налажена (по...

Клиент серверное приложение TcpServer или IdTCPServer?
Здравствуйте господа. Мне необходимо сделать серверное приложение для программы реализованной в Builder 5 (да именно старый) на...

Создать клиент-серверное приложение на основе TServerSocket и TClientSocket
Я создаю сервер на одном хосте. На другом запускаю клиент, который должен подлючиться к серверу в локальной сети, не зная ни имени хоста,...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! */ #include <iostream> #include <stack> #include <cctype>. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru