프로그래밍/C#

클라이언트 서버 예제 3

mi-nos 2024. 5. 14. 00:29

 

서버 > 중간프로그램 > 디바이스 로 전송/수신 되는 프로그램이며, 

외부 프로그램은 서버와  디바이스이고, 중간프로그램이 아래 동작 코드이다. 

 

아래 코드는 서버에서 아래 형태의 Json 데이터를 받으면 

{"command":"CMD_002","targetDevice":["DEVICE_083","DEVICE_015"],"param":"ce3c39e1"}

 

device.json 파일에서 아래 정보를 읽은 후 

{  "deviceInfo":[
      {"device":"DEVICE_069", "hostname":"127.0.0.1", "port":9010},
      {"device":"DEVICE_083", "hostname":"127.0.0.1", "port":9020},
      {"device":"DEVICE_015", "hostname":"127.0.0.1", "port":9030}
   ]
}

server_command.json 에서 아래 정보를 읽은 후 

{  "serverCommandInfo":[
      {"command":"CMD_001", "forwardCommand":"CMD_001_A"},
      {"command":"CMD_002", "forwardCommand":"CMD_002_B"}
   ]
}

 

조합하여 아래형식으로 디바이스로 전달 한다. 

{"command":"CMD_002_B","param":"ce3c39e1"}

 

서버전송은 아래 정보를 참고한다. 

구분                                              URI
Server로부터의 Request            POST http://127.0.0.1:8010/ fromServer
Device로의 Request                   POST http://<Device hostname>:<Device port>/ fromEdge

 

그러면 아래 형식으로 response를 받게 되고, 

 Device 083 응답 : {"result":["c8d4fc55"]}

Device 015 응답 : {"result":["9604d2cd"]}

 

디바이스 별로 전달되는 것을 취합하여 아래형식으로 최종 서버에 응답한다. 

{"result":["c8d4fc55","9604d2cd"]}

 

 

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;

namespace SP_TEST
{
    class DeviceInfo
    {
        public string device = null;
        public string hostname = null;
        public int port = 0;
    }

    class Program
    {
        // Command Info 관리 리스트 
        static Dictionary<string, string> CmdInfo = new Dictionary<string, string>();
        static Dictionary<string, DeviceInfo> dicDeviceInfo = new Dictionary<string, DeviceInfo>();

        static void Main(string[] args)
        {
            //// 파일로부터 Command Info 읽어오기 
            LoadCmdInfo();
            LoadDeviceInfo();

            HttpListener listener = new HttpListener();
            listener.Prefixes.Add("http://127.0.0.1:8010/");
            listener.Start();

            while (true)
            {
                var context = listener.GetContext();
                Console.WriteLine(string.Format(">>>>>>>>>>>>>>[{0}] Request({1}) : {2}", DateTime.Now.ToString("hh:mm:ss.fff"), context.Request.HttpMethod, context.Request.Url));

                Thread th = new Thread(Http_Server);
                th.Start(context);
            }
        }

        static void Http_Server(Object obj)
        {
            string strRes = null;
            HttpListenerContext context = (HttpListenerContext)obj;

            Console.WriteLine("Http_Server Thread Start : " + context.Request.RawUrl);

            StreamReader sr = new StreamReader(context.Request.InputStream);
            JObject body = JObject.Parse(sr.ReadToEnd());
            sr.Close();
            Console.WriteLine("body : " + body);

            switch (context.Request.RawUrl)
            {
                case "/fromServer":
                    strRes = sendToDevices(body["command"].ToString(), body["param"].ToString(), body["targetDevice"].ToObject<List<string>>());
                    break;
                default:
                    Console.WriteLine("error");
                    break;
            }

            if (strRes != null)
            {
                byte[] data = Encoding.UTF8.GetBytes(strRes);
                context.Response.OutputStream.Write(data, 0, data.Length);
            }
            context.Response.StatusCode = 200;
            context.Response.Close();
        }

        static string sendToDevices(string command, string param, List<string> targetDevice)
        {
            JObject jRes = new JObject();
            jRes["result"] = new JArray(); // device들로부터 전달되는 결과값들
            foreach (string deviceId in targetDevice)
            {
                string forwardCommand = CmdInfo[command];
                JObject deviceRet = sendToDevice(deviceId, forwardCommand, param);
                ((JArray)jRes["result"]).Add(deviceRet.GetValue("result").First);
            }
            return jRes.ToString();
        }

        // 특정 device에 command 전송
        static JObject sendToDevice(string device, string command, string param)
        {
            string url = string.Format("http://{0}:{1}/fromEdge", dicDeviceInfo[device].hostname, dicDeviceInfo[device].port);
            HttpClient client = new HttpClient();
            HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, url);

            dynamic body = new JObject();
            body.command = command;
            body.param = param;
            Console.WriteLine($"Send to device : {url}, {body}");
            httpRequestMessage.Content = new StringContent(body.ToString(), Encoding.UTF8, "application/json");

            var res = client.SendAsync(httpRequestMessage).Result;
            string strRes = res.Content.ReadAsStringAsync().Result;
            Console.WriteLine($"Response : {strRes}");
            return JObject.Parse(strRes);
        }

        // 파일로부터 Command Info 사용하기 쉽게 읽어오기 
        static void LoadCmdInfo()
        {
            JObject jObj = JObject.Parse(File.ReadAllText(".\\INFO\\SERVER_COMMAND.JSON"));
            foreach (JObject cmd in jObj["serverCommandInfo"])
            {
                CmdInfo[cmd["command"].ToString()] = cmd["forwardCommand"].ToString();
            }
        }

        // 파일로부터 Device Info 사용하기 쉽게 읽어오기
        static void LoadDeviceInfo()
        {
            JObject jObj = JObject.Parse(File.ReadAllText(".\\INFO\\DEVICE.JSON"));
            foreach (JObject device in jObj["deviceInfo"])
            {
                DeviceInfo deviceInfo = device.ToObject<DeviceInfo>();
                dicDeviceInfo.Add(deviceInfo.device, deviceInfo);
            }
        }
    }
}