Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma comment(lib, "Ws2_32.lib")
- #include <concurrent_vector.h>
- #include <vector>
- #include <string>
- #include <winsock2.h>
- #include <windows.h>
- #include <iostream>
- using std::string;
- using std::cout;
- using std::endl;
- using std::cin;
- DWORD WINAPI listenClient(LPVOID lpParam); // args: [0] SOCKET* server
- DWORD WINAPI listenServer(LPVOID lpParam); // args: [0] SOCKET* server
- void runServer();
- void runClient();
- int main() {
- #pragma region Регестрируем сокеты
- WORD socketVer;
- WSADATA wsaData;
- socketVer = MAKEWORD(2, 2);
- WSAStartup(socketVer, &wsaData);
- #pragma endregion
- setlocale(LC_ALL, "Russian");
- string type; // Client/Server
- int port;
- cout << "Что запускаем [client/server]" << endl;
- cin >> type;
- if (type.compare("server") == 0) {
- runServer();
- }else if (type.compare("client") == 0) {
- runClient();
- }
- system("pause");
- return 0;
- }
- void runClient() {
- // Создаем TCP сокет
- SOCKET _socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (_socket == SOCKET_ERROR) cout << "Не удалось создать сокет" << endl;
- int port;
- cout << "Введите порт клиента" << endl;
- cin >> port;
- #pragma region Создаем адрес клиента (addr) с портом port и любым адресом
- SOCKADDR_IN addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = INADDR_ANY;
- #pragma endregion
- // Назначаем сокету адрес
- int result = bind(_socket, (LPSOCKADDR)&addr, sizeof(addr));
- if (result == SOCKET_ERROR) cout << "Не удалось забиндить сокет" << endl;
- // Подключаемся к серверу
- string server_ip;
- cout << "Введите ip сервера" << endl;
- cin >> server_ip;
- #pragma region Создаем адрес сервера (server_addr) с портом 2003 и server_ip
- SOCKADDR_IN server_addr;
- server_addr.sin_family = AF_INET;
- server_addr.sin_addr.S_un.S_addr = inet_addr(server_ip.c_str());
- server_addr.sin_port = htons(2003);
- #pragma endregion
- result = connect(_socket, (sockaddr*)&server_addr, sizeof(server_addr));
- if (result == SOCKET_ERROR) cout << "Не удалось подключиться" << endl;
- cout << "Подключение к серверу прошло успешно" << endl;
- // Создаем поток, который будет слушать сокет
- DWORD threadID;
- CreateThread(
- NULL, // Структура, которая определяет безопасность (NULL - по умолчанию)
- 0, // Размер стека (0 - стандартное значение)
- (LPTHREAD_START_ROUTINE)&listenServer, // Указатель на фунцию, которая выполнится в потоке
- (LPVOID)_socket, // Аргументы функции
- 0, // Флаги, которые управляют созданием потока.
- &threadID // Указатель на переменную, в которую передастся номер потока
- );
- // А здесь будем читать то, что ввел клиент
- for (string line; std::getline(std::cin, line);) {
- send(_socket, line.c_str(), line.size(), 0);
- }
- }
- DWORD WINAPI listenServer(LPVOID lpParam) {
- SOCKET server = (SOCKET)lpParam;
- char buf[256];
- int buf_length = 256;
- int connected = true;
- // Слушаем сервер
- cout << "Слушаем сервер" << endl;
- while (connected) {
- buf_length = recv(server, buf, 256, 0);
- if (buf_length == SOCKET_ERROR) {
- cout << "Не удалось получить сообщение" << endl;
- connected = false;
- break;
- }
- buf[buf_length] = '\0';
- cout << buf << endl;
- }
- return 0;
- }
- /**
- * Массив с указателями на сокеты клиентов
- * Нужен для отправки сообщения всем клиентам
- * Потокобезопасен
- */
- //concurrency::concurrent_vector<SOCKET*> clients;
- std::vector<SOCKET> clients;
- void runServer() {
- // Создаем TCP сокет
- SOCKET _socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (_socket == SOCKET_ERROR) cout << "Не удалось создать сокет" << endl;
- #pragma region Создаем адрес сервера (addr) с портом 2003 и любым адресом
- SOCKADDR_IN addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(2003);
- addr.sin_addr.s_addr = INADDR_ANY;
- #pragma endregion
- // Назначаем сокету адрес
- int result = bind(_socket, (LPSOCKADDR) &addr, sizeof(addr));
- if (result == SOCKET_ERROR) cout << "Не удалось забиндить сокет" << endl;
- // Слушаем подключения
- while (true) {
- cout << "Ожидаем подключение клиента" << endl;
- result = listen(_socket, 5);
- if (result == SOCKET_ERROR) cout << "Не удалось слушать сокет" << endl;
- SOCKADDR_IN remote_address;
- int address_length = sizeof(remote_address);
- // Подключаем нового клиента
- SOCKET client = accept(_socket, (sockaddr*) &remote_address, &address_length);
- if (client == INVALID_SOCKET) cout << "Не удалось принять подключение" << endl;
- // Добавляем сокет клиента в контейнер
- clients.push_back(client);
- // Создаем новый поток, для клиента, где будем слушать его сокет
- DWORD threadID;
- CreateThread(
- NULL, // Структура, которая определяет безопасность (NULL - по умолчанию)
- 0, // Размер стека (0 - стандартное значение)
- (LPTHREAD_START_ROUTINE)&listenClient, // Указатель на фунцию, которая выполнится в потоке
- (LPVOID) client, // Аргументы функции
- 0, // Флаги, которые управляют созданием потока.
- &threadID // Указатель на переменную, в которую передастся номер потока
- );
- }
- }
- DWORD WINAPI listenClient(LPVOID lpParam) {
- cout << "Создали поток" << endl;
- SOCKET client = (SOCKET)lpParam;
- char buf[256];
- int buf_length = 256;
- int connected = true;
- // Слушаем клиента
- cout << "Слушаем клиента" << endl;
- while (connected) {
- buf_length = recv(client, buf, 256, 0);
- if (buf_length == SOCKET_ERROR) {
- cout << "Не удалось получить сообщение" << endl;
- connected = false;
- break;
- }
- buf[buf_length] = '\0';
- // Отправляем сообщение всем клиентам
- // Кроме клиента, от которого пришло сообщение
- for (auto other_client : clients) {
- // Сравниваем указатели на сокеты клиентов
- // if (client == other_client) continue;
- send(other_client, buf, buf_length, 0);
- }
- cout << "Пришло сообщение: " << buf << endl;
- }
- // Удаляем клиента из массива клиентов
- cout << "Клиент отсоединился" << endl;
- clients.erase(std::remove(clients.begin(), clients.end(), client), clients.end());
- return 0;
- }
Advertisement