メモリマップされたファイルがどのように動作するかを誰かが理解できるようになることを本当に願っています。私はオンラインで多くの研究をしてきましたが、時には助けを求めるのが簡単です。メモリマップファイルを使用して、同じコンピュータ上のサーバとクライアント間で通信するにはどうすればよいですか?
私は実行しているサーバー上にドキュメント作成システムを作成しています。クライアントプログラム(それ自体がファイルを要求する実際のクライアントへのサービス)に要求に応じてテンプレートファイルを提供するサービスを作成したいと思います。
ユーザーがファイルを要求するたびにサーバーがハードドライブにアクセスする必要がないように、テンプレートファイルをメモリに保存します。
問題のファイルが大きすぎるため、パイプ接続を使用できません。私は、ソケットスタイルの接続を使用するか、ファイルをより小さな部分に分割することができますが、この問題を解決するように設計されているメモリマップファイルよりもあまり良い解決策ではないようです。 2つのプロセス間で大きなファイルを共有できます。
私はファイル名を@ "グローバル\" +ファイル名(コードを参照)に変更するまで、メモリマップされたファイルを動作させることができませんでした。これはしばらくの間働いていましたが、それは動作を停止しました - しかし、私は私が何を変更したのか分かりません。その考えはhereです。私は、 "グローバル"プリペンドが何をしても、私の問題の解決策に関係していると思います。なぜなら、Windowsメモリはファイルシステムがフォーマットされたのと同様の方法で分割されており、プロセスによってアクセスレベルが異なる可能性があるからです。ここで
は、サービスからのコードです:クライアント側のコードここpublic partial class TemplateDistributorService : ServiceBase
{
protected ServiceHost host;
public static Dictionary<string, System.IO.MemoryMappedFiles.MemoryMappedFile> memFiles;
public static Dictionary<string, int> fileSizes;
public TemplateDistributorService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
memFiles = new Dictionary<string, System.IO.MemoryMappedFiles.MemoryMappedFile>();
fileSizes = new Dictionary<string, int>();
foreach (var path in args)
{
string fileName = @"Global\" + System.IO.Path.GetFileNameWithoutExtension(path);
var sz = new System.IO.FileInfo(path).Length;
//all files must be less than 2GB for easier programming. I don't anticipate
//this being a problem, and if it does become one, we can up this to the max system file size (4 GB)
if (sz <= System.Int32.MaxValue)
{
using (System.IO.MemoryMappedFiles.MemoryMappedFile mmf =
System.IO.MemoryMappedFiles.MemoryMappedFile.CreateNew(fileName,
sz, System.IO.MemoryMappedFiles.MemoryMappedFileAccess.ReadWrite))
{
fileSizes[fileName] = System.Convert.ToInt32(sz);
using (var stream = mmf.CreateViewStream())
{
using (var writer = new System.IO.BinaryWriter(stream))
{
byte[] fileBytes = System.IO.File.ReadAllBytes(path);
writer.Write(fileBytes);
}
}
memFiles[fileName] = mmf;
}
}
}
host = new ServiceHost(typeof(TemplateDistributor));
host.AddServiceEndpoint(typeof(TemplateDistributorInterface),
new NetNamedPipeBinding(),
"net.pipe://localhost/PipedTemplateAccess");
host.Open();
}
protected override void OnStop()
{
host.Close();
}
}
[ServiceContract]
public interface TemplateDistributorInterface
{
[OperationContract]
int AddFile(string path, string fileName);
[OperationContract]
int FileSize(string fileName);
}
public class TemplateDistributor : TemplateDistributorInterface
{
public int AddFile(string path, string fileName)
{
//prepending the filename with 'Global\' is really important. Not sure why, but you can't access the memory mapped file without it
//https://stackoverflow.com/questions/11301978/memory-mapped-file-and-win-service-cannot-find-file-created-by-server
//string fileName = @"Global\" + System.IO.Path.GetFileNameWithoutExtension(path);
if (TemplateDistributorService.memFiles.ContainsKey(fileName))
{
if (TemplateDistributorService.memFiles[fileName] != null)
{
return 0;
}
else
{
return -1;
}
}
var sz = new System.IO.FileInfo(path).Length;
if (sz > System.Int32.MaxValue)
{
return -1;
}
using (System.IO.MemoryMappedFiles.MemoryMappedFile mmf =
System.IO.MemoryMappedFiles.MemoryMappedFile.CreateNew(fileName, sz, System.IO.MemoryMappedFiles.MemoryMappedFileAccess.ReadWrite))
{
TemplateDistributorService.fileSizes[fileName] = System.Convert.ToInt32(sz);
using (var stream = mmf.CreateViewStream())
{
using (var writer = new System.IO.BinaryWriter(stream))
{
byte[] fileBytes = System.IO.File.ReadAllBytes(path);
writer.Write(fileBytes);
}
}
TemplateDistributorService.memFiles[fileName] = mmf;
}
return 1;
}
public int FileSize(string fileName)
{
if (TemplateDistributorService.fileSizes.ContainsKey(fileName))
{
return TemplateDistributorService.fileSizes[fileName];
}
else
{
return 0;
}
}
}
れる(例外:「型 『System.IO.FileNotFoundException』の未処理の例外をSystem.Core.dllに発生しました」私がメモリマップファイルを開こうとするとき):
[ServiceContract]
public interface TemplateDistributorInterface
{
[OperationContract]
int AddFile(string path, string fileName);
[OperationContract]
int FileSize(string fileName);
}
class Program
{
static void Main(string[] args)
{
TestDocService();
}
static void TestDocService()
{
var path = @"C:\Users\jack.geiger\Documents\BuschFTP.docx";
ChannelFactory<TemplateDistributorInterface> streamPipeFactory =
new ChannelFactory<TemplateDistributorInterface>(
new NetNamedPipeBinding(),
new EndpointAddress(
"net.pipe://localhost/PipedTemplateAccess"));
TemplateDistributorInterface streamPipeProxy = streamPipeFactory.CreateChannel();
string fileName = @"Global\Restricted\" + System.IO.Path.GetFileNameWithoutExtension(path);
var f = streamPipeProxy.AddFile(path, fileName);
f = streamPipeProxy.AddFile(path, fileName);
//prepending the filename with 'Global\' is really important. Not sure why, but you can't access the memory mapped file without it
//https://stackoverflow.com/questions/11301978/memory-mapped-file-and-win-service-cannot-find-file-created-by-server
//mmf is being created in service, but I can't find it here for some reason
using (System.IO.MemoryMappedFiles.MemoryMappedFile mmf =
System.IO.MemoryMappedFiles.MemoryMappedFile.OpenExisting(
fileName,
System.IO.MemoryMappedFiles.MemoryMappedFileRights.Read,
System.IO.HandleInheritability.None))
{
using (var stream = mmf.CreateViewStream(0, 0, System.IO.MemoryMappedFiles.MemoryMappedFileAccess.Read))
{
using (System.IO.BinaryReader binReader = new System.IO.BinaryReader(stream))
{
var fileSize = streamPipeProxy.FileSize(fileName);
var bts = binReader.ReadBytes(streamPipeProxy.FileSize(fileName));
using (System.IO.MemoryStream memStr = new System.IO.MemoryStream())
{
memStr.Read(bts, 0, bts.Length);
memStr.Seek(0, System.IO.SeekOrigin.Begin);
using (WordprocessingDocument template = WordprocessingDocument.Create(memStr, WordprocessingDocumentType.Document))
{
template.MainDocumentPart.Document.RemoveAllChildren();
}
}
}
}
}
}
は、サーバーが実際にエラーなし「グローバルの\ somefileという」を作成していますか? – RbMm
はい、私はそれをデバッグしました。また、追加のサニティチェックとして、クライアントアプリケーションの "f"の値をチェックすることができます。ファイルが正常に生成されたことを示す1を返します(サーバーを再起動せずに2回デバッグしない限り、0を返します。 ) –
'WinObj.exe'をとる - 「メモリマップファイル」「グローバル\ SomeName」を作成するときに' \ BaseNamedObjects \ SomeName' *セクション*オブジェクトを作成する必要があります。 * Open * 'Global \ BuschFTP.docx' - checkは' \ BaseNamedObjects \ BuschFTP.docx'です* section *は存在しますか? – RbMm