■ 채팅 서버/클라이언트를 만드는 방법을 보여준다.
[TestLibrary 프로젝트]
▶ ConnectRequest.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
namespace TestLibrary { /// <summary> /// 연결 요청 /// </summary> public class ConnectRequest { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 사용자명 - UserName /// <summary> /// 사용자명 /// </summary> public string UserName { get; set; } #endregion } } |
▶ ConnectResponse.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
namespace TestLibrary { /// <summary> /// 연결 응답 /// </summary> public class ConnectResponse { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 메시지 - Message /// <summary> /// 메시지 /// </summary> public string Message { get; set; } #endregion } } |
▶ NickNameRequest.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 |
namespace TestLibrary { /// <summary> /// 닉네임 요청 /// </summary> public class NickNameRequest { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 사용자명 - UserName /// <summary> /// 사용자명 /// </summary> public string UserName { get; set; } #endregion #region 신규 사용자명 - NewUserName /// <summary> /// 신규 사용자명 /// </summary> public string NewUserName { get; set; } #endregion } } |
▶ NickNameResponse.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 |
namespace TestLibrary { /// <summary> /// 닉네임 응답 /// </summary> public class NickNameResponse { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 사용자명 - UserName /// <summary> /// 사용자명 /// </summary> public string UserName { get; set; } #endregion #region 신규 사용자명 - NewUserName /// <summary> /// 신규 사용자명 /// </summary> public string NewUserName { get; set; } #endregion } } |
▶ SayRequest.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 |
namespace TestLibrary { /// <summary> /// 말하기 요청 /// </summary> public class SayRequest { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 사용자명 - UserName /// <summary> /// 사용자명 /// </summary> public string UserName { get; set; } #endregion #region 메시지 - Message /// <summary> /// 메시지 /// </summary> public string Message { get; set; } #endregion } } |
▶ SayResponse.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 |
namespace TestLibrary { /// <summary> /// 말하기 응답 /// </summary> public class SayResponse { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 사용자명 - UserName /// <summary> /// 사용자명 /// </summary> public string UserName { get; set; } #endregion #region 메시지 - Message /// <summary> /// 메시지 /// </summary> public string Message { get; set; } #endregion } } |
[TestServer 프로젝트]
▶ ChatServerActor.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 |
using System.Collections.Generic; using Akka.Actor; using TestLibrary; namespace TestServer { /// <summary> /// 채팅 서버 액터 /// </summary> public class ChatServerActor : ReceiveActor, ILogReceive { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 액터 참조 해시 세트 /// </summary> private readonly HashSet<IActorRef> actorRefHashSet = new HashSet<IActorRef>(); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - ChatServerActor() /// <summary> /// 생성자 /// </summary> public ChatServerActor() { Receive<ConnectRequest> ( connectRequest => { this.actorRefHashSet.Add(Sender); Sender.Tell ( new ConnectResponse { Message = "Hello and welcome to Akka.NET chat example", }, Self ); } ); Receive<NickNameRequest> ( nickNameRequest => { NickNameResponse nickNameResponse = new NickNameResponse { UserName = nickNameRequest.UserName, NewUserName = nickNameRequest.NewUserName, }; foreach(IActorRef actorRef in this.actorRefHashSet) { actorRef.Tell(nickNameResponse, Self); } } ); Receive<SayRequest> ( sayRequest => { SayResponse sayResponse = new SayResponse { UserName = sayRequest.UserName, Message = sayRequest.Message, }; foreach(IActorRef actorRef in this.actorRefHashSet) { actorRef.Tell(sayResponse, Self); } } ); } #endregion } } |
▶ 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 46 47 48 49 50 51 52 53 54 55 56 57 |
using System; using Akka.Actor; using Akka.Configuration; namespace TestServer { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { string hocon = @" akka { actor { provider = remote } remote { dot-netty.tcp { port = 9999 hostname = 0.0.0.0 public-hostname = localhost } } } "; Config config = ConfigurationFactory.ParseString(hocon); using(ActorSystem actorSystem = ActorSystem.Create("TestServer", config)) { actorSystem.ActorOf(Props.Create(() => new ChatServerActor()), "ChatServer"); Console.ReadLine(); } } #endregion } } |
[TestClient 프로젝트]
▶ ChatClientActor.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 |
using System; using Akka.Actor; using TestLibrary; namespace TestClient { /// <summary> /// 채팅 클라이언트 액터 /// </summary> public class ChatClientActor : ReceiveActor, ILogReceive { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 액터 선택 /// </summary> private readonly ActorSelection actorSelection = Context.ActorSelection("akka.tcp://TestServer@localhost:9999/user/ChatServer"); /// <summary> /// 닉네임 /// </summary> private string nickName = "Roggan"; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - ChatClientActor() /// <summary> /// 생성자 /// </summary> public ChatClientActor() { Receive<ConnectRequest> ( connectRequest => { Console.WriteLine("Connecting...."); this.actorSelection.Tell(connectRequest); } ); Receive<ConnectResponse> ( connectResponse => { Console.WriteLine("Connected!"); Console.WriteLine(connectResponse.Message); } ); Receive<NickNameRequest> ( nickNameRequest => { nickNameRequest.UserName = this.nickName; Console.WriteLine($"Changing nick to {nickNameRequest.NewUserName}"); this.nickName = nickNameRequest.NewUserName; this.actorSelection.Tell(nickNameRequest); } ); Receive<NickNameResponse> ( nickNameRequest => { Console.WriteLine($"{nickNameRequest.UserName} is now known as {nickNameRequest.NewUserName}"); } ); Receive<SayRequest> ( sayRequest => { sayRequest.UserName = this.nickName; this.actorSelection.Tell(sayRequest); } ); Receive<SayResponse> ( sayResponse => { Console.WriteLine($"{sayResponse.UserName} : {sayResponse.Message}"); } ); } #endregion } } |
▶ 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 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 |
using System; using System.Linq; using Akka.Actor; using Akka.Configuration; using TestLibrary; namespace TestClient { /// <summary> /// 프로그램 /// </summary> class Program { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region 프로그램 시작하기 - Main() /// <summary> /// 프로그램 시작하기 /// </summary> private static void Main() { string hocon = @" akka { actor { provider = remote } remote { dot-netty.tcp { port = 0 hostname = localhost } } } "; Config config = ConfigurationFactory.ParseString(hocon); using(ActorSystem actorSystem = ActorSystem.Create("TestClient", config)) { IActorRef actorRef = actorSystem.ActorOf(Props.Create<ChatClientActor>()); actorRef.Tell(new ConnectRequest() { UserName = "Roggan", }); while(true) { string input = Console.ReadLine(); if(input.StartsWith("/")) { string[] partArray = input.Split(' '); string command = partArray[0].ToLowerInvariant(); string rest = string.Join(" ", partArray.Skip(1)); if(command == "/nick") { actorRef.Tell(new NickNameRequest { NewUserName = rest }); } if(command == "/exit") { Console.WriteLine("exiting"); break; } } else { actorRef.Tell(new SayRequest() { Message = input }); } } actorSystem.Terminate().Wait(); } } #endregion } } |