I have code client on c++, client works on ubuntu. When i create session ny bash closed. Why?
In function SendCommand i see the info about shellPid but my shall pid is already closed May be problem in destructor ShellHandler? if u have idea write please
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <poll.h>
#include <csignal>
#include <atomic>
#include <unordered_map>
#include <mutex>
#include <thread>
std::atomic<bool> running(true);
void signalHandler(int signal) {
if (signal == SIGINT) {
running = false;
}
}
class ShellHandler {
private:
int pipeIn[2]; // Pipe for sending input to the shell
int pipeOut[2]; // Pipe for receiving output from the shell
pid_t shellPid;
public:
ShellHandler() : pipeIn{-1, -1}, pipeOut{-1, -1}, shellPid(-1) {
// Create pipes for communication with the shell
if (pipe(pipeIn) == -1 || pipe(pipeOut) == -1) {
throw std::runtime_error("Failed to create pipes.");
}
// Fork a child process to run the shell
shellPid = fork();
if (shellPid == -1) {
throw std::runtime_error("Failed to fork.");
}
if (shellPid == 0) {
// Child process: Run the shell
close(pipeIn[1]); // Close the write end of the input pipe (не используется в дочернем процессе)
close(pipeOut[0]); // Close the read end of the output pipe (не используется в дочернем процессе)
// Redirect stdin and stdout to the pipes
if (dup2(pipeIn[0], STDIN_FILENO) == -1) {
std::cerr << "Error: Failed to redirect stdin. Errno: " << errno << std::endl;
_exit(1);
}
if (dup2(pipeOut[1], STDOUT_FILENO) == -1) {
std::cerr << "Error: Failed to redirect stdout. Errno: " << errno << std::endl;
_exit(1);
}
if (dup2(pipeOut[1], STDERR_FILENO) == -1) {
std::cerr << "Error: Failed to redirect stderr. Errno: " << errno << std::endl;
_exit(1);
}
// Execute the shell
execl("/bin/bash", "bash", "-i", nullptr); // Запуск в интерактивном режиме
// If execl fails
std::cerr << "Error: Failed to execute shell. Errno: " << errno << std::endl;
_exit(1);
} else {
// Parent process: Close unused pipe ends
close(pipeIn[0]); // Close the read end of the input pipe (не используется в родительском процессе)
close(pipeOut[1]); // Close the write end of the output pipe (не используется в родительском процессе)
std::cout << "Shell started with PID: " << shellPid << std::endl;
}
}
~ShellHandler() {
// Clean up
if (pipeIn[1] != -1) close(pipeIn[1]);
if (pipeOut[0] != -1) close(pipeOut[0]);
// Если shell все еще работает, отправляем команду на завершение
if (shellPid > 0) {
std::cout << "Checking if shell with PID " << shellPid << " is still running..." << std::endl;
if (kill(shellPid, 0) == 0) {
std::cout << "Sending exit command to shell with PID: " << shellPid << std::endl;
std::string cmd = "exit\n";
if (write(pipeIn[1], cmd.c_str(), cmd.size()) == -1) {
std::cerr << "Error: Failed to send exit command to shell. Errno: " << errno << std::endl;
}
// Ждем завершения shell
waitpid(shellPid, nullptr, 0);
} else {
std::cerr << "Error: Shell process is not running. Errno: " << errno << std::endl;
}
}
}
void SendCommand(const std::string& command) {
// Логирование информации о сессии
std::cout << "Session Info:" << std::endl;
std::cout << " shellPid: " << shellPid << std::endl;
std::cout << " pipeIn[0]: " << pipeIn[0] << ", pipeIn[1]: " << pipeIn[1] << std::endl;
std::cout << " pipeOut[0]: " << pipeOut[0] << ", pipeOut[1]: " << pipeOut[1] << std::endl;
if (pipeIn[1] == -1) {
std::cerr << "Error: Pipe is closed." << std::endl;
throw std::runtime_error("Error: Pipe is closed.");
}
// Проверка, что shell все еще работает
if (kill(shellPid, 0) == -1) {
std::cerr << "Error: Shell process is not running." << std::endl;
throw std::runtime_error("Error: Shell process is not running.");
}
// Отправка команды
std::string cmd = command + "\n";
std::cout << "Sending command to shell: " << cmd << std::endl;
if (write(pipeIn[1], cmd.c_str(), cmd.size()) == -1) {
std::cerr << "Error: Failed to write to pipe. Errno: " << errno << std::endl;
throw std::runtime_error("Error: Failed to write to pipe.");
}
}
std::string ReceiveOutput() {
// Set the output pipe to non-blocking mode
SetNonBlocking(pipeOut[0]);
// Use poll to check if there is data available in the output pipe
struct pollfd fds[1];
fds[0].fd = pipeOut[0];
fds[0].events = POLLIN;
std::string output;
bool dataAvailable = true;
while (dataAvailable) {
int ret = poll(fds, 1, 100); // Wait for 100ms
if (ret == -1) {
std::cerr << "Error: poll failed." << std::endl;
throw std::runtime_error("Error: poll failed.");
} else if (ret == 0) {
std::cout << "Poll timeout, no data available." << std::endl;
dataAvailable = false;
} else if (fds[0].revents & POLLIN) {
char buffer[4096] = {0};
int bytesRead = read(pipeOut[0], buffer, sizeof(buffer));
if (bytesRead <= 0) {
std::cerr << "No data read from pipe." << std::endl;
dataAvailable = false;
} else {
output.append(buffer, bytesRead);
std::cout << "Read " << bytesRead << " bytes from pipe: " << output << std::endl;
}
}
}
return output;
}
private:
void SetNonBlocking(int fd) {
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) {
std::cerr << "Error: fcntl(F_GETFL) failed." << std::endl;
throw std::runtime_error("Error: fcntl(F_GETFL) failed.");
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
std::cerr << "Error: fcntl(F_SETFL) failed." << std::endl;
throw std::runtime_error("Error: fcntl(F_SETFL) failed.");
}
std::cout << "Pipe set to non-blocking mode." << std::endl;
}
};
class NetworkHandler {
private:
int clientSocket;
public:
NetworkHandler(const std::string& serverIP, int port) {
// Create a socket
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == -1) {
throw std::runtime_error("Failed to create socket.");
}
// Define server address
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
inet_pton(AF_INET, serverIP.c_str(), &serverAddr.sin_addr);
// Try to connect to the server in a loop
while (running) {
if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == 0) {
std::cout << "Connected to the server." << std::endl;
break; // Exit the loop on successful connection
} else {
std::cerr << "Failed to connect to the server. Retrying in 5 seconds..." << std::endl;
sleep(5); // Wait for 5 seconds before retrying
}
}
}
~NetworkHandler() {
close(clientSocket);
}
std::string ReceiveCommand() {
char buffer[4096] = {0};
int bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesReceived <= 0) {
throw std::runtime_error("Connection closed by the server.");
}
return std::string(buffer, bytesReceived);
}
void SendResult(const std::string& result) {
// Отправляем длину сообщения
uint32_t messageLength = htonl(result.size());
send(clientSocket, &messageLength, sizeof(messageLength), 0);
// Отправляем само сообщение
send(clientSocket, result.c_str(), result.size(), 0);
}
};
class Client {
private:
NetworkHandler networkHandler;
std::unordered_map<int, ShellHandler> sessions; // Сессии (sessionID -> ShellHandler)
int activeSessionID = -1; // Активная сессия
std::mutex sessionsMutex; // Мьютекс для синхронизации доступа к сессиям
int nextSessionID = 1; // Счетчик для генерации уникальных sessionID
public:
Client(const std::string& serverIP, int port)
: networkHandler(serverIP, port) {}
void Run() {
while (running) {
try {
// Receive a command from the server
std::string command = networkHandler.ReceiveCommand();
std::cout << "Received command: " << command << std::endl;
// Обработка команд управления сессиями
if (command == "list_sessions") {
std::lock_guard<std::mutex> lock(sessionsMutex);
std::string result = "Active sessions:\n";
for (const auto& session : sessions) {
result += "SessionID: " + std::to_string(session.first) + "\n";
}
networkHandler.SendResult(result);
} else if (command == "create_new_session") {
std::lock_guard<std::mutex> lock(sessionsMutex);
int sessionID = nextSessionID++;
sessions.emplace(sessionID, ShellHandler());
activeSessionID = sessionID;
networkHandler.SendResult("New session created and selected. SessionID: " + std::to_string(sessionID));
} else {
if (activeSessionID == -1) {
networkHandler.SendResult("No active session. Use 'create_new_session' to create one.");
continue;
}
std::lock_guard<std::mutex> lock(sessionsMutex);
auto it = sessions.find(activeSessionID);
if (it != sessions.end()) {
std::cout << "Sending command to session " << activeSessionID << ": " << command << std::endl;
try {
it->second.SendCommand(command);
std::string output = it->second.ReceiveOutput();
networkHandler.SendResult(output);
std::cout << "Output from session " << activeSessionID << ":\n" << output << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error in session " << activeSessionID << ": " << e.what() << std::endl;
networkHandler.SendResult("Error: " + std::string(e.what()));
}
} else {
networkHandler.SendResult("Active session not found.");
}
}
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
// Не завершаем работу клиента, а продолжаем цикл
continue;
}
}
}
};
int main() {
// Set up signal handler for graceful shutdown
std::signal(SIGINT, signalHandler);
try {
Client client("192.168.12.34", 12345); // Replace with server's IP address
client.Run();
} catch (const std::exception& e) {
std::cerr << "Fatal error: " << e.what() << std::endl;
return 1;
}
std::cout << "Connection closed." << std::endl;
return 0;
}
i added more debugs in code to the localisate the problem
Server code
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <thread>
#include <atomic>
#include <mutex>
#include <unordered_map>
#pragma comment(lib, "ws2_32.lib")
std::mutex clientsMutex; // Мьютекс для синхронизации доступа к списку клиентов
class ClientHandler {
public:
SOCKET socket;
int clientID;
std::atomic<bool> running;
ClientHandler(SOCKET sock, int id) : socket(sock), clientID(id), running(true) {}
// Удаляем конструктор копирования и оператор присваивания
ClientHandler(const ClientHandler&) = delete;
ClientHandler& operator=(const ClientHandler&) = delete;
void SendCommand(const std::string& command) {
if (send(socket, command.c_str(), static_cast<int>(command.size()), 0) == SOCKET_ERROR) {
std::cerr << "Error: Failed to send command to ClientID: " << clientID << std::endl;
running = false;
}
}
std::string ReceiveResult() {
// Сначала получаем длину сообщения
uint32_t messageLength;
int bytesReceived = recv(socket, reinterpret_cast<char*>(&messageLength), sizeof(messageLength), 0);
if (bytesReceived <= 0) {
running = false;
return "";
}
// Преобразуем длину сообщения из сетевого порядка байт в хостовый
messageLength = ntohl(messageLength);
// Получаем само сообщение
std::string result;
result.resize(messageLength);
char* buffer = &result[0];
int totalReceived = 0;
while (totalReceived < static_cast<int>(messageLength)) {
bytesReceived = recv(socket, buffer + totalReceived, static_cast<int>(messageLength - totalReceived), 0);
if (bytesReceived <= 0) {
running = false;
return "";
}
totalReceived += bytesReceived;
}
return result;
}
};
class Server {
private:
std::list<ClientHandler> clients; // Список клиентов
std::vector<std::thread> clientThreads; // Потоки для обработки клиентов
std::unordered_map<int, int> activeSessions; // Активные сессии (clientID -> sessionID)
std::mutex sessionsMutex; // Мьютекс для синхронизации доступа к активным сессиям
std::atomic<bool> running;
int activeClientID = -1; // ID активного клиента
void HandleClient(ClientHandler& client) {
while (client.running) {
std::string result = client.ReceiveResult();
if (!result.empty()) {
std::cout << "Result from ClientID " << client.clientID << ":\n" << result << std::endl;
}
else {
std::cerr << "ClientID " << client.clientID << " disconnected." << std::endl;
break;
}
}
// Удаляем клиента из списка
std::lock_guard<std::mutex> lock(clientsMutex);
clients.remove_if([&client](const ClientHandler& c) { return c.clientID == client.clientID; });
}
public:
Server() : running(true) {}
void Run() {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed." << std::endl;
return;
}
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET) {
std::cerr << "Socket creation failed." << std::endl;
WSACleanup();
return;
}
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(12345);
if (bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Bind failed." << std::endl;
closesocket(serverSocket);
WSACleanup();
return;
}
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
std::cerr << "Listen failed." << std::endl;
closesocket(serverSocket);
WSACleanup();
return;
}
std::cout << "Server is running. Waiting for clients..." << std::endl;
while (running) {
SOCKET clientSocket = accept(serverSocket, NULL, NULL);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Accept failed." << std::endl;
continue;
}
std::lock_guard<std::mutex> lock(clientsMutex);
int clientID = clients.size() + 1;
clients.emplace_back(clientSocket, clientID);
clientThreads.emplace_back(&Server::HandleClient, this, std::ref(clients.back()));
std::cout << "Client connected. ClientID: " << clientID << std::endl;
}
closesocket(serverSocket);
WSACleanup();
}
void HandleCommands() {
std::string command;
while (true) {
std::cout << "Enter command: ";
std::getline(std::cin, command);
if (command.substr(0, 6) == "change") {
// Выбор активного клиента
int id = std::stoi(command.substr(7));
std::lock_guard<std::mutex> lock(clientsMutex);
auto it = std::find_if(clients.begin(), clients.end(), [id](const ClientHandler& client) {
return client.clientID == id;
});
if (it != clients.end()) {
activeClientID = id;
std::cout << "Selected ClientID: " << id << std::endl;
}
else {
std::cout << "ClientID not found." << std::endl;
}
}
else if (command == "list") {
// Список подключенных клиентов
std::lock_guard<std::mutex> lock(clientsMutex);
std::cout << "Connected clients:" << std::endl;
for (const auto& client : clients) {
std::cout << "ClientID: " << client.clientID << std::endl;
}
}
else if (command == "exit") {
running = false;
break;
}
else {
// Отправка команды активному клиенту
if (activeClientID == -1) {
std::cout << "No client selected. Use 'change <client_id>' to select a client." << std::endl;
continue;
}
std::lock_guard<std::mutex> lock(clientsMutex);
auto it = std::find_if(clients.begin(), clients.end(), [this](const ClientHandler& client) {
return client.clientID == activeClientID;
});
if (it != clients.end()) {
it->SendCommand(command);
}
else {
std::cout << "Active client not found." << std::endl;
}
}
}
}
};
int main() {
Server server;
std::thread serverThread([&server]() { server.Run(); });
server.HandleCommands();
serverThread.join();
return 0;
}
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744731976a4590519.html
评论列表(0条)