Giới thiệu
Có nhiều phương thức giao tiếp giữa các tiến trình (IPC), trong bài viết này chúng ta sẽ tổng hợp các phương thức phổ biến để tham khảo.
Ống Đặt Tên (Named Pipes)
Ống đặt tên là một phương thức giao tiếp hiệu quả giữa các tiến trình trên cùng một máy.
Code máy chủ:
Console.WriteLine("Máy chủ Ống Đặt Tên đang hoạt động...");
using (var serverPipe = new NamedPipeServerStream("my_pipe_channel", PipeDirection.InOut))
{
Console.WriteLine("Chờ kết nối từ máy khách");
await serverPipe.WaitForConnectionAsync();
Console.WriteLine("Máy khách đã kết nối");
//Đọc tin nhắn từ máy khách
byte[] dataBuffer = new byte[2048];
int bytesReceived = await serverPipe.ReadAsync(dataBuffer, 0, dataBuffer.Length);
var clientMessage = Encoding.UTF8.GetString(dataBuffer, 0, bytesReceived);
Console.WriteLine("Nhận được tin nhắn từ máy khách: " + clientMessage);
//Gửi phản hồi
string serverResponse = "Xin chào từ máy chủ";
byte[] responseBuffer = Encoding.UTF8.GetBytes(serverResponse);
await serverPipe.WriteAsync(responseBuffer, 0, responseBuffer.Length);
Console.ReadLine();
}
Code máy khách:
Console.WriteLine("Máy khách Ống Đặt Tên đang hoạt động...");
using (var clientPipe = new NamedPipeClientStream(".", "my_pipe_channel", PipeDirection.InOut))
{
Console.WriteLine("Đang kết nối đến máy chủ");
await clientPipe.ConnectAsync();
Console.WriteLine("Đã kết nối đến máy chủ");
//Gửi tin nhắn
string messageToServer = "Xin chào, tôi là máy khách";
byte[] messageBuffer = Encoding.UTF8.GetBytes(messageToServer);
await clientPipe.WriteAsync(messageBuffer, 0, messageBuffer.Length);
//Đọc phản hồi
byte[] responseBuffer = new byte[2048];
int bytesRead = await clientPipe.ReadAsync(responseBuffer, 0, responseBuffer.Length);
var serverResponse = Encoding.UTF8.GetString(responseBuffer, 0, bytesRead);
Console.WriteLine("Nhận được phản hồi từ máy chủ: " + serverResponse);
Console.ReadLine();
}
Ống Ẩn Danh (Anonymous Pipes)
Ống ẩn danh thường được sử dụng cho giao tiếp giữa tiến trình cha và con, trong khi ống đặt tên có thể được sử dụng cho bất kỳ tiến trình nào.
Ứng dụng chính: Giao tiếp giữa tiến trình cha-con, truyền dữ liệu đơn hướng đơn giản, giao tiếp tạm thời không cần chia sẻ qua nhiều tiến trình.
class AnonymousPipeServer
{
static void Main(string[] args)
{
// Tạo ống ẩn danh
using (var pipeServer = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable))
{
Console.WriteLine("Tiến trình cha đang chạy...");
// Khởi động tiến trình con
var processInfo = new ProcessStartInfo("AnonymousPipeClient.exe");
processInfo.Arguments = pipeServer.GetClientHandleAsString();
processInfo.UseShellExecute = false;
using (var childProcess = Process.Start(processInfo))
{
// Gửi tin nhắn đến tiến trình con
using (var writer = new StreamWriter(pipeServer))
{
writer.AutoFlush = true;
writer.WriteLine("Xin chào từ tiến trình cha!");
}
// Chờ tiến trình con kết thúc
childProcess.WaitForExit();
}
}
}
}
Máy khách
using System;
using System.IO;
using System.IO.Pipes;
class AnonymousPipeClient
{
static void Main(string[] args)
{
// Lấy handle ống từ tiến trình cha
string pipeHandle = args[0];
using (var pipeClient = new AnonymousPipeClientStream(PipeDirection.In, pipeHandle))
{
Console.WriteLine("Tiến trình con đang chạy...");
// Đọc tin nhắn từ tiến trình cha
using (var reader = new StreamReader(pipeClient))
{
string message = reader.ReadLine();
Console.WriteLine($"Nhận từ tiến trình cha: {message}");
}
}
}
}
Tệp Định Dạng Bộ Nhớ (Memory-Mapped Files)
Tệp định dạng bộ nhớ cho phép nhiều tiến trình chia sẻ vùng bộ nhớ, phù hợp cho truyền tải dữ liệu lớn với hiệu suất cao.
Máy ghi
using System.IO.MemoryMappedFiles;
//Tệp định dạng bộ nhớ cho phép nhiều tiến trình chia sẻ vùng bộ nhớ, phù hợp cho truyền tải dữ liệu lớn.
Console.WriteLine("Máy ghi Tệp Định Dạng Bộ Nhớ khởi động~");
//Tạo một tệp định dạng bộ nhớ
using (var memoryMappedFile = MemoryMappedFile.CreateOrOpen("shared_memory", 15000))
{
//Tạo một bộ truy cập để xem
using (var accessor = memoryMappedFile.CreateViewAccessor())
{
Console.WriteLine("Tệp định dạng bộ nhớ đã tạo, chờ máy khách kết nối");
Console.ReadLine();
Console.WriteLine("Máy khách đã kết nối, bắt đầu ghi dữ liệu");
var message = "Xin chào từ máy ghi";
//Ghi dữ liệu
var dataArray = System.Text.Encoding.UTF8.GetBytes(message);
accessor.WriteArray(0, dataArray, 0, dataArray.Length);
Console.WriteLine("Hoàn tất ghi dữ liệu");
Console.ReadLine();
}
}
Máy đọc
using System.IO.MemoryMappedFiles;
using System.Text;
Console.WriteLine("Máy đọc Tệp Định Dạng Bộ Nhớ khởi động");
using (var memoryMappedFile = MemoryMappedFile.OpenExisting("shared_memory"))
{
Console.WriteLine("Tệp định dạng bộ nhớ đã được mở");
using (var accessor = memoryMappedFile.CreateViewAccessor())
{
var buffer = new byte[1500];
accessor.ReadArray(0, buffer, 0, buffer.Length);
string message = Encoding.UTF8.GetString(buffer);
Console.WriteLine("Đọc được dữ liệu: " + message);
Console.ReadLine();
}
}
Kênh Ipc
Kênh Ipc là một phương thức giao tiếp giữa các tiến trình dựa trên .NET Remoting, có hiệu suất cao, phù hợp cho giao tiếp giữa các tiến trình trên cùng một máy. Tuy nhiên, chỉ áp dụng cho .NET Framework: Kênh Ipc và .NET Remoting không áp dụng cho .NET Core và .NET 5+. .NET Remoting không hỗ trợ cơ chế bảo mật hiện đại, chỉ nên sử dụng trong môi trường đáng tin cậy.
Định nghĩa thư viện chung
public class RemoteService : MarshalByRefObject
{
public string GreetUser(string userName)
{
return $"Xin chào, {userName}!";
}
}
Máy chủ
static void Main(string[] args)
{
// Tạo và đăng ký Kênh Ipc
IpcServerChannel communicationChannel = new IpcServerChannel("MyIpcChannel");
ChannelServices.RegisterChannel(communicationChannel, false);
// Đăng ký đối tượng từ xa
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemoteService), // Loại đối tượng từ xa
"RemoteService.rem", // URI đối tượng từ xa
WellKnownObjectMode.Singleton); // Chế độ singleton
Console.WriteLine("Máy chủ đang chạy. Nhấn Enter để thoát...");
Console.ReadLine();
}
Máy khách
static void Main(string[] args)
{
// Tạo và đăng ký Kênh Ipc
IpcClientChannel clientChannel = new IpcClientChannel();
ChannelServices.RegisterChannel(clientChannel, false);
// Lấy đối tượng từ xa
RemoteService remoteService = (RemoteService)Activator.GetObject(
typeof(RemoteService), // Loại đối tượng từ xa
"ipc://MyIpcChannel/RemoteService.rem"); // URI đối tượng từ xa
// Gọi phương thức từ xa
string response = remoteService.GreetUser(" từ máy chủ");
Console.WriteLine($"Nhận từ máy chủ: {response}");
Console.WriteLine("Nhấn Enter để thoát...");
Console.ReadLine();
}
WCF
Phù hợp cho các kịch bản giao tiếp phức tạp, hỗ trợ nhiều giao thức.
Socket
Phù hợp cho giao tiếp mạng cần tùy chỉnh cao.
gRPC-----
Kết hợp hiệu suất cao và giao tiếp RPC đa ngôn ngữ.
gRPC trong .net - hướng dẫn sử dụng
Kênh Http
Kênh Tcp
Gửi Tin Nhắn Win32 Api
Tín hiệu Mutex
Địa chỉ code: https://gitee.com/xiaoqingyao/ipcdemo.git
Tham khảo:
Giao tiếp đa tiến trình C#, hôm nay, nó đã đến - blog园