■ MemoryMappedFile 클래스의 CreateNew 정적 메소드를 사용해 시스템 메모리에서 메모리 매핑 파일을 만드는 방법을 보여준다.
[TestLibrary 프로젝트]
▶ SharedMemoryHelper.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
using System.IO.MemoryMappedFiles; namespace TestLibrary { /// <summary> /// 공유 메모리 헬퍼 /// </summary> public static class SharedMemoryHelper { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 쓰기 - Write<T>(mapName, mapSize, offset, source) /// <summary> /// 쓰기 /// </summary> /// <typeparam name="T">구조체 타입</typeparam> /// <param name="mapName">맵 명칭</param> /// <param name="mapSize">맵 크기</param> /// <param name="offset">위치</param> /// <param name="source">소스</param> public static void Write<T>(string mapName, long mapSize, long offset, T source) where T : struct { MemoryMappedFile file = MemoryMappedFile.CreateNew(mapName, mapSize); MemoryMappedViewAccessor accessor = file.CreateViewAccessor(); accessor.Write<T>(offset, ref source); } #endregion #region 읽기 - Read<T>(mapName, offset) /// <summary> /// 읽기 /// </summary> /// <typeparam name="T">구조체 타입</typeparam> /// <param name="mapName">맵 명칭</param> /// <param name="offset">오프셋</param> /// <returns>구조체</returns> public static T Read<T>(string mapName, long offset) where T : struct { using(MemoryMappedFile file = MemoryMappedFile.OpenExisting(mapName)) { using(MemoryMappedViewStream stream = file.CreateViewStream(0, StructureHelper.SizeOf(typeof(T)))) { using(MemoryMappedViewAccessor accessor = file.CreateViewAccessor()) { T target; accessor.Read(offset, out target); return target; } } } } #endregion } } |
▶ StructureHelper.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
using System; using System.Collections.Generic; using System.Reflection.Emit; using System.Runtime.InteropServices; namespace TestLibrary { /// <summary> /// 구조체 헬퍼 /// </summary> public static class StructureHelper { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 타입 딕셔너리 /// </summary> private static Dictionary<Type, int> _typeDictionary = new Dictionary<Type, int>(); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 크기 구하기 - SizeOf(type) /// <summary> /// 크기 구하기 /// </summary> /// <param name="type">타입</param> /// <returns>크기</returns> public static int SizeOf(Type type) { int size; if(_typeDictionary.TryGetValue(type, out size)) { return size; } size = GetSize(type); _typeDictionary.Add(type, size); return size; } #endregion #region 복사하기 - Copy(source, target) /// <summary> /// 복사하기 /// </summary> /// <param name="source">소스 문자열</param> /// <param name="target">타겟 포인터</param> public unsafe static void Copy(string source, char* target) { char[] sourceCharArray = source.ToCharArray(); Marshal.Copy(sourceCharArray, 0, new IntPtr(target), sourceCharArray.Length); } #endregion #region 문자열 구하기 - GetString(sourcePointer) /// <summary> /// 문자열 구하기 /// </summary> /// <param name="sourcePointer">소스 포인터</param> /// <returns>문자열</returns> public unsafe static string GetString(char* sourcePointer) { return new string(sourcePointer); } #endregion //////////////////////////////////////////////////////////////////////////////// Private #region 크기 - GetSize(type) /// <summary> /// 크기 구하기 /// </summary> /// <param name="type">타입</param> /// <returns>크기</returns> private static int GetSize(Type type) { DynamicMethod dynamicMethod = new DynamicMethod("SizeOfType", typeof(int), new Type[] { }); ILGenerator ilGenerator = dynamicMethod.GetILGenerator(); ilGenerator.Emit(OpCodes.Sizeof, type); ilGenerator.Emit(OpCodes.Ret); return (int)dynamicMethod.Invoke(null, null); } #endregion } } |
▶ Student.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
using System; namespace TestLibrary { /// <summary> /// 학생 /// </summary> public unsafe struct Student { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region Field /// <summary> /// ID /// </summary> public int ID; /// <summary> /// 성명 /// </summary> public fixed char Name[20]; /// <summary> /// 생성 시간 /// </summary> public DateTime CreateTime; #endregion } } |
[TestServer 프로젝트]
▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
using System; using TestLibrary; namespace TestServer { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private unsafe static void Main() { Console.WriteLine("공유 메모리 쓰기를 실행합니다."); Student student = new Student(); student.ID = 1; student.CreateTime = DateTime.Now; StructureHelper.Copy("홍길동", student.Name); SharedMemoryHelper.Write("testMap", 1000, 0, student); Console.WriteLine($"ID : {student.ID}"); Console.WriteLine($"성명 : {StructureHelper.GetString(student.Name)}"); Console.WriteLine($"생성 시간 : {student.CreateTime}"); Console.ReadKey(false); } #endregion } } |
[TestClient 프로젝트]
▶ Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
using System; using System.Threading; using TestLibrary; namespace TestClient { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private unsafe static void Main() { Thread.Sleep(1000); // 테스트시 서버에서 공유 메모리를 쓰는 시간을 반영한다. Console.WriteLine("공유 메모리 읽기를 실행합니다."); Student student = SharedMemoryHelper.Read<Student>("testMap", 0); Console.WriteLine($"ID : {student.ID}"); Console.WriteLine($"성명 : {StructureHelper.GetString(student.Name)}"); Console.WriteLine($"생성 시간 : {student.CreateTime}"); Console.ReadKey(false); } #endregion } } |