Пишем консольный сервер и клиент на C++ в Windows 32/64
Как обычно, создаём новый пустой проект C++, но для решения указываем имя, например, ClientServer
, а для проекта - другое имя, пусть будет Server
.
Потом ещё раз создаём пустой проект с именем Client
, но добавляем его в то то же самое решение.
Жмём правую кнопку мыши на "исходных файлах" приложения-сервера, выбираем команды Добавить, Создать элемент, Visual C++, файл C++, имя файла с исходным текстом можно оставить Source.cpp
(по умолчанию).
Вот полный исходник этого файла, откомпилированный в Visual Studio 2019 под актуальной сборкой Windows 10.
#define _WINSOCK_DEPRECATED_NO_WARNINGS #include <iostream> #include <cstdio> #include <cstring> #include <winsock2.h> #pragma comment(lib, "WS2_32.lib") using namespace std; DWORD WINAPI serverReceive(LPVOID lpParam) { //Получение данных от клиента char buffer[1024] = { 0 }; //Буфер для данных SOCKET client = *(SOCKET*)lpParam; //Сокет для клиента while (true) { //Цикл работы сервера if (recv(client, buffer, sizeof(buffer), 0) == SOCKET_ERROR) { //Если не удалось получить данные буфера, сообщить об ошибке и выйти cout << "recv function failed with error " << WSAGetLastError() << endl; return -1; } if (strcmp(buffer, "exit\n") == 0) { //Если клиент отсоединился cout << "Client Disconnected." << endl; break; } cout << "Client: " << buffer << endl; //Иначе вывести сообщение от клиента из буфера memset(buffer, 0, sizeof(buffer)); //Очистить буфер } return 1; } DWORD WINAPI serverSend(LPVOID lpParam) { //Отправка данных клиенту char buffer[1024] = { 0 }; SOCKET client = *(SOCKET*)lpParam; while (true) { fgets(buffer, 1024, stdin); if (send(client, buffer, sizeof(buffer), 0) == SOCKET_ERROR) { cout << "send failed with error " << WSAGetLastError() << endl; return -1; } if (strcmp(buffer, "exit\n") == 0) { cout << "Thank you for using the application" << endl; break; } } return 1; } int main() { WSADATA WSAData; //Данные SOCKET server, client; //Сокеты сервера и клиента SOCKADDR_IN serverAddr, clientAddr; //Адреса сокетов WSAStartup(MAKEWORD(2, 0), &WSAData); server = socket(AF_INET, SOCK_STREAM, 0); //Создали сервер if (server == INVALID_SOCKET) { cout << "Socket creation failed with error:" << WSAGetLastError() << endl; return -1; } serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(5555); if (bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { cout << "Bind function failed with error: " << WSAGetLastError() << endl; return -1; } if (listen(server, 0) == SOCKET_ERROR) { //Если не удалось получить запрос cout << "Listen function failed with error:" << WSAGetLastError() << endl; return -1; } cout << "Listening for incoming connections...." << endl; char buffer[1024]; //Создать буфер для данных int clientAddrSize = sizeof(clientAddr); //Инициализировать адерс клиента if ((client = accept(server, (SOCKADDR*)&clientAddr, &clientAddrSize)) != INVALID_SOCKET) { //Если соединение установлено cout << "Client connected!" << endl; cout << "Now you can use our live chat application. " << "Enter \"exit\" to disconnect" << endl; DWORD tid; //Идентификатор HANDLE t1 = CreateThread(NULL, 0, serverReceive, &client, 0, &tid); //Создание потока для получения данных if (t1 == NULL) { //Ошибка создания потока cout << "Thread Creation Error: " << WSAGetLastError() << endl; } HANDLE t2 = CreateThread(NULL, 0, serverSend, &client, 0, &tid); //Создание потока для отправки данных if (t2 == NULL) { cout << "Thread Creation Error: " << WSAGetLastError() << endl; } WaitForSingleObject(t1, INFINITE); WaitForSingleObject(t2, INFINITE); closesocket(client); //Закрыть сокет if (closesocket(server) == SOCKET_ERROR) { //Ошибка закрытия сокета cout << "Close socket failed with error: " << WSAGetLastError() << endl; return -1; } WSACleanup(); } }
Я выбрал в стандартной панели инструментов конфигурацию Debug - X64. Если нужно, разрешить приложению работать с сетью, подтверждаем это.

Разрешить консольному приложению сервера доступ к сети
Аналогично добавляем файл Source.cpp
в приложение Client
, вот его полный исходный код, так как он, в сущности, очень похож, можно без столь подробных комментариев:
#define _WINSOCK_DEPRECATED_NO_WARNINGS #include <iostream> #include <cstdio> #include <cstring> #include <winsock2.h> #pragma comment(lib, "WS2_32.lib") using namespace std; DWORD WINAPI clientReceive(LPVOID lpParam) { //Получение данных от сервера char buffer[1024] = { 0 }; SOCKET server = *(SOCKET*)lpParam; while (true) { if (recv(server, buffer, sizeof(buffer), 0) == SOCKET_ERROR) { cout << "recv function failed with error: " << WSAGetLastError() << endl; return -1; } if (strcmp(buffer, "exit\n") == 0) { cout << "Server disconnected." << endl; return 1; } cout << "Server: " << buffer << endl; memset(buffer, 0, sizeof(buffer)); } return 1; } DWORD WINAPI clientSend(LPVOID lpParam) { //Отправка данных на сервер char buffer[1024] = { 0 }; SOCKET server = *(SOCKET*)lpParam; while (true) { fgets(buffer, 1024, stdin); if (send(server, buffer, sizeof(buffer), 0) == SOCKET_ERROR) { cout << "send failed with error: " << WSAGetLastError() << endl; return -1; } if (strcmp(buffer, "exit") == 0) { cout << "Thank you for using the application" << endl; break; } } return 1; } int main() { WSADATA WSAData; SOCKET server; SOCKADDR_IN addr; WSAStartup(MAKEWORD(2, 0), &WSAData); if ((server = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { cout << "Socket creation failed with error: " << WSAGetLastError() << endl; return -1; } addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //коннект к серверу addr.sin_family = AF_INET; addr.sin_port = htons(5555); //порт if (connect(server, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) { cout << "Server connection failed with error: " << WSAGetLastError() << endl; return -1; } cout << "Connected to server!" << endl; cout << "Now you can use our live chat application. " << " Enter \"exit\" to disconnect" << endl; DWORD tid; HANDLE t1 = CreateThread(NULL, 0, clientReceive, &server, 0, &tid); if (t1 == NULL) cout << "Thread creation error: " << GetLastError(); HANDLE t2 = CreateThread(NULL, 0, clientSend, &server, 0, &tid); if (t2 == NULL) cout << "Thread creation error: " << GetLastError(); WaitForSingleObject(t1, INFINITE); WaitForSingleObject(t2, INFINITE); closesocket(server); WSACleanup(); }
Обратите внимание на директивы покдлючения библиотек в начале обоих листингов.
В Обозревателе Решений жмём правую кнопку на заголовке решения (самого верхнего уровня), выбираем "Назначить запускаемые проекты", подтверждаем запуск нескольких проектов.

Запуск нескольких проектов из решения
Наши клиент и сервер могут обмениваться сообщениями в режиме чата, конечно, функционал нетрудно расширить. Работа приложения предполагает, что у вас есть нужные компоненты в системе и настройки стандартны, в частности, доступен стандартный "локалхост" с IP-адресом 127.0.0.1

Проект в работе
Скачать это решение в архиве .zip, главная папка решения уже создана в архиве (6 Кб)
Так как опции решения хранятся в файле .suo
вместе с асболютными путями к файлам проекта (а у вас эти пути точно не совпадут с моими), то действие со второго рисунка ("Запуск нескольких проектов из решения") в скачанном проекте будет не настроено.
28.07.2020, 01:02 [29069 просмотров]