2017년 1월 23일 월요일

C# 유용한 소켓 Select 함수 핸들러 소스코드 - useful socket select method handler source code

소켓 수신 이벤트 처리에 유용한 코드이다.
소켓 이벤트 핸들러를 등록하면 수신 이벤트 발생시 콜백으로 호출해준다.
TCP/UDP-서버/클라이언트 구분없이 모두 사용할 수 있다.

 using System;  
 using System.Collections.Generic;  
 using System.Text;  
 using System.Diagnostics;  
 using System.Net;  
 using System.Net.Sockets;  
 using System.Collections;  
 using System.Threading;  
   
 namespace MySocketLib  
 {  
   public delegate void SocketReadHandlerCallback(Object data);  
   
   public class SocketHandler  
   {  
     public Socket sock;  
     public SocketReadHandlerCallback handler;  
     public object data;  
   }  
   
   public class SocketTaskScheduler  
   {  
     protected Dictionary<Socket, SocketHandler> sockHandlerTable = new Dictionary<Socket, SocketHandler>();  
     protected bool isRunning = false;  
     protected Thread thread;  
     protected int TIMEOUT = 1000000;  
   
     public SocketTaskScheduler()  
     {  
     }  
   
     public void RegisterSocketHandler(Socket sock, SocketReadHandlerCallback handler, object data)  
     {  
       lock (sockHandlerTable)  
       {  
         if (sock != null)  
         {  
           SocketHandler sockHandler = new SocketHandler();  
           sockHandler.sock = sock;  
           sockHandler.handler = handler;  
           sockHandler.data = data;  
           sockHandlerTable.Add(sockHandler.sock, sockHandler);  
         }  
       }  
     }  
   
     public void UnregisterSocketHandler(Socket sock)  
     {  
       lock (sockHandlerTable)  
       {  
         if (sock != null && sockHandlerTable.ContainsKey(sock))  
         {  
           sockHandlerTable.Remove(sock);  
         }  
       }  
     }  
   
     protected void SingleStep()  
     {  
       lock (sockHandlerTable)  
       {  
         try  
         {  
           ArrayList selectList = new ArrayList();  
           foreach (var handler in sockHandlerTable)  
           {  
             selectList.Add(handler.Key);  
           }  
   
           if (selectList.Count == 0)  
           {  
             Thread.Sleep(10);  
             return;  
           }  
   
           Socket.Select(selectList, null, null, TIMEOUT);  
   
           foreach (Socket sock in selectList)  
           {  
             var handler = sockHandlerTable[sock];  
             if (handler != null && handler.handler != null) handler.handler(handler.data);  
           }            
         }  
         catch (Exception ex)  
         {  
           Trace.WriteLine(ex.ToString());  
         }  
       }  
     }  
   
     protected void DoEventLoop()  
     {  
       while (isRunning == true)  
       {  
         SingleStep();  
       }  
     }  
   
     public void StartEventLoop()  
     {  
       if (isRunning == true) return;  
   
       thread = new Thread(new ThreadStart(DoEventLoop));  
       thread.IsBackground = true;  
       isRunning = true;  
       thread.Start();  
     }  
   
     public void StopEventLoop()  
     {  
       isRunning = false;  
       if (thread != null)  
       {  
         if (Thread.CurrentThread != thread)  
         {  
           thread.Join();  
           thread = null;  
         }  
       }  
       sockHandlerTable.Clear();  
     }  
   }  
 }  
   


< 사용법 >

Socket clientSock;
SocketTaskScheduler task = new SocketTaskScheduler();
...
clientSock.Blocking = false;
clientSock.Connect(serverIP, serverPort);

task.RegisterSocketHandler(clientSock, IncomingPacketHandler, this);
task.StartEventLoop();
...

private void IncomingPacketHandler(object data)
{
            int ret = clientSock.Receive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None);
            if (ret <= 0)
            {
                task.UnregisterSocketHandler(clientSock);
                CloseSocket();

                task.StopEventLoop();
            }
            else
            {
                 // process recvBuffer
            }
}




댓글 없음:

댓글 쓰기