gpt4 book ai didi

c# - C#[在Unity中]和C++之间的命名管道

转载 作者:行者123 更新时间:2023-12-02 10:32:59 28 4
gpt4 key购买 nike

我目前正在Unity中开发一个脚本,该脚本与C++通信以便接收字节流。现在,我正在研究一个示例,其中两个进程传达一条标准消息,并且通过查看堆栈溢出,我发现了一些我决定使用的有趣示例。

这是C++代码(与Microsoft clic提供的示例相同,但我进行了一些更改以尝试了解正在发生的情况)



#include "NamedPipeWithCSharpNew.h"
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>

#define BUFSIZE 512

DWORD WINAPI InstanceThread(LPVOID);
VOID GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD);

int _tmain(VOID)
{
BOOL fConnected = FALSE;
DWORD dwThreadId = 0;
HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;
LPCTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe");

// The main loop creates an instance of the named pipe and
// then waits for a client to connect to it. When the client
// connects, a thread is created to handle communications
// with that client, and this loop is free to wait for the
// next client connect request. It is an infinite loop.

for(;;)
{
_tprintf(TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszPipename);
hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_BYTE | // byte type pipe
PIPE_READMODE_BYTE | // byte-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
NULL); // default security attribute

if (hPipe == INVALID_HANDLE_VALUE)
{
_tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError());
return -1;
}

// Wait for the client to connect; if it succeeds,
// the function returns a nonzero value. If the function
// returns zero, GetLastError returns ERROR_PIPE_CONNECTED.

fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

if (fConnected)
{
printf("Client connected, creating a processing thread.\n");

// Create a thread for this client.
hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
InstanceThread, // thread proc
(LPVOID)hPipe, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID

if (hThread == NULL)
{
_tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError());
return -1;
}
else CloseHandle(hThread);
}
else
// The client could not connect, so close the pipe.
CloseHandle(hPipe);
}
return 0;
}

DWORD WINAPI InstanceThread(LPVOID lpvParam)
// This routine is a thread processing function to read from and reply to a client
// via the open pipe connection passed from the main loop. Note this allows
// the main loop to continue executing, potentially creating more threads of
// of this procedure to run concurrently, depending on the number of incoming
// client connections.
{
HANDLE hHeap = GetProcessHeap();
TCHAR* pchRequest = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(TCHAR));
TCHAR* pchReply = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE * sizeof(TCHAR));


DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
BOOL fSuccess = FALSE;
HANDLE hPipe = NULL;

// Do some extra error checking since the app will keep running even if this
// thread fails.

if (lpvParam == NULL)
{
printf("\nERROR - Pipe Server Failure:\n");
printf(" InstanceThread got an unexpected NULL value in lpvParam.\n");
printf(" InstanceThread exitting.\n");
if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return (DWORD)-1;
}

if (pchRequest == NULL)
{
printf("\nERROR - Pipe Server Failure:\n");
printf(" InstanceThread got an unexpected NULL heap allocation.\n");
printf(" InstanceThread exitting.\n");
if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);
return (DWORD)-1;
}

if (pchReply == NULL)
{
printf("\nERROR - Pipe Server Failure:\n");
printf(" InstanceThread got an unexpected NULL heap allocation.\n");
printf(" InstanceThread exitting.\n");
if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);
return (DWORD)-1;
}

// Print verbose messages. In production code, this should be for debugging only.
printf("InstanceThread created, receiving and processing messages.\n");

// The thread's parameter is a handle to a pipe object instance.

hPipe = (HANDLE)lpvParam;

// Loop until done reading
while (1)
{
// Read client requests from the pipe. This simplistic code only allows messages
// up to BUFSIZE characters in length.
fSuccess = ReadFile(
hPipe, // handle to pipe
pchRequest, // buffer to receive data
BUFSIZE * sizeof(TCHAR), // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O

if (!fSuccess || cbBytesRead == 0)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
{
_tprintf(TEXT("InstanceThread: client disconnected.\n"));
}
else
{
_tprintf(TEXT("InstanceThread ReadFile failed, GLE=%d.\n"), GetLastError());
}
break;
}

// Process the incoming message.
GetAnswerToRequest(pchRequest, pchReply, &cbReplyBytes);
printf("Continuing..\n"); // qua ci arriva

// Write the reply to the pipe.
fSuccess = WriteFile(
hPipe, // handle to pipe
pchReply, // buffer to write from
cbReplyBytes, // number of bytes to write
&cbWritten, // number of bytes written
NULL); // not overlapped I/O

if (!fSuccess || cbReplyBytes != cbWritten)
{
_tprintf(TEXT("InstanceThread WriteFile failed, GLE=%d.\n"), GetLastError());
break;
}
printf("Continuing..\n"); // qua ci arriva

}

// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the pipe, and close the
// handle to this pipe instance.

FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);

HeapFree(hHeap, 0, pchRequest);
HeapFree(hHeap, 0, pchReply);

printf("InstanceThread exiting.\n");
return 1;
}

VOID GetAnswerToRequest(LPTSTR pchRequest,
LPTSTR pchReply,
LPDWORD pchBytes)
// This routine is a simple function to print the client request to the console
// and populate the reply buffer with a default data string. This is where you
// would put the actual client request processing code that runs in the context
// of an instance thread. Keep in mind the main thread will continue to wait for
// and receive other client connections while the instance thread is working.
{
_tprintf(TEXT("Client Request String:\"%s\"\n"), pchRequest);

// Check the outgoing message to make sure it's not too long for the buffer.
if (FAILED(StringCchCopy(pchReply, BUFSIZE, TEXT("default answer from server"))))
{
*pchBytes = 0;
pchReply[0] = 0;
printf("StringCchCopy failed, no outgoing message.\n");
return;
}
*pchBytes = (lstrlen(pchReply) + 1) * sizeof(TCHAR);
}


这是C#代码:
 private static string pipeName = "mynamedpipe";

[...]

void Update()
{
if (Input.GetKey(KeyCode.C))
{
using (var client = new NamedPipeClientStream(pipeName))
{
client.Connect(100);
var writer = new StreamWriter(client);
var request = "Hi, server.";
writer.WriteLine(request);
writer.Flush();

var reader = new StreamReader(client);
var response = reader.ReadLine();
Debug.Log("Response from server: " + response);
}

}

}

的问题是: POST已更新,请不要在编辑时向下查询这些问题
  • 我不明白在哪里可以看到 pchReply 的内容或如何编辑它,注释说这是默认数据字符串,但是当数据交换完成后,C#程序读取的字符串是“d”。
  • 当C++服务器从C#接收到请求字符串时,应该是嗨,服务器,它应该在函数GetAnswerToRequest中打印它(C++代码的最后一个)。结果,我总是得到“客户端请求字符串:????”而不是“客户端请求字符串:嗨,服务器”
  • 这可能是最关键的:在我关闭c++服务器之前,C#客户端没有任何响应,它被阻止等待。我针对C++代码的本质进行了处理:有一个循环说> Loop,直到完成阅读为止,但此循环永不中断。另一个是初始的for(;;)

  • 希望您能对此提供帮助,如果您需要更多详细信息,我会在此发布它们,我担心这个问题已经足够长了哈哈。

    编辑1:

    感谢您的答复,我关注的事实是,无论在C#还是C++中,我都不需要任何 字符串类型,我需要将二进制文件从C++端传输到C#。这是我更新的内容:

    C++
      GetAnswerToRequest(pchRequest, pchReply, &cbReplyBytes);
    std::ifstream uncompressedFile;
    uncompressedFile.open("C:/Users/prova.p3d",std::ifstream::binary);
    std::streambuf* raw = uncompressedFile.rdbuf();

    fSuccess = WriteFile(
    hPipe, // handle to pipe
    pchReply, // buffer to write from
    cbReplyBytes, // number of bytes to write
    &cbWritten, // number of bytes written
    NULL); // not overlapped I/O


    VOID GetAnswerToRequest(LPTSTR pchRequest,
    LPTSTR pchReply,
    LPDWORD pchBytes)
    {

    if (FAILED(StringCchCopy(pchReply, BUFSIZE, TEXT("default answer \n from server"))))
    {
    *pchBytes = 0;
    pchReply[0] = 0;
    printf("StringCchCopy failed, no outgoing message.\n");
    return;
    }
    *pchBytes = (lstrlen(pchReply) + 1) * sizeof(TCHAR);
    }

    C#:
     byte[] buffer = new byte[512000];
    int bytesRead = client.Read(buffer, 0, 512000);

    int ReadLength = 0;
    for (int i = 0; i < bytesRead; i++)
    {
    ReadLength++;
    }

    if (ReadLength >0)
    {
    byte[] Rc = new byte[ReadLength];
    Buffer.BlockCopy(buffer, 0, Rc, 0, ReadLength);

    using(BinaryWriter binWriter = new BinaryWriter(File.Open("C:/Users/provolettaCS.p3d",FileMode.Create)))
    {
    binWriter.Write(Rc);
    binWriter.Close();
    }

    buffer.Initialize();

    现在,这可以在C++的标准响应下正常工作,这意味着我创建的文件包含以下内容:

    default answer from serverNULL (Don't know why there's that NULL in the end, though)



    但是我试图用自己的变量 pchReply交换 WriteFile函数中的“ raw”,即 uncompressedFile.rdbuf(),但是当我尝试保存文件C#时,我保存了一堆NULL。

    为了传输文件中的二进制信息,我还需要放置什么其他缓冲区而不是 pchReply

    最佳答案

    System.Stringstd::string是不同的对象,您需要在托管类型和非托管类型之间进行调度。

    这有点痛苦,您最好的选择是创建一个C++ / CLI包装器。检查此文件:
    https://docs.microsoft.com/en-us/cpp/dotnet/overview-of-marshaling-in-cpp?view=vs-2019

    关于c# - C#[在Unity中]和C++之间的命名管道,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61590037/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com