我正在研究一種在C#和C++之間使用命名管道的解決方案,我在某種程度上正在努力。服務器是C#,客戶端是C++。我的問題是,我不能總是重新連接到服務。客戶端需要能夠連接,斷開,連接,斷開......。第一個連接沒有問題,但有時重新連接失敗,客戶端上的ERROR_FILE_NOT_FOUND。通過NamedPipe將C++客戶端重新連接到C#服務器
我附上示例代碼。我的測試已在兩臺不同的計算機上進行。第一個,我必須徹底刪除客戶端中的Sleep()以獲得失敗狀態。在第二臺計算機上,失敗情況通常在第二次或第三次通過外部while循環時達到。請注意,這是我的問題的一個例子或模擬。我在實際工作中的規模更大。具有非常大的發送緩衝區。我現在的猜測是,在某些情況下,文件清理速度不夠快,但我真的不確定如何解決問題。我正在關閉我所知道的一切。
服務器:
public class NamedPipeServer
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern SafeFileHandle CreateNamedPipe(String pipeName,
uint dwOpenMode,
uint dwPipeMode,
uint nMaxInstances,
uint nOutBufferSize,
uint nInBufferSize,
uint nDefaultTimeOut,
IntPtr lpSecurityAttributes);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int ConnectNamedPipe(SafeFileHandle hNamedPipe,
IntPtr lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int DisconnectNamedPipe(SafeFileHandle hNamedPipe);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int GetLastError();
public const uint INBOUND = (0x00000001);
public const uint FILE_FLAG_OVERLAPPED = (0x40000000);
public const uint REJECT_REMOTE_CLIENTS = (0x00000008);
public const uint READMODE_BYTE = (0x00000000);
public bool NamePipeProcessing = false;
private const int BUFFER_SIZE = 100;
private SafeFileHandle _pipeHandle;
private Client _clientInfo;
private Thread _listenThread;
private Thread _receiveThread;
private string _pipeName;
public class Client
{
public SafeFileHandle handle;
public FileStream stream;
}
public NamedPipeServer(string pipeName)
{
_pipeName = pipeName;
_clientInfo = new Client();
_listenThread = new Thread(new ThreadStart(ConnectionManager));
_listenThread.Start();
}
private void ConnectionManager()
{
while (NamePipeProcessing)
{
_pipeHandle = CreateNamedPipe(_pipeName, INBOUND|FILE_FLAG_OVERLAPPED,
REJECT_REMOTE_CLIENTS|READMODE_BYTE,
1, 0, BUFFER_SIZE, 0, IntPtr.Zero);
// could not create namedPipe
if (_pipeHandle.IsInvalid)
return;
int errorCode = GetLastError();
Console.WriteLine("pipe created "+ _pipeName + " ErrorCode:" + errorCode);
//THIS IS A BLOCKING CALL
int success = ConnectNamedPipe(_pipeHandle , IntPtr.Zero);
// could not connect to client
if (success == 0)
{
return;
}
_clientInfo.handle = _pipeHandle;
_clientInfo.stream = new FileStream(_clientInfo.handle, FileAccess.Read, BUFFER_SIZE, true);
_receiveThread = new Thread(new ThreadStart(Receiver));
_receiveThread.Start();
_receiveThread.Join();
}
}
private void Receiver()
{
int bytesReceived = 0;
byte[] buffer = null;
while (NamePipeProcessing)
{
bytesReceived = 0;
// Attempt to received data from pipe
try
{
buffer = new byte[BUFFER_SIZE];
//THIS IS A BLOCKING CALL
bytesReceived = _clientInfo.stream.Read(buffer, 0, BUFFER_SIZE);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
break;
}
// client has disconnected
if (bytesReceived == 0)
{
Console.WriteLine(" No bytes Received");
break;
}
// if data was received
if (bytesReceived > 0)
{
// handle message
Console.WriteLine("Received: " + bytesReceived.ToString());
}
}
_clientInfo.stream.Close();
_clientInfo.handle.Close();
_clientInfo.stream.Dispose();
_clientInfo.handle.Dispose();
}
public void StopServer()
{
try
{
NamePipeProcessing = false;
DisconnectNamedPipe(_pipeHandle);
_listenThread.Abort();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
Class Program
{
static void Main(string[] args)
{
NamedPipeServer PServer = new NamedPipeServer(@"\\.\pipe\myNamedPipe");
NamedPipeServer PS string Ms="Start";
PServer.NamePipeProcessing = true;
do
{
//Console.WriteLine("Enter quit to exit server");
Ms = Console.ReadLine();
//PServer2.SendMessage(Ms, PServer2.clientse);
} while (Ms != "quit");
PServer.StopServer();
Console.WriteLine("Press any key to stop");
Console.ReadKey();
}
客戶:
int _tmain(int argc, _TCHAR* argv[])
{
BYTE* byteArray = (BYTE*) malloc(BUFFER_SIZE);
DWORD cbWritten = (DWORD)strlen((const char*)byteArray);;
int count = 0;
int count2 = 0;
int value = 10;
while(count2 < 5)
{
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\myNamedPipe");
hPipe=CreateFile(lpszPipename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if ((hPipe == NULL || hPipe == INVALID_HANDLE_VALUE))
{
printf("Could not open the pipe - (error %ld)\n",GetLastError());
}
else
{
printf("Send data\n");
while(count < 3)
{
byteArray[0] = value;
byteArray[1] = value + 10;
byteArray[2] = value + 1;
byteArray[3] = value + 20;
byteArray[4] = value - 5;
byteArray[5] = value + 30;
value = 10;
WriteFile(hPipe, byteArray, 10, &cbWritten, NULL);
Sleep(1);
if(count != 3)
count +=1;
}
}
CloseHandle(hPipe);
count = 0 ;
count2 += 1;
Sleep(1);
printf("Done Sending\n");
}
free(byteArray);
printf("Press any key to exit..."); fflush(0);
_getch();
return 0;
}
進程互操作永遠是脆弱的,你只是不知道在其他進程中發生了什麼。有明顯的失敗模式,比如嘗試連接過早(等待)或嘗試重新連接到不存在的進程(如此放棄)。 –