노력과 삽질 퇴적물

C#: 문법 스캔 (3) 본문

프로그래밍note/언어. C# 계열

C#: 문법 스캔 (3)

MTG 2021. 7. 16. 00:14
목차
(1)
 이론
(2)
 TCP
(3)
 소켓


* 주요 참조자료상, 닷넷 기반 TCP/IP, UDP입니다.


 
 
 
1. 이론
 
1) TCP
> TCP클라이언트와 TCP Listener 클래스가 사용된.
 
 
2) UDP
> 연결지향인 TCP와 달리, UDP는 속도를 중시한 처리가 중요한 프로토콜.

* TCP클라이언트/Listener 클래스와 UDP클라이언트 클래스는 내부적으로 소켓 클래스 사용하고, 소켓 클래스는 low-level 소켓 프로그래밍 지원.
* 해당 포스팅에서는 UDP 예시는 생략.





2. TCP


1) 클라이언트 사이드
> 인코딩/디코딩 절차상, 예제의 문자열뿐 아니라 이미지같은 미디어 전송도 가능.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Net.Sockets;
... ... ...
 
//STEP.1    IP주소와 포트번호
TcpClient tClient = new TcpClient("127.0.0.1"80);
 
string requestMsg = "2021_05_17";
byte[] encodedBytes = Encoding.ASCII.GetBytes(requestMsg);//인코딩처리.
 
//STEP.2    NetworkStream
NetworkStream nwStream = tClient.GetStream();
 
//STEP.3    NetworkStream.Write
nwStream.Write(encodedBytes, 0, encodedBytes.Length);
 
//STEP.4    NetworkStream.Read
byte[] recivedBytes = new byte[1024];
int nbytes = nwStream.Read(recivedBytes, 0, recivedBytes.Length);
string resultMsg = Encoding.ASCII.GetString(recivedBytes, 0, nbytes);
 
//STEP.5    접속종료
nwStream.Close();
tClient.Close();
cs


(HTTP 프로토콜처럼)연결 끊길때까지 처리하려면 STEP.4에서

1
2
3
4
5
6
7
8
9
byte[] recivedBytes = new byte[1024];
int nbytes;
MemoryStream mStream = new MemoryStream();
while ((nbytes = nwStream.Read(recivedBytes, 0, recivedBytes.Length)) > 0)
{
     mStream.Write(recivedBytes, 0, nbytes);
}
byte[] resultBytes = mStream.ToArray();
mStream.Close();
cs
MemoryStream으로 루프 돌려야.



2) TCP Listener를 이용한 비동기 서버

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
static void Main(string[] args)
{
  TestTcpAysnc().Wait();
}
... ... ...
async static Task TestTcpAysnc()
{
  int port = 2021;
  IPAddress targetAddress = IPAddress.Parse("127.0.0.1");
 
  TcpListener tListener = new TcpListener(targetAddress, port);
  try
  {
    tListener.Start();
  } catch(SocketException e) {
    //do-something.
  } finally {
    tListener.Stop();
  }
 
  while (true)
  {        
    TcpClient tcpClient = await tListener.AcceptTcpClientAsync().ConfigureAwait(false);
    Task.Factory.StartNew(doStreamAsync, tcpClient);//to new thread
  }
}
 
async static void doStreamAsync(object argObj)
{
  TcpClient tcpClient = (TcpClient)argObj;
  NetworkStream nwStream = tcpClient.GetStream();
 
  String msg = null;
  byte[] buff = new byte[1024];//512, 1024, 2048 ...
  var nBytes = await nwStream.ReadAsync(buff, 0, buff.Length).ConfigureAwait(false);
  if (nBytes > 0)
  {                
    msg = Encoding.ASCII.GetString(buff, 0, nbytes);       
    await nwStream.WriteAsync(buff, 0, nbytes).ConfigureAwait(false);
  }
 
  nwStream.Close();
  tcpClient.Close();
}
cs





 

3. 소켓
 

1) 클라이언트 사이드

> Connect->Send->Receive->Close
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
using System.Net;
using System.Net.Sockets;
... ... ...
public class TestSocket
{
    public static void Main(string[] args)
    {
        int port = 8080;
        Socket socket = null;
        byte[] requestBytes = Encoding.ASCII.GetBytes( string.Empty );
        byte[] responseBytes = new byte[8192];
 
 
        //STEP.1 연결관련 객체
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("172.0.0.1"), port);
        socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
 
        //STEP.2 서버에 연결
        socket.Connect(endPoint);
 
 
        while ((cmd = Console.ReadLine()) != "q")
        {
            requestBytes = Encoding.UTF8.GetBytes(cmd);
 
            try{
                //STEP.3 리퀘스트
                socket.Send(requestBytes, requestBytes.Length, 0);
 
                //STEP.4 리스폰스
                int responseInt = socket.Receive(responseBytes, responseBytes.Length, 0);
                string response = Encoding.UTF8.GetString(responseBytes, 0, responseInt);
                Console.WriteLine(response);
            } catch(SocketException except){
                Console.WriteLine(except.ErrorCode);
                //do-something
            }
        }
 
        //STEP.5
        socket.Close();
    }
}
cs


2) 서버 사이드
> (Bind->Listen->Accept)->(Receive->Send)->Close
// 서버가 블라블라(BLA BLA)하는걸 듣고서 대답하고 닫기.
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
using System.Net;
using System.Net.Sockets;
... ... ...
 
namespace TestSocketServer
{
    static void Main(string[] args)
    {
        int port = 8080;
        Socket serverSocket = null;
        Socket clientSocket = null;
        byte[] responseBytes = new byte[8192];
 
 
        //STEP.1 소켓 객체
        IPEndPoint endPoint = new IPEndPoint("172.0.0.1", port);
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 
        try{
            //STEP.2 (포트번호대로)수신 시작.
            serverSocket.Bind(endPoint);
            serverSocket.Listen(10);
 
 
            //STEP.3 새소켓
            clientSocket = serverSocket.Accept();
        } catch(SocketException except){
            Console.WriteLine(except.ErrorCode);
        } catch(ObjectDisposedException except){
            Console.WriteLine(except.ErrorCode);
        }
 
 
        int responseResult = -1;
        string responseString = null;
        while (!Console.KeyAvailable)
        {
            //STEP.4 새소켓으로 수신
            responseResult = clientSocket.Receive(responseBytes);
            responseString = Encoding.UTF8.GetString(responseBytes, 0, responseResult);
 
 
            //STEP.5 답신
            clientSocket.Send(responseBytes, 0, receiveResult, SocketFlags.None);
        }
 
        //STEP.6 소켓 
        clientSocket.Close();
        socket.Close();
    }
}
cs


3) 비동기 소켓 서버
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
using System.Net;
using System.Net.Sockets;
using System.Threading;
... ... ...
 
namespace TestSocketServer
{
    public static ManualResetEvent _threadEvent = new ManualResetEvent(false);
 
    static void Main(string[] args)
    {
        int port = 8080;
        Socket serverSocket = null;
 
 
        //STEP.1 소켓 객체
        IPEndPoint endPoint = new IPEndPoint("172.0.0.1", port);
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 
        try{
            //STEP.2 (포트번호대로)수신 시작.
            serverSocket.Bind(endPoint);
            serverSocket.Listen(10);
        } catch(SocketException except){
            Console.WriteLine(except.ErrorCode);
        } catch(ObjectDisposedException except){
            Console.WriteLine(except.ErrorCode);
        }
 
 
        try{
            while (true)
            {
                _threadEvent.Reset();
 
                //STEP.3 클라이언트 요청이 있을때마다 요청 수락
                serverSocket.BeginAccept(SocketCallback, serverSocket);//Accept.시작
 
                _threadEvent.WaitOne();// Wait until a connection is made before continuing.
            }
        } catch(Exception except){
            Console.WriteLine(except.ErrorCode);
        }
    }
 
    private static void SocketCallback(IAsyncResult argResultAsync)
    {
        Console.WriteLine("Accepted");
        Console.ReadLine();
 
        _threadEvent.Set();// Signal the main thread to continue.
 
        Socket listener = (Socket)argResultAsync.AsyncState;
        Socket clientSocket = listener.EndAccept(argResultAsync);//Accept.끝
 
        clientSocket.Close();
    }
}
cs




기타. 참조자료

1) 한국어
C# 프로그래밍 배우기 (Learn C# Programming)
TCP 클라이언트
비동기 TCP 서버