如何将命名管道字符串从托管代码空间发送到托管代码空间?
我似乎遇到了命名管道 101 问题。我有一个非常简单的设置来连接从 C++ 非托管应用程序传输到 C# 托管应用程序的单工命名管道。管道已连接,但我无法通过管道发送“消息”,除非我关闭似乎刷新缓冲区并传递消息的句柄。就好像消息被屏蔽了一样。我尝试颠倒客户端/服务器的角色并使用不同的标志组合调用它们,但没有任何运气。我可以轻松地从 C# 托管到 C++ 非托管的另一个方向发送消息。有没有人有任何见解。你们中有人能成功地将消息从 C++ 非托管发送到 C# 托管吗?我可以找到大量内部管理或非托管管道的示例,但不能找到内部管理到/来自未管理的管道的示例 - 只是声称能够做到这一点。
在清单中,为了清楚起见,我省略了大部分包装材料。我认为相关的关键位是管道连接/创建/读写方法。不要太担心这里的阻塞/线程。
C# 服务器端
// This runs in its own thread and so it is OK to block
private void ConnectToClient()
{
// This server will listen to the sending client
if (m_InPipeStream == null)
{
m_InPipeStream =
new NamedPipeServerStream("TestPipe", PipeDirection.In, 1);
}
// Wait for client to connect to our server
m_InPipeStream.WaitForConnection();
// Verify client is running
if (!m_InPipeStream.IsConnected)
{
return;
}
// Start listening for messages on the client stream
if (m_InPipeStream != null && m_InPipeStream.CanRead)
{
ReadThread = new Thread(new ParameterizedThreadStart(Read));
ReadThread.Start(m_InPipeStream);
}
}
// This runs in its own thread and so it is OK to block
private void Read(object serverObj)
{
NamedPipeServerStream pipeStream = (NamedPipeServerStream)serverObj;
using (StreamReader sr = new StreamReader(pipeStream))
{
while (true)
{
string buffer = "" ;
try
{
// Blocks here until the handle is closed by the client-side!!
buffer = sr.ReadLine(); // <<<<<<<<<<<<<< Sticks here
}
catch
{
// Read error
break;
}
// Client has disconnected?
if (buffer == null || buffer.Length == 0)
break;
// Fire message received event if message is non-empty
if (MessageReceived != null && buffer != "")
{
MessageReceived(buffer);
}
}
}
}
C++ 客户端
// Static - running in its own thread.
DWORD CNamedPipe::ListenForServer(LPVOID arg)
{
// The calling app (this) is passed as the parameter
CNamedPipe* app = (CNamedPipe*)arg;
// Out-Pipe: connect as a client to a waiting server
app->m_hOutPipeHandle =
CreateFile("\\\\.\\pipe\\TestPipe",
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Could not create handle
if (app->m_hInPipeHandle == NULL ||
app->m_hInPipeHandle == INVALID_HANDLE_VALUE)
{
return 1;
}
return 0;
}
// Sends a message to the server
BOOL CNamedPipe::SendMessage(CString message)
{
DWORD dwSent;
if (m_hOutPipeHandle == NULL ||
m_hOutPipeHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
else
{
BOOL bOK =
WriteFile(m_hOutPipeHandle,
message, message.GetLength()+1, &dwSent, NULL);
//FlushFileBuffers(m_hOutPipeHandle); // <<<<<<< Tried this
return (!bOK || (message.GetLength()+1) != dwSent) ? FALSE : TRUE;
}
}
// Somewhere in the Windows C++/MFC code...
...
// This write is non-blocking. It just passes through having loaded the pipe.
m_pNamedPipe->SendMessage("Hi de hi");
...
I appear to have a named pipes 101 issue. I have a very simple set up to connect a simplex named pipe transmitting from a C++ unmanaged app to a C# managed app. The pipe connects, but I cannot send a "message" through the pipe unless I close the handle which appears to flush the buffer and pass the message through. It's like the message is blocked. I have tried reversing the roles of client/server and invoking them with different Flag combinations without any luck. I can easily send messages in the other direction from C# managed to C++ unmanaged. Does anyone have any insight. Can any of you guys successfully send messages from C++ unmanaged to C# managed? I can find plenty of examples of intra amanged or unmanaged pipes but not inter managed to/from unamanged - just claims to be able to do it.
In the listings, I have omitted much of the wrapper stuff for clarity. The key bits I believe that are relevant are the pipe connection/creation/read and write methods. Don't worry too much about blocking/threading here.
C# Server side
// This runs in its own thread and so it is OK to block
private void ConnectToClient()
{
// This server will listen to the sending client
if (m_InPipeStream == null)
{
m_InPipeStream =
new NamedPipeServerStream("TestPipe", PipeDirection.In, 1);
}
// Wait for client to connect to our server
m_InPipeStream.WaitForConnection();
// Verify client is running
if (!m_InPipeStream.IsConnected)
{
return;
}
// Start listening for messages on the client stream
if (m_InPipeStream != null && m_InPipeStream.CanRead)
{
ReadThread = new Thread(new ParameterizedThreadStart(Read));
ReadThread.Start(m_InPipeStream);
}
}
// This runs in its own thread and so it is OK to block
private void Read(object serverObj)
{
NamedPipeServerStream pipeStream = (NamedPipeServerStream)serverObj;
using (StreamReader sr = new StreamReader(pipeStream))
{
while (true)
{
string buffer = "" ;
try
{
// Blocks here until the handle is closed by the client-side!!
buffer = sr.ReadLine(); // <<<<<<<<<<<<<< Sticks here
}
catch
{
// Read error
break;
}
// Client has disconnected?
if (buffer == null || buffer.Length == 0)
break;
// Fire message received event if message is non-empty
if (MessageReceived != null && buffer != "")
{
MessageReceived(buffer);
}
}
}
}
C++ client side
// Static - running in its own thread.
DWORD CNamedPipe::ListenForServer(LPVOID arg)
{
// The calling app (this) is passed as the parameter
CNamedPipe* app = (CNamedPipe*)arg;
// Out-Pipe: connect as a client to a waiting server
app->m_hOutPipeHandle =
CreateFile("\\\\.\\pipe\\TestPipe",
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Could not create handle
if (app->m_hInPipeHandle == NULL ||
app->m_hInPipeHandle == INVALID_HANDLE_VALUE)
{
return 1;
}
return 0;
}
// Sends a message to the server
BOOL CNamedPipe::SendMessage(CString message)
{
DWORD dwSent;
if (m_hOutPipeHandle == NULL ||
m_hOutPipeHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
else
{
BOOL bOK =
WriteFile(m_hOutPipeHandle,
message, message.GetLength()+1, &dwSent, NULL);
//FlushFileBuffers(m_hOutPipeHandle); // <<<<<<< Tried this
return (!bOK || (message.GetLength()+1) != dwSent) ? FALSE : TRUE;
}
}
// Somewhere in the Windows C++/MFC code...
...
// This write is non-blocking. It just passes through having loaded the pipe.
m_pNamedPipe->SendMessage("Hi de hi");
...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
sr.ReadLine() 期望看到换行符来知道行尾。因为它既没有收到换行符也没有收到流结束符,所以它会等待更多。
尝试:
或一些 sr.Read() 方法。
sr.ReadLine() expects to see a newline character(s) to know the end of the line. Because it receives neither new-line nor end-of-stream, it waits for more.
Try:
or some of the sr.Read() methods.