레이블이 C#인 게시물을 표시합니다. 모든 게시물 표시
레이블이 C#인 게시물을 표시합니다. 모든 게시물 표시

2022년 9월 14일 수요일

Unity SearchLogic 개선(List 처리 추가, 중복검색 클래스)

 



인자로 리스트 있을때 처리


///ProductName은 리스트 구조라서 람다식안에서 foreach를 한번 돌려줬다


이렇게 해서 해결


public List<CompanyInfo> SearhCompanyInf(int value, string input, bool sort= true)
    {
        Func<CompanyInfo, bool> condition;
        //Func<CompanyInfo, object> order;
        string search = input.ToLower();

        //if (value < 0 || value >= searchDropdown.options.Count)
        //    return new List<FixtureItemData>();
        switch (value) //Dropdown value에 따라 조건 설정
        {
            case 0: // 제조사
                condition = item => item.CompanyName.ToLower().Contains(search);
                //order = item => item.CompanyName;
                break;
            case 1: // 조명 이름

                ///ProductName은 리스트 구조라서 람다식안에서 foreach를 한번 돌려줬다
                condition = item =>
                {
                    foreach (var x in item.ProductNames)
                    {
                        if (x.Contains(search))
                            return true;
                    }
                    return false;
                };
                //order = item => item.ProductNames;
               
               


                //condition = item => item.FindCompany(search);
                //order = item => item.ProductNames;
                break;
            //case 2: // 채널
            //    condition = item => item.channelList.Count.ToString().Contains(search);
            //    order = item => item.channelList.Count;
            //    break;
            default: //모드
                condition = item => item.CompanyName.ToLower().Contains(search);
                //order = item => item.CompanyName;
                break;
        }

        int i = 1;
        IEnumerable<CompanyInfo> result;

        result = originTable.Where(condition);


        //result = sort ? result.OrderByDescending(order) : result.OrderBy(order);

        result = result.Select(x => new CompanyInfo
        {
            CompanyName = x.CompanyName,
            floorIdx = x.floorIdx,
            ProductNames = x.ProductNames
        });

        return result.ToList();

    }




///중복검색 제거 클래스
public class CompanyUiItem
{
    public string companyName;
    public string companyType;
    public string url;
    public List<string> products;
    public List<string> cars;


    public override bool Equals(object obj)
    {
        return this.companyName == ((CompanyUiItem)obj).companyName &&
            this.companyType == ((CompanyUiItem)obj).companyType &&
            this.cars.SequenceEqual(((CompanyUiItem)obj).cars)&&
            this.products.SequenceEqual(((CompanyUiItem)obj).products)
            ;
    }
    public override int GetHashCode()
    {
        return companyName.GetHashCode() ^ companyType.GetHashCode() ^ cars.GetHashCode()^products.GetHashCode();
    }

}


///다른방식의 검색

public List<CompanyUiItem> SearchTableData(string input)
    {
        if (input.Length == 0)
            return originTable;


        Func<CompanyUiItem,bool> condition_car; //검색 조건
        Func<CompanyUiItem, bool> condition_products; //검색 조건
        Func<CompanyUiItem, bool> condition_companyName; //검색 조건
        Func<CompanyUiItem, bool> condition_companyType; //검색 조건
       
        //Func<CompanyUiItem, object> order; //정렬 기준
        string search = input.ToLower(); //소문자로 변환

        condition_car = item => item.cars.Where(x=> x.ToLower().Contains(search)).Any();
        condition_products = item => item.products.Where(x => x.ToLower().Contains(search)).Any();
        condition_companyName = item => item.companyName.ToLower().Contains(search);
        condition_companyType = item => item.companyType.ToLower().Contains(search);






       
        IEnumerable<CompanyUiItem> result_car;
        IEnumerable<CompanyUiItem> result_products;
        IEnumerable<CompanyUiItem> result_company;
        IEnumerable<CompanyUiItem> result_type;

        result_car = originTable.Where(condition_car);
        result_products = originTable.Where(condition_products);
        result_company = originTable.Where(condition_companyName);
        result_type = originTable.Where(condition_companyType);

        //result = originTable.Where(condition_car).Where(condition_companyName).Where(condition_companyType).Where(condition_products);
        result_car = result_car.Select(x => new CompanyUiItem
        {
            companyName = x.companyName,
            companyType = x.companyType,
            cars = x.cars,
            products = x.products,
            url = x.url,
        });
        result_products = result_products.Select(x => new CompanyUiItem
        {
            companyName = x.companyName,
            companyType = x.companyType,
            cars = x.cars,
            products = x.products,
            url = x.url,
        });
        result_company = result_company.Select(x => new CompanyUiItem
        {
            companyName = x.companyName,
            companyType = x.companyType,
            cars = x.cars,
            products = x.products,
            url = x.url,
        });
        result_type = result_type.Select(x => new CompanyUiItem
        {
            companyName = x.companyName,
            companyType = x.companyType,
            cars = x.cars,
            products = x.products,
            url = x.url,
        });


       

       
        IEnumerable<CompanyUiItem> result  =
            new[] { result_car, result_products, result_company, result_type }.
            Where(x=>x!=null).
            SelectMany(x => x).
            Distinct();

       


        //Debug.Log($"car {result_car.Count()}");
        //Debug.Log($"products {result_products.Count()}");
        //Debug.Log($"result_company {result_company.Count()}");
        //Debug.Log($"result_type {result_type.Count()}");


        //Debug.Log($"result{result.Count()}");

        return result.ToList();
    }

2022년 4월 22일 금요일

( c# create class object by name) c# 이름으로 클래스 객체 생성

 


using System.Reflection;


public object GenNewClass(string Type)
{
    Assembly creator = Assembly.GetExecutingAssembly();
    object obj = creator.CreateInstance(Type);
    return obj;
}


foreach (PacketID state in Enum.GetValues(typeof(PacketID)))
{
    ts.Add(GenNewClass(state.ToString()));
}

(Check all arguments of an Enum)Enum의 모든 인자 확인하기

 




public enum customEnum
{
  aaaa,
  bbbb,
  ccccc,
  ddddd,
}

foreach (customEnum item in Enum.GetValues(typeof(customEnum)))
{
  Console.WriteLine(item.ToString());
}

2022년 4월 21일 목요일

c# A function that changes the value of a specific class field(특정클래스 필드값 변경하는 함수)

/// <summary>
        /// 특정클래스의 field값을 변경하는 함수
        /// ex) m_PLC_Data.Field_Write(m_PLC_Data, "posX",100);
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="exm"></param>
        /// <param name="valueName"></param>
        /// <param name="subject"></param>
        public void Field_Write<T>(T exm, string valueName, object subject)
        {
            //Type tp = typeof(T);
            Type tp = exm.GetType();
            FieldInfo[] flds = tp.GetFields(BindingFlags.Instance |
                                                 BindingFlags.NonPublic |
                                                 BindingFlags.Public |
                                                 BindingFlags.NonPublic);
            foreach (var t in flds)
            {
                if (valueName != t.Name)
                    continue;

                object point = t.GetValue(exm);
                if (point is int)
                    t.SetValue(exm, int.Parse(subject.ToString()));
                if (point is float)
                    t.SetValue(exm, float.Parse(subject.ToString()));
                if (point is string)
                    t.SetValue(exm, subject);
            }
        }


        /// <summary>
        /// 특정 클래스의 값을 읽어오는 함수
        /// ex) Console.WriteLine(m_PLC_Data.Field_GetValue(m_PLC_Data, "posX"));
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="exm"></param>
        /// <param name="valueName"></param>
        /// <returns></returns>
        public object Field_GetValue<T>(T exm, string valueName)
        {
            Type tp = exm.GetType();
            FieldInfo[] flds = tp.GetFields(BindingFlags.Instance |
                                                 BindingFlags.NonPublic |
                                                 BindingFlags.Public |
                                                 BindingFlags.NonPublic);

            object point = null;
            foreach (var t in flds)
            {
                if (valueName != t.Name)
                    continue;
                point = t.GetValue(exm);
                break;
            }

            return point;
        }

2022년 4월 19일 화요일

Winform class-based dynamic UI creation(winform 클래스기반 동적 UI 생성)

 


public void DynamicButton_Load(object sender, EventArgs e)
{
    PLCDataButton(TargetClass 원하는클래스);
}

public void PLCDataButton<T>(T target)
{
    List<string> fieldNames = new List<string>();
   
    foreach (var prop in target.GetType().GetFields())
    {
       
        fieldNames.Add(prop.Name);
    }

    m_PLC_Data.Field_Write(m_PLC_Data, "posX",100);
    Console.WriteLine(m_PLC_Data.Field_GetValue(m_PLC_Data, "posX"));

    Control[] BTN = new Control[fieldNames.Count];
    Control[] TB = new Control[fieldNames.Count];

    for (int idx = 0; idx < fieldNames.Count; idx++)
    {
        BTN[idx] = new Button();
        BTN[idx].Name = "btn_"+fieldNames[idx];
        BTN[idx].Parent = this;
        BTN[idx].Size = new Size(90, 30);


        TB[idx] = new TextBox();
        TB[idx].Name = "tb_"+fieldNames[idx];
        TB[idx].Parent = this;
        TB[idx].Size = new Size(90, 30);

        BTN[idx].Text = fieldNames[idx];

        if (m_PLC_Data.Field_GetValue(m_PLC_Data, fieldNames[idx]) == null)
            TB[idx].Text = "0";
        else
            TB[idx].Text = m_PLC_Data.Field_GetValue(m_PLC_Data, fieldNames[idx]).ToString();
       

        //BTN[idx].Click += TB_PLC_Change;
        TB[idx].TextChanged += TB_PLC_Change;

        WIDTH += 80;

        HEIGHT += 30;

        ///[flp_btns] 이것은 따로 만들어주는게 맘이편함
        ///[flp_btns] I like to make this separately.
        flp_btns.Controls.Add(BTN[idx]);
        flp_btns.Controls.Add(TB[idx]);
    }

    this.Controls.Add(flp_btns);
}


특정 클래스에 있는 Field 부분만 UI로 만들어서

UI에서 변경하면 직접 변경되게 하는 코드(버튼은 의미없긴함)


By making only the Field part in a specific class as UI

Code that makes changes directly when changed in UI (buttons are meaningless)











2022년 3월 31일 목요일

Unity EDITOR에서만 동작하는 함수

 




using System.Diagnostics;

using Debug = UnityEngine.Debug; ///Debug class는  UnityEngine.Debug 사용하겠다 선언



Debug.Assert(IsRegistered, "this quest has already been registered,");///버그잡기용 코드 //빌드시에는 적용안됨!

/// 에디터에서만 작동하는 함수
    [Conditional("UNITY_EDITOR")]///여기오타나면 안됨!
    private void CheckIsRunning()
    {
        Debug.Assert(IsRegistered, "this quest has already been registered,");///버그잡기용 코드 //빌드시에는 적용안됨!
        Debug.Assert(!IsCancle, "this quest has been canceled.");///버그잡기용 코드 //빌드시에는 적용안됨!
        Debug.Assert(!IsComplete, "this quest has already been complete.");///버그잡기용 코드 //빌드시에는 적용안됨!
    }

2022년 3월 13일 일요일

[c# TCP 고도화 (가상함수구현)]

 


세션 가상클래스로 만들어서 사용

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace ServerCore
{
    /// <summary>
    /// 추상class로 만들어서 상속받은 클래스로 사용하기
    /// </summary>
    ///

    abstract class Session
    {
        Socket _socket;
        int _disconnected = 0;
        List<ArraySegment<byte>> _pendinglist = new List<ArraySegment<byte>>();
        SocketAsyncEventArgs _sendArgs = new SocketAsyncEventArgs(); /// 재사용을 위해 전역변수로 선언
        Queue<byte[]> _sendQueue = new Queue<byte[]>();

        /// <summary>
        /// 엔진과 컨텐츠를 분리하기위해 가상함수 만들엇다!!
        /// </summary>
       
        public abstract void OnConnected(EndPoint endpoint);
        public abstract void OnRecv(ArraySegment<byte> buffer);
        public abstract void OnSend(int numOfBytes);
        public abstract void OnDisconnected(EndPoint endPoint);


        //bool _pending;
        object _lock = new object();

        public void Start(Socket socket)
        {
            _socket = socket;
            SocketAsyncEventArgs recvArgs = new SocketAsyncEventArgs();
            recvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnRecvCompleted);
            ///recvArgs.UserToken = 1;///아무거나 넘겨줘도 됨 this,숫자,아무거나 가능!! 식별자로 구분하고싶을때 사용
            recvArgs.SetBuffer(new byte[1024],0,1024);


            _sendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);

            RegisterRecv(recvArgs);
        }

        /// <summary>
        /// send는 recv 만큼 단순하지 않다
        /// 뭘 보낼지 모르니까 필요할때 써야한다.
        /// 많이 까다롭고 방법도 여러가지가 존재한다!
        /// </summary>
        /// <param name="sendBuff"></param>
        public void Send(byte[] sendBuff)
        {
            ///_socket.Send(sendBuff);
            ///
            ///문제 여기서 게속 생성해서 샌드하면 너무 손해다 (new)
           

            lock (_lock)
            {
                ///멀티스레드 이니까 락이 무조건 필요!!(여러명이 Queue에 접근못하게!)
                _sendQueue.Enqueue(sendBuff);
                if (_pendinglist.Count==0)///_pending == false
                {
                    ///처음 send를 호출한 상태(Register가능)
                    RegisterSend();
                }
            }



            ///매번 이렇게 호출하면 너무 비효율적! Queue에 담아서 될때만 호출해주자!
            //_sendArgs.SetBuffer(sendBuff,0,sendBuff.Length);
            //RegisterSend();

        }

        public void Disconnect()
        {
           
            if (Interlocked.Exchange(ref _disconnected, 1) == 1)
                return;

            ///Disconnected가 성공하면 OnDisconnected가 한번 실행될것이다!
            OnDisconnected(_socket.RemoteEndPoint);

            _socket.Shutdown(SocketShutdown.Both);
            _socket.Close();

            ///안좋은 예
            ///

            ///if (_socket == null)
            ///    return;
            ///_socket = null;
           
        }


        #region 네트워크 통신 (내부사용)



        ///Send부분
        void RegisterSend()
        {

            ///멀티스레드여도 RegisterSend자체가 Lock에서 호출되고 있으니까 lock을 걸필요는 없음

            /// 심지어 이부분에서 sendAsync를 여러번 반복하면 부하가 너~~무 심하다!
            /// _socket.SendAsync(args) 이것을 아무대나 막쓰는것은 문제가 심하다.
            /// 뭉쳐서 보내야 한다!
            //_pending = true;
            //byte[] buff = _sendQueue.Dequeue();
            //_sendArgs.SetBuffer(buff, 0, buff.Length);

            /// _sendArgs.BufferList 한번에 리스트로 Async 콜을 줄일수있다.
            /// SetBuffer와 같이 사용할순 없다(둘중 하나 선택해야함)

            ///_pendinglist.Clear();

            while (_sendQueue.Count>0)
            {
                byte[] buff = _sendQueue.Dequeue();
                ///Add 하는 방식이 특이! ArraySegment 어떤 배열의 일부를 나타내는 구조체!
                /// a[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ] c++은 포인터 개념이 있어서 포인터로 시작주소를 옮겨서 건내주면됨
                /// 하지만 c#이라면 포인터가 없어서 무조건 첫 주소만 알수있음
                /// 그래서 시작주소를 알수있게 보통 (buff, 0, buff.Length) 이런식으로 생겨있다.
                //_sendArgs.BufferList.Add(new ArraySegment<byte>(buff, 0, buff.Length));

                _pendinglist.Add(new ArraySegment<byte>(buff, 0, buff.Length));
            }

            _sendArgs.BufferList = _pendinglist;




            bool pending = _socket.SendAsync(_sendArgs); ///전역변수 사용으로 함수 인자 하나 없애기!(꼬이기 방지)
            if (pending == false)
                OnSendCompleted(null, _sendArgs);
        }
        void OnSendCompleted(object sender, SocketAsyncEventArgs args)
        {

            ///여기는 callback 방식으로 다른스레드에서 실행될수도 있으니 lock을 걸어줘야한다.
            ///_sendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted); <-- 이부분
            /// 사실 잘 와닿지 않을수 있음
            /// 멀티스레드 프로그램은 계속 크래시를 내보면서 해볼수 밖에 없음 그래야지 감각이 좋아짐

            lock (_lock)
            {
                if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
                {
                    try
                    {
                        ///recv와 다르게 보낸개 성공했을때 굳이 뭐 할게 없긴하다
                        ///
                        ///Send는 Receive처럼 시점이 정해져있지 않음
                        ///Send 하기!
                        /// RegisterSend는 재사용 당연히 불가능!

                        _sendArgs.BufferList = null; ///필요는 없음 그냥 구분하기 위해서 넣어준거라고 보면됨
                        _pendinglist.Clear();
                        OnSend(_sendArgs.BytesTransferred);

                        ///_pending 을 통과못한 큐에 쌓인 데이터 전부 처리해주기
                        if (_sendQueue.Count > 0)
                            RegisterSend();
                       




                    }
                    catch (Exception e)
                    {
                        Console.WriteLine($"On RecvCompleted Failed{e}");
                    }
                }
                else
                {
                    Disconnect();
                }
               
            }
        }



        ///비동기 방식으로 처리하려면
        ///두단계 필요!
        ///1.등록
        ///2.완료

        void RegisterRecv(SocketAsyncEventArgs args)
        {
            bool pending= _socket.ReceiveAsync(args);
            if (pending == false) ///완료됬으면 complete 호출!
                OnRecvCompleted(null,args);
        }
        void OnRecvCompleted(object sender, SocketAsyncEventArgs args)
        {
            if (args.BytesTransferred >0 && args.SocketError == SocketError.Success)
            {

                try
                {
                    ///이제 성공적으로 recv를 받앗을때 OnRecv가 콜되게 만듬!!
                    OnRecv(new ArraySegment<byte>(args.Buffer, args.Offset, args.BytesTransferred));
                   
                    RegisterRecv(args);
                }
                catch (Exception e)
                {
                    Console.WriteLine($"On RecvCompleted Failed{e}");
                }
               
            }
            else
            {
                /// TODO Disconnect!!
                Disconnect();
            }
        }



        #endregion
    }
}






메인 프로그램

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;



/// <summary>
/// 소켓 프로그래밍 기초
///
/// 메모장 코드를 메인안에 때려박아넣으면 안됨!
///어짜피 커질꺼니까 처음부터 분리하는 습관을 들여야함!
///
///
/// </summary>

namespace ServerCore
{

   
    class GameSession : Session
    {
        /// <summary>
        /// 컨텐츠 에서는 각자 세션을 상속받은 클래스에서 하고싶은것을 하면됨!
        /// </summary>
       
        public override void OnConnected(EndPoint endPoint)
        {
            Console.WriteLine($"OnConnected :{endPoint}");


            byte[] sendBuff = Encoding.UTF8.GetBytes("Welcome to MMORPG SERVER!");
            Send(sendBuff);

            Thread.Sleep(1000);

            Disconnect();
        }

        public override void OnDisconnected(EndPoint endPoint)
        {
            Console.WriteLine($"OnDisconnected :{endPoint}");
        }

        public override void OnRecv(ArraySegment<byte> buffer)
        {
            /// 성공적으로 데이터 가져오기 완료
            string recvData = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
            Console.WriteLine($"From Client[{recvData}]");
        }

        public override void OnSend(int numOfBytes)
        {
            Console.WriteLine($"Transferred bytes:{numOfBytes}");
        }
    }

    class Program
    {
        static Listener _listener = new Listener();
        ///static Session _Session = new Session();

        static void Main(string[] args)
        {
            /// DNS (Domain Name System)
            /// 172.1.2.3(실제로 넣으면 문제가됨!) 하드코딩 X!
            /// 하지만 도메인 등록이라면 문제가 없다
            /// www.rookiss.com -> 123.123.123.12
            string host = Dns.GetHostName();
            IPHostEntry ipHost = Dns.GetHostEntry(host);
            IPAddress ipAddr =  ipHost.AddressList[0];
            IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777);


            ///혹시나 누가 들어오면 OnAcceptHandler에 전달해줘
            _listener.Init(endPoint, ()=> { return new GameSession(); });
            Console.WriteLine("Listening...");

            while (true)
            {

            }
        }
    }
}




func를 이용해서 session클래스 사용


using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace ServerCore
{
    class Listener
    {
        Socket _listenSocket;

        /// Accept가 완료되면 어떻게 처리할건지
        ///Action<Socket> _onAcceptHandler;
        ///
       
        ///GameSession session = new GameSession(); 을 사용하지않기위해
        Func<Session> _sessionFactory;


        public void Init(IPEndPoint endPoint, Func<Session> sessionFactory)
        {
            ///문지기 만들기(핸드폰만들기)
            _listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            _sessionFactory += sessionFactory; /// func라서 리턴값이 있는 람다식을 받을 수 있음

            ///_listener.Init(endPoint, ()=> { return new GameSession(); }); 이런식으로 사용!

            ///문지기 교육
            _listenSocket.Bind(endPoint);

            ///영업 시작
            ///backlog : 최대 대기수
            /// 문지기가 안내하기 전까지 대기하는 수
            /// 만약 이 수가 넘어가는 사람이 문의하면 바로 fail이 뜬다
            _listenSocket.Listen(10);

            /// 한번만 만들어주면 계속 재활용 할수있는 어마어마한 장점이 있음
            SocketAsyncEventArgs args = new SocketAsyncEventArgs();
            args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);///나중에라도 완료되면 여기 이벤트로 연락오게하기!
            RegisterAccept(args);///최초로 낚시대를 강물에 던짐!


            ///여러개를 만들어도 상관없음
            ///
           /* for (int i = 0; i < 10; i++)
            {
                /// 한번만 만들어주면 계속 재활용 할수있는 어마어마한 장점이 있음
                SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);///나중에라도 완료되면 여기 이벤트로 연락오게하기!
                RegisterAccept(args);///최초로 낚시대를 강물에 던짐!
            }*/

        }








        void RegisterAccept(SocketAsyncEventArgs args)
        {

            ///중요!
            ///다시 돌아올때 비어있는 args여야한다!!!
            args.AcceptSocket = null;


            /// 비동기! 동시에 처리안되고 나중에 처리될수있음!!!
            ///성공하든 아니든 상관없이 바로 리턴을 하고 본다(문제가 될수있음)
            ///로그인에 실패했는데 리턴때릴수있음
            ///비동기 계열을 사용하면 대화를 해야함(결과에 대해서)
            ///

            ///당장 완료한다는 보장은 없고 요청을 하긴 할꺼다
            ///말그대로 등록을 한거라고 보면됨
            bool pending = _listenSocket.AcceptAsync(args);
            if (pending == false)
            {
                ///비동기로 실행했지만 운좋게 완료된 케이스
                ///낚시대를 강물에 던지자마자 물고기가 잡힌 케이스
                OnAcceptCompleted(null,args);
            }
            else
            {
                ///pending true
                /// 나중에 args로 Completed 로 연락이 올것이다.
            }

        }

        void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
        {
            ///주 스레드와 엮일수 있는 REDZONE이다!!!! 조심!!!!!!!!
            ///멀티스레드 주의~~~

            if (args.SocketError == SocketError.Success)
            {
                ///에러 없이 잘 처리 됫다(실제로 accept를 했다)
                /// 유저가 커넥트 연결이 와서 실제로 accept까지 했다면
                ///TODO
                ///


                /// <summary>
                /// 다른이름의 세션이 될수도 있음
                /// ex) MMOSession MasterSession 등등...무조건 GameSession일리는 없음!
                /// </summary>

                Session session = _sessionFactory.Invoke(); ///-> ()=> { return new GameSession();
                session.Start(args.AcceptSocket);
                session.OnConnected(args.AcceptSocket.RemoteEndPoint);

                //_onAcceptHandler.Invoke(args.AcceptSocket);///완료됬으면 _onAccepHandler 실행!

            }
            else
            {
                Console.WriteLine(  args.SocketError.ToString());
            }


            ///모두 완료됬으니 다음 아이를 위해서 다시 등록!!
            ///다음 낚시대 던지기
            RegisterAccept(args);
        }

    }
}



git rejected error(feat. cherry-pick)

 문제 아무 생각 없이 pull을 받지않고 로컬에서 작업! 커밋, 푸시 진행을 해버렷다. push에선 remote와 다르니 당연히 pull을 진행해라고 하지만 로컬에서 작업한 내용을 백업하지 않고 진행하기에는 부담스럽다(로컬작업 유실 가능성) 해결하려...