Форум программистов, компьютерный форум, киберфорум
C++: Сети
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
8 / 3 / 1
Регистрация: 11.08.2016
Сообщений: 46

Winsock и цикл сообщений

07.09.2020, 02:19. Показов 3461. Ответов 6

Студворк — интернет-сервис помощи студентам
В общем, делаю лабу универскую, пытаюсь разобраться с Winsock, но никак не могу понять, в чем проблема. Сначала скину код.
Сервер:
Кликните здесь для просмотра всего текста

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
#define _WINSOCK_DEPRECATED_NO_WARNINGS
 
#include "Winsock2.h"                // заголовок  WS2_32.dll
#pragma comment(lib, "WS2_32.lib")   // экспорт  WS2_32.dll
 
#include <iostream>
#include <string>
 
std::string SetErrorMsgText(std::string msgText, int code);
std::string itos(int i);
 
union Converter // для перевода int в char[4] и обратно
{
    int number;
    char bytes[4];
};
 
int main()
{
    WSADATA wsaData;
    try
    {
        // инициализация библиотеки
        if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)
            throw SetErrorMsgText("Startup:", WSAGetLastError());
 
        // создаем СОКЕТ ДЛЯ ПРОСЛУШИВАНИЯ ПОРТА и получаем его дескриптор
        SOCKET serverSocket = socket(
            AF_INET,        //[in]  формат адреса: TCP/IP - AF_INET, не должен быть = null!!!
            SOCK_STREAM,    //[in]  тип сокета: ориентированный на сообщения (UDP, SOCK_DGRAM) или на поток (TCP, SOCK_STREAM)
            IPPROTO_TCP     //[in]  протокол транспортного уровня. для tcp можно указать null
        );
        if (serverSocket == INVALID_SOCKET)
            throw SetErrorMsgText("socket:", WSAGetLastError());
 
        SOCKADDR_IN serv;                     // параметры  сокета sS
        serv.sin_family = AF_INET;            // используется IP-адресация  
        serv.sin_port = htons(2000);          // порт 2000
        serv.sin_addr.s_addr = INADDR_ANY;    // ответ присылать на IP-адрес: любой собственный IP-адрес 
 
        if (bind(serverSocket, (LPSOCKADDR)&serv, sizeof(serv)) == SOCKET_ERROR)
            throw SetErrorMsgText("bind:", WSAGetLastError());
        // запуск прослушивания сокетом порта
        if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) // SOMAXCONN - максимально возможная длина очереди подключений
            throw SetErrorMsgText("socket can't listen to port: ", WSAGetLastError());
        // теперь клиентская прог может вызывать connect() для подключения
 
        // переменные для работы с клиентом
        SOCKADDR_IN clientSocketInfo;       // параметры сокета клиента
        int size = sizeof(SOCKADDR_IN);     // размер структуры этих параметров
        SOCKET clientSocket;                // СОКЕТ ДЛЯ ОБМЕНА ДАННЫМИ
 
        memset(&clientSocketInfo, 0, sizeof(clientSocketInfo)); // обнулить память
        
 
        std::cout << "Server is listening to port 2000...\n";
        // получаем дескриптор сокета для обмена данными по КАНАЛУ
        clientSocket = accept(serverSocket,                 // [in]  дескриптор связанного сокета
                            (sockaddr*)&clientSocketInfo,   // [out] указатель на sockaddr
                            &size);             // [out] указатель на длину структуры sockaddr
 
        if (clientSocket == INVALID_SOCKET)
            throw SetErrorMsgText("socket: ", WSAGetLastError());
 
        // служебная инфа
        std::cout << "IP address: " << inet_ntoa(clientSocketInfo.sin_addr) << std::endl << "Port: " << htons(clientSocketInfo.sin_port) << std::endl;
 
        Converter dataSize;
        char* buffer;
 
        for(int i = 0; i < 1000; i++) {
            // принимаем размер будущих данных
            char* cSize = new char[4]; // 4 байта = int
            memset(cSize, 0, 4);
            int byteCounter = 0;
            byteCounter = recv(clientSocket, cSize, sizeof(int), NULL); // 4-й аргумент: NULL - после получения входной буфер очищается, MSG_PEEK - входной буфер не очищается
            //byteCounter = recv(clientSocket, cSize, sizeof(int), NULL); // 4-й аргумент: NULL - после получения входной буфер очищается, MSG_PEEK - входной буфер не очищается
            if (byteCounter == SOCKET_ERROR)
                throw SetErrorMsgText("recv: ", WSAGetLastError());
            std::cout << "MESSAGE SIZE = " << byteCounter << std::endl;
            
            // конвертируем
            dataSize.bytes[0] = cSize[0];
            dataSize.bytes[1] = cSize[1];
            dataSize.bytes[2] = cSize[2];
            dataSize.bytes[3] = cSize[3];
 
 
            buffer = new char[dataSize.number];
            memset(buffer, 0, dataSize.number);
            std::cout << "Getting " << dataSize.number << " bytes...\n";
 
            byteCounter = 0;
            while (byteCounter < dataSize.number)
            {
                byteCounter += recv(clientSocket, buffer, dataSize.number, MSG_PEEK); // 4-й аргумент: NULL - после получения входной буфер очищается, MSG_PEEK - входной буфер не очищается
                if (byteCounter == SOCKET_ERROR)
                    throw SetErrorMsgText("recv: ", WSAGetLastError());
            }
            std::cout << buffer << std::endl << "Bytes got: " << byteCounter << std::endl;
            delete[] buffer;
            delete[] cSize;
        }
 
        // закрываем сокеты
        if (closesocket(clientSocket) == SOCKET_ERROR)
            throw SetErrorMsgText("closing client socket error:", WSAGetLastError());
        if (closesocket(serverSocket) == SOCKET_ERROR)
            throw SetErrorMsgText("closing server socket error:", WSAGetLastError());
 
        // выгрузка библиотеки
        if (WSACleanup() == SOCKET_ERROR)
            throw SetErrorMsgText("Cleanup:", WSAGetLastError());
    }
    catch (std::string errorMsgText)
    {
        std::cout << std::endl << std::endl << errorMsgText;
        getchar();
    }
    std::cout << "DONE.";
    getchar();
    return 0;
}
 
std::string GetErrorMsgText(int code)    // cформировать текст ошибки 
{
    std::string msgText;
    switch (code)                      // проверка кода возврата  
    {
    case WSAEINTR: msgText = "WSAEINTR"; break;
    case WSAEACCES: msgText = "WSAEACCES"; break;
    case WSAEFAULT: msgText = "WSAEFAULT"; break;
    case WSAEINVAL: msgText = "WSAEINVAL"; break;
        //..........коды WSAGetLastError ..........................
    case WSASYSCALLFAILURE: msgText = "WSASYSCALLFAILURE"; break;
    default: msgText = "UNKNOWN ERROR. CODE: " + itos(code); break;
    };
    return msgText;
};
 
std::string SetErrorMsgText(std::string msgText, int code) { return  msgText + GetErrorMsgText(code); };
 
#include <sstream>
std::string itos(int i) // convert int to string
{
    std::stringstream s;
    s << i;
    return s.str();
}

Клиент:
Кликните здесь для просмотра всего текста

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
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
 
#include "Winsock2.h"                // заголовок  WS2_32.dll
#pragma comment(lib, "WS2_32.lib")   // экспорт  WS2_32.dll
 
#include <iostream>
#include <string>
 
std::string SetErrorMsgText(std::string msgText, int code);
// Преобразование int в string
std::string itos(int i);
 
 
union Converter // для перевода int в char[4] и обратно
{
    int number;
    char bytes[4];
};
 
int main()
{
    WSADATA wsaData;
    try
    {
        // инициализация библиотеки
        if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)
            throw SetErrorMsgText("Startup:", WSAGetLastError());
 
        // создаем СОКЕТ ДЛЯ ОТПРАВЛЕНИЯ и получаем его дескриптор
        SOCKET clientSocket = socket(
            AF_INET,        //[in] формат адреса: TCP/IP - AF_INET, не должен быть = null!!!
            SOCK_STREAM,    //[in] тип сокета: ориентированный на сообщения (UDP, SOCK_DGRAM) или на поток (TCP, SOCK_STREAM)
            IPPROTO_TCP     //[in] протокол транспортного уровня. для tcp можно указать null
        );
        if (clientSocket == INVALID_SOCKET)
            throw SetErrorMsgText("socket:", WSAGetLastError());
 
        SOCKADDR_IN serverInfo; // параметры сокета сервера
        memset(&serverInfo, 0, sizeof(serverInfo)); // обнулить память
        serverInfo.sin_family = AF_INET;                        // тип сети
        serverInfo.sin_port = htons(2000);                      // порт для подключения
        serverInfo.sin_addr.s_addr = inet_addr("127.0.0.1");    // IP-адрес сервера для подключения
        //serverInfo.sin_addr.s_addr = inet_addr("192.168.56.103"); // IP-адрес сервера для подключения
 
        std::cout << "Connecting...\n";
        if (connect(clientSocket, (LPSOCKADDR)&serverInfo, sizeof(serverInfo)) == SOCKET_ERROR)
            throw SetErrorMsgText("can't connect: ", WSAGetLastError());
 
        for (int i = 0; i < 1000; i++)
        {
            std::string message = "Hello from Client " + itos(i);
            
            const char* m = message.c_str();
 
            std::cout << m << std::endl;
 
            Converter size;
            size.number = strlen(m);
 
            // отправляем размер
            std::cout << "Sending " << size.number << " bytes...\n";
 
            int code = send(clientSocket, size.bytes, sizeof(int), NULL);
            if (code == SOCKET_ERROR)
                throw SetErrorMsgText("send: ", WSAGetLastError());
 
            // теперь отправляем сами данные
            code = send(clientSocket, m, size.number, NULL);
            if (code == SOCKET_ERROR)
                throw SetErrorMsgText("send: ", WSAGetLastError());
            
            getchar();
        }
 
        // закрываем сокеты
        if (closesocket(clientSocket) == SOCKET_ERROR)
            throw SetErrorMsgText("closesocket:", WSAGetLastError());
 
        // выгрузка библиотеки
        if (WSACleanup() == SOCKET_ERROR)
            throw SetErrorMsgText("Cleanup:", WSAGetLastError());
    }
    catch (std::string errorMsgText)
    {
        std::cout << std::endl << std::endl << errorMsgText;
    }
    std::cout << "\n\nDONE.";
    getchar();
    return 0;
}
 
std::string GetErrorMsgText(int code)    // cформировать текст ошибки 
{
    std::string msgText;
    switch (code)                      // проверка кода возврата  
    {
    case WSAEINTR: msgText = "WSAEINTR"; break;
    case WSAEACCES: msgText = "WSAEACCES"; break;
    case WSAEFAULT: msgText = "WSAEFAULT"; break;
    case WSAEINVAL: msgText = "WSAEINVAL"; break;
        //..........коды WSAGetLastError ..........................
    case WSASYSCALLFAILURE: msgText = "WSASYSCALLFAILURE"; break;
    default: msgText = "UNKNOWN ERROR. CODE: " + itos(code); break;
    };
    return msgText;
};
 
std::string SetErrorMsgText(std::string msgText, int code) { return  msgText + GetErrorMsgText(code); };
 
#include <sstream>
std::string itos(int i) // convert int to string
{
    std::stringstream s;
    s << i;
    return s.str();
}

Какую дичь я только не пробовал (думаю, по коду вы это понимаете), все равно не работает.
Задание такое: отправить 1000 раз сообщение "Hello from Client XXX", где XXX - номер сообщения.
Т.к. сообщение у меня переменной длины, то сначала я отправляю его размер, а затем само сообщение. Вроде бы адекватное решение, верно? На сервере соответственно я сначала читаю размер будущего сообщения, затем само смс. Но почему-то на сервере во время 2-й итерации происходит вылет при инициализации массива buffer: size.number принимает аномально огромное значение. Глянув внимательно в консоль сервера и прогнав через отладчик, я понял, что при 1-й итерации массив имеет размер 19 символов (тут все верно), но в консоль каждый раз выводит одни и те же 23 (wtf?) символа: "Hello from Clientээээ". Что за бред? Первая глупость, приходящая в голову: 4-хбайтовый размер следующего СМС прилетел сюда, из-за чего появились эти символы и на 2-й итерации в size.number записываются уже другие 4 байта. Но т.к. клиент останавливается с помощью getchar(), это просто невозможно! Также заметил, что на 2-й итерации в массив cSize, что в начале цикла, постоянно записывается значение "Hellээээ*~Ъ\". Часть от отправленной фразы длиной в 4 байта?.. В общем, я окончательно запутался в этом вопросе. Я гуглил эту тему, но ответа так и не нашел. Плохо гуглил? Пожалуйста, объясните начинающему студенту, как правильно отправлять такие сообщения и исправить ошибки.
Заранее спасибо! Удачи всем и хорошего кода!
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
07.09.2020, 02:19
Ответы с готовыми решениями:

Цикл сообщений и функция их обработки
вечер добрый! я почти нулевой новичок в win api, в одном из первых примеров, которые я смотрел упоминался цикл сообщений и функция их...

Чем отличается цикл сообщений в скрытом окне от бесконечного цикла?
Написал прогу под WinAPI, которая перебирает все окна в бесконечном цикле #include &lt;windows.h&gt; BOOL CALLBACK EnumProc(HWND...

Отправка сообщений. Winsock, send и telnet
Приветствую. Пишу простенький сервер. Использую Delphi 6, winsock. Клиентом является стандартный telnet. При подключении хочу...

6
Native x86
Эксперт Hardware
 Аватар для quwy
6853 / 3787 / 1024
Регистрация: 13.02.2013
Сообщений: 11,861
07.09.2020, 03:55
О правильном использовании TServerSocket/TClientSocked и подобными компонентами, пункт 3 (на п.2 тоже обратите внимение).
Там про компоненты Delphi/Builder, но чистых сокетов это касается в той же мере.
0
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
07.09.2020, 08:43
Лучший ответ Сообщение было отмечено Ivanshka как решение

Решение

Цитата Сообщение от Ivanshka Посмотреть сообщение
Вроде бы адекватное решение, верно?
верно, но оно совсем не обязательно.
к тому же, у вас оно неправильное, т.к. в сеть принято отправлять байты только в прямом порядке байт, чтобы у других не возникало путаницы.
так же у std::string есть метод size().
код на клиенте должен выглядеть как-то так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
for (int i = 0; i < 1000; i++)
{
    std::string message = "Hello from Client " + itos(i);
 
    std::cout << message << std::endl;
 
    uint32_t size = message.size();
    size = htonl(size); // переводим в прямой порядок байт
 
    // отправляем размер
    std::cout << "Sending " << size << " bytes...\n";
 
    int code = send(clientSocket, (const char *)&size, sizeof(uint32_t), 0);
    if (code == SOCKET_ERROR)
        throw SetErrorMsgText("send: ", WSAGetLastError());
 
    // теперь отправляем сами данные
    code = send(clientSocket, message.data(), message.size(), 0);
    if (code == SOCKET_ERROR)
        throw SetErrorMsgText("send: ", WSAGetLastError());
    
    getchar();
}
Цитата Сообщение от Ivanshka Посмотреть сообщение
byteCounter += recv(clientSocket, buffer, dataSize.number, MSG_PEEK);
зачем здесь флаг MSG_PEEK?
к тому же последним аргументом send и recv принимают int, а не указатель, поэтому там должно быть не NULL, а 0.
в таком случае у вас буфер не вычитывается и вы постепенно продолжаете его вычитывать как size, у которого этот флаг не стоит.
если добавлять к этому исправление отправки размера из предыдущего шага, то получается как-то так:
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
for(int i = 0; i < 1000; i++) {
    // принимаем размер будущих данных
    uint32_t cSize = 0;
    int byteCounter = 0;
    byteCounter = recv(clientSocket, (char *)&cSize, sizeof(uint32_t), 0); // 4-й аргумент: NULL - после получения входной буфер очищается, MSG_PEEK - входной буфер не очищается
    cSize = ntohl(cSize); // перевод из прямого в системный порядок байт
    if (byteCounter == SOCKET_ERROR)
        throw SetErrorMsgText("recv: ", WSAGetLastError());
    std::cout << "MESSAGE SIZE = " << byteCounter << std::endl;
 
 
    buffer = new char[cSize];
    memset(buffer, 0, cSize);
    std::cout << "Getting " << cSize << " bytes...\n";
 
    byteCounter = 0;
    while (byteCounter < cSize)
    {
        byteCounter += recv(clientSocket, buffer + byteCounter, cSize - byteCounter, 0); // 4-й аргумент: NULL - после получения входной буфер очищается, MSG_PEEK - входной буфер не очищается
        if (byteCounter == SOCKET_ERROR)
            throw SetErrorMsgText("recv: ", WSAGetLastError());
    }
    std::cout << buffer << std::endl << "Bytes got: " << byteCounter << std::endl;
    delete[] buffer;
}
1
8 / 3 / 1
Регистрация: 11.08.2016
Сообщений: 46
07.09.2020, 15:57  [ТС]
Цитата Сообщение от GbaLog- Посмотреть сообщение
верно, но оно совсем не обязательно.
Не обязательно? О_о Тогда как быть, если у меня информация, например, 1 КБ? TCP разобьет его на части (например, 200 + 300 + 500 байт), и мне прилетит первая часть, а остальные - с задержкой. А как в этом случае правильно читать данные? Просто я хочу понять, как правильно передавать данные динамического размера.
Касаемо вашего кода, то все заработало, а пояснения я понял) Большое спасибо!)
Остался лишь 1 момент, который я не могу объяснить и исправить. При выводе полученных данных на консоль сервера, он выводит "Hello frm Client XXX¤¤¤¤". Откуда взялись еще 4 символа?..

Добавлено через 16 минут
Цитата Сообщение от GbaLog- Посмотреть сообщение
к тому же последним аргументом send и recv принимают int, а не указатель, поэтому там должно быть не NULL, а 0.
И, кстати, какая разница между 0 и NULL, если NULL - это всего лишь
C++
1
#define NULL 0
? Это ведь не указатель.
0
2734 / 888 / 331
Регистрация: 10.02.2018
Сообщений: 2,097
07.09.2020, 16:32
Цитата Сообщение от Ivanshka Посмотреть сообщение
Откуда взялись еще 4 символа?
Вы со строками работаете, а завершающий строку 0 не передаёте и ручками не добавляете. Поэтому мусор разный в конце строки появляется.
1
Любитель чаепитий
 Аватар для GbaLog-
3745 / 1801 / 566
Регистрация: 24.08.2014
Сообщений: 6,020
Записей в блоге: 1
07.09.2020, 16:54
Цитата Сообщение от Ivanshka Посмотреть сообщение
Не обязательно?
я имел ввиду, что это не единственный способ.
например, в HTTP конец строки обозначается последовательностью \r\n, а конец заголовка \r\n\r\n.
размер заголовка нигде не передаётся, но благодаря этим правилам подходит для потокового декодирования.
Цитата Сообщение от Ivanshka Посмотреть сообщение
При выводе полученных данных на консоль сервера, он выводит "Hello frm Client XXX¤¤¤¤". Откуда взялись еще 4 символа?..
как вам и сказали выше, у вас не хватает в строке завершающего строку символа: '\0'.
поэтому std::cout выводит строку, пока не встретит этот символ.
для того, чтобы этого избежать вам нужно создавать буфер размера cSize + 1. и memset так же поправить.
Цитата Сообщение от Ivanshka Посмотреть сообщение
какая разница между 0 и NULL, если NULL - это всего лишь
это не обязательно.
NULL может быть реализован через nullptr, а nullptr имеет тип std::nullptr_t.
вероятно, у вас скомпилируется код и с ним, но так просто не стоит делать.
NULL следует использовать только для указателей, а лучше использовать nullptr.
1
8 / 3 / 1
Регистрация: 11.08.2016
Сообщений: 46
08.09.2020, 08:48  [ТС]
Цитата Сообщение от GbaLog- Посмотреть сообщение
я имел ввиду, что это не единственный способ.
например, в HTTP конец строки обозначается последовательностью \r\n, а конец заголовка \r\n\r\n.
размер заголовка нигде не передаётся, но благодаря этим правилам подходит для потокового декодирования.
Ух ты) Теперь стало яснее)
Цитата Сообщение от GbaLog- Посмотреть сообщение
как вам и сказали выше, у вас не хватает в строке завершающего строку символа: '\0'.
поэтому std::cout выводит строку, пока не встретит этот символ.
для того, чтобы этого избежать вам нужно создавать буфер размера cSize + 1. и memset так же поправить.
Да, еще вчера, как прочел то СМС, сразу так сделал и исправил)
Цитата Сообщение от GbaLog- Посмотреть сообщение
это не обязательно.
NULL может быть реализован через nullptr, а nullptr имеет тип std::nullptr_t.
вероятно, у вас скомпилируется код и с ним, но так просто не стоит делать.
NULL следует использовать только для указателей, а лучше использовать nullptr.
О_о. nullptr я использовал по назначению и ранее, но вот про такой подводный камень не знал. Теперь все стало ясно.
Большое спасибо за помощь!)
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
08.09.2020, 08:48
Помогаю со студенческими работами здесь

Цикл обработки сообщений
Можно ли как то отобразить основной цикл обработки сообщений в WinForms c++ если нет то как получить управление над потоком (ну я скорее...

Как реализовать цикл ввода сообщений?
Программа должна выпольняться пока пользователь не введет слово Exit. Программа спрашивает пользователя ввести число от 1 до 5 и ввыводит...

Может так случится, что процесс приема новых сообщений и их прорисовки превратится в бесконечный цикл?
Допустим у меня есть приложение, которое добавляет в себя поступающие сообщения. А эти сообщения сыпят постоянно. Может так случится,что...

Используйте цикл for для вывода сообщений об именах и id десяти тегов <span> при нажатии кнопки.
Помогите пожалуйста. Используйте цикл for для вывода сообщений об именах и id деся-ти тегов &lt;span&gt; при нажатии кнопки «START».

Создать программу по всем 3 видам циклов...цикл с параметром,цикл с условием,цикл,и цикл с предусловием...
Найти сумму чисел 1 в квадрате до 10 c квадрате...операцию возведению в степень не использовать учесть особенности получения квадратного...


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

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru