C# TCP IP Socket 프로그래밍 하기(1)

really·2024년 12월 1일

CSharp

목록 보기
1/2

⭐Socket이란??

결론적으로, Socket도 파일이다
소켓은 OS커널의 구성요소인 TCP/IP 프로그램을 추상화시킨 인터페이스 파일이다.
우리는 Socket File에다가 입출력 IO작업을 수행하는 것이다.
그래서, 소켓 프로그래밍에서 socket()을 하는 작업은 C언어의 fopen(&fp)을 하는 작업과 유사하다.
그리고, 이 Socket에 attached된 Buffer 메모리공간이 존재한다.

⭐TCP와 UDP

  • TCP는 연결 지향적이고, Connection,Session이라는 개념이 있다
  • 데이터가 정상적으로 전송되었는지 확인하는 3way handshaking과정을 가지고 있으며
    데이터를 보낼 때, 수신하는 측에서 데이터 여유공간이 없을때(=Zero Window일 때) 데이터를 보내지 않는다. 그래서 안전하며, 신뢰성이 있는 통신 프로토콜 방식이다.
  • 이러한 특징으로 웹 서버, 파일전송, 채팅 등에서 사용된다

반면 UDP는

  • 비연결성이며 연결 설정없이 데이터를 한 번에 보내는 방식이다, 수신 측에서 데이터를 받든 말든 계속 데이터를 보낸다
  • 데이터의 안정적인 발송이나 순차 발송이 보장되지 않지만, 빠른 속도가 필요할 경우 사용된다.
  • 이러한 특징으로, 실시간 게임, 스트리밍, 음성 통화 등에서 사용된다

⭐Socket 프로그래밍 실전

🌠사용되는 3가지 소켓
1. 서버소켓 : client의 접속을 대기하는 소켓(new Socket()으로 객체 생성됨)
2. 서버의 통신소켓(=클라이언트와 통신하는 서버의 통신 소켓) : accept()함수가 반환하는 소켓 객체임.
accept()함수는 client가 connect()로 접속할 때 수행되고, 그 전에 서버는 listen()상태로 감지하고 있어어함!
3. 클라이언트 소켓 : 통신을 시도하는 Client의 소켓, connect()함수로 연결을 시도한다.
다음과 같이 3개의 소켓이 필요하다

📄Server코드

using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Server;

internal class Server
{
	static void Main(string[] args)
	{
		using(Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
		{
			IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("192.168.45.249"), 20000);
			serverSocket.Bind(endPoint);
			serverSocket.Listen(20);

			using (Socket clientSocket = serverSocket.Accept())
			{ 
				// RemoteEndPoint : IP주소와 Port번호 알 수 있음
				Console.WriteLine("연결됨!!" + clientSocket.RemoteEndPoint);
				while (true)
				{
					byte[] rcvBuffer = new byte[256];
					int totalBytes = clientSocket.Receive(rcvBuffer);
					if (totalBytes < 1)
					{
						Console.WriteLine("클라이언트의 연결 종료");
						return;
					}
					// 받은 데이터 역직렬화
					Console.WriteLine($"Server : {Encoding.UTF8.GetString(rcvBuffer)}" );
					// Client에게 받은 메시지 전달
					clientSocket.Send(rcvBuffer);
				}
            }
		}
    }
}

📄Client코드

using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Client;

internal class Client
{
	static void Main(string[] args)
	{
		using(Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
		{
			IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("192.168.45.249"), 20000);
			socket.Connect(endPoint); //서버와 Connect

			while(true)
			{
				string str = Console.ReadLine();
				if(str == "exit")
				{
					return;
				}
				//입력받은 String을 byte[]로 직렬화
				byte[] strBuffer = Encoding.UTF8.GetBytes(str);
				socket.Send(strBuffer); // 서버에 입력받은 메시지 전달

				// From server
				byte[] rcvBuffer = new byte[256];
				int bytesRead = socket.Receive(rcvBuffer);
				if(bytesRead < 1)
				{
                    Console.WriteLine("서버 연결 종료!");
					return;
                } else
				{
                    Console.WriteLine($"From Server : {Encoding.UTF8.GetString(rcvBuffer)}");
				}
			}
		}
	}
}

<결과>

한계

다음 프로그램은 이와 같은 한계를 가진다.
1. Server에서 rcvBuffer를 항상 고정길이 256byte길이로 받는것..

2. TCP 프로토콜은 데이터의 시작과 끝이 없다,그래서 Server코드에서 Client가 보낸 데이터를 1번만의 Receive함수로 받을 수 없음

해당 부분을 2편에서 개선하도록 한다.


<참고자료>
인프런 C# TCP/IP 소켓 프로그래밍
인프런 Windows 소켓 프로그래밍 입문에서 고성능 서버까지!

0개의 댓글