.NET Framework Networking
1. TCP Client & Server 만들기
관련 클래스
System.Net.Sockets.TCPClient : TCP 네트웍의 클라이언트 서비스를 제공, Socket 클래스를 기본으로 작성 되었으며 TCP 서비스를 제공 한다. TCPCLient는 TCP Client를 작성 할 때 쓰이며 FTP나 HTTP와 같은 애플리케이션 계층 프로토콜을 개발 하는데 주로 사요 된다.
예)
TCPClient myClient = new TCPClient(“***.***.***.***”, 13);
Stream myStream = myClient.GetStream();
System.Net.Sockets.NetworkStream : Network용 데이터 스트림을 제공 한다. 네트웍의 소켓을 통해 데이터를 전송 및 수신하는 표준 닷넷 프레임워크 스트림 방식을 구현 한다.
System.Net.Sockets.Socket : 버클리 소켓을 제공 한다. 트랜스포트 계층을 지원하며 생성된 소켓은 Bind() 메소드를 통해 특정한 종단점으로 바운드 되며 Connect 메소드를 통해서 연결이 생성 된다. Send(), SendTo() 메소드르 통해 테이터를 소켓으로 전송하며 Receive() 나 ReceiveFrom() 메소들 통해 소켓으로부터 데이터를 수신한다. 소켓으로 하는 모든 작업이 완료되면 Shutdown() 메소드를 이용해 소켓을 비활성화 한 후 Close() 메소드를 이용 해 소켓을 닫는다. 닷넷에서의 소켓은 인터넷의 TcpClient, UdpClient, WebRequest 그리고 파생된 클래스들의 연결을 맺는데 사용 된다.
System.Net.Sockets.TcpListener : TCP 네트웍의 클라이언트 접속을 Listen, 소켓 클래스를 기반으로 TCP 서비스를 제공하기 위한 클래스 이다. TcpListener는 TCP 클라이언트의 접속을 리슨하기 위해 서버 측에서 사용하며 FTP, HTTP와 같은 프로토콜을 사용하는 애프리케이션 계층은 TcpListener를 기반으로 작성 될 수 있다.
소스(TcpClientExample.cs)
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
class TcpClientTest {
static void Main(string[] args)
{
TcpClient client = null;
try {
//LocalHost에 지정 포트로 TCP Connection을 생성하고 데이터를 송수신 하기
//위한 스트림을 얻는다.
client = new TcpClient();
client.Connect("localhost", 5001);
NetworkStream writeStream = client.GetStream();
//보낼 데이터를 읽어 Default 형식의 바이트 스트림으로 변환
string dataToSend = Console.ReadLine();
byte [] data = Encoding.Default.GetBytes(dataToSend);
while(true)
{
dataToSend += "\r\n";
data = Encoding.Default.GetBytes(dataToSend);
writeStream.Write(data,0,data.Length);
if (dataToSend.IndexOf("<EOF>") > -1) break;
dataToSend = Console.ReadLine();
}
}
catch(Exception ex) {
Console.WriteLine(ex.ToString());
}
finally {
client.Close();
}
}
}
소스(TCPServer.cs)
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
class Server
{
public static void Main()
{
NetworkStream stream = null;
TcpListener tcpListener = null;
StreamReader reader = null;
Socket clientsocket = null;
try
{
//IP주소를 나타내는 객체를 생성,TcpListener를 생성시 인자로 사용할려고
IPAddress ipAd = IPAddress.Parse("127.0.0.1");
//TcpListener Class를 이용하여 클라이언트의 연결을 받아 들인다.
tcpListener = new TcpListener(ipAd, 5001);
tcpListener.Start();
//Client의 접속이 올때 까지 Block 되는 부분, 대개 이부분을 Thread로 만들어 보내 버린다.
//백그라운드 Thread에 처리를 맡긴다.
clientsocket = tcpListener.AcceptSocket();
//클라이언트의 데이터를 읽고, 쓰기 위한 스트림을 만든다.
stream = new NetworkStream(clientsocket);
Encoding encode = System.Text.Encoding.GetEncoding("ks_c_5601-1987");
reader = new StreamReader(stream, encode);
while(true)
{
string str = reader.ReadLine();
Console.WriteLine(str);
}
}
catch (Exception e )
{
Console.WriteLine(e.ToString());
}
finally {
clientsocket.Close();
}
}
}
[실습] 위의 예제는 Client는 단순히 보내기만 하고 Server는 단순히 받기만 한다. 적절히 수정하여 Client가 보내는 것을 서버는 화면에 출력하고 Client에 다시 보내는 EchoClient와 EchoServer를 작성 해 보시기를 바랍니다. 이 경우 Client 역시 보내고 받는 부분의 처리가 가능 해야 합니다.
[EchoClient.cs]
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
class TcpClientTest {
static void Main(string[] args) {
TcpClient client = null;
try {
//LocalHost에 지정 포트로 TCP Connection을 생성하고 데이터를 송수신 하기
//위한 스트림을 얻는다.
client = new TcpClient();
client.Connect("localhost", 5001);
NetworkStream writeStream = client.GetStream();
Encoding encode = System.Text.Encoding.GetEncoding("ks_c_5601-1987");
StreamReader readerStream = new StreamReader(writeStream, encode);
//보낼 데이터를 읽어 Default 형식의 바이트 스트림으로 변환
string dataToSend = Console.ReadLine();
byte [] data = Encoding.Default.GetBytes(dataToSend);
while(true)
{
dataToSend += "\r\n";
data = Encoding.Default.GetBytes(dataToSend);
writeStream.Write(data,0,data.Length);
if (dataToSend.IndexOf("<EOF>") > -1) break;
string returnData;
returnData = readerStream.ReadLine();
Console.WriteLine("server : " + returnData);
dataToSend = Console.ReadLine();
}
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
client.Close();
}
}
}
[EchoServer.cs]
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
class Server
{
public static void Main()
{
NetworkStream stream = null;
TcpListener tcpListener = null;
StreamReader reader = null;
Socket clientsocket = null;
try
{
//IP주소를 나타내는 객체를 생성,TcpListener를 생성시 인자로 사용할려고
IPAddress ipAd = IPAddress.Parse("localhost");
//TcpListener Class를 이용하여 클라이언트의 연결을 받아 들인다.
tcpListener = new TcpListener(ipAd, 5001);
tcpListener.Start();
//Client의 접속이 올때 까지 Block 되는 부분, 대개 이부분을 Thread로 만들어 보내 버린다.
//백그라운드 Thread에 처리를 맡긴다.
clientsocket = tcpListener.AcceptSocket();
//클라이언트의 데이터를 읽고, 쓰기 위한 스트림을 만든다.
stream = new NetworkStream(clientsocket);
Encoding encode = System.Text.Encoding.GetEncoding("ks_c_5601-1987");
reader = new StreamReader(stream, encode);
while(true)
{
string str = reader.ReadLine();
if(str.IndexOf("<EOF>") > -1)
{
Console.WriteLine("Bye~ Bye~");
break;
}
Console.WriteLine(str);
str += "\r\n";
byte[] dataWrite = Encoding.Default.GetBytes(str);
stream.Write(dataWrite,0,dataWrite.Length);
}
}
catch (Exception e )
{
Console.WriteLine(e.ToString());
}
finally
{
clientsocket.Close();
}
}
}
[질문] 위의 예제에서 Client를 두 개 이상 만들어서 서버에 접속 해 보길 바랍니다.
과연 어떤 일이 일어 날까요? 그럼 그 해결책은 무엇 인가요? 아마도 멀티 쓰레드를 이용하여 블록킹 되는 메소드를 쓰레드로 처리를 해야 할 겁니다. 실습 해 보시기 바랍니다.
Client Program은 그대로 두고 서버를 다시 만들도록 합시다.
[MultiThreadEchoServer.cs]
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
public class ClientHandler
{
public Socket clientSocket;
public void runClient()
{
NetworkStream stream = null;
StreamReader reader = null;
try
{
//Client의 접속이 올때 까지 Block 되는 부분, 대개 이부분을 Thread로 만들어 보내 버린다.
//백그라운드 Thread에 처리를 맡긴다.
//clientSocket = tcpListener.AcceptSocket();
//클라이언트의 데이터를 읽고, 쓰기 위한 스트림을 만든다.
stream = new NetworkStream(clientSocket);
System.Console.WriteLine("111111111");
Encoding encode = System.Text.Encoding.GetEncoding("ks_c_5601-1987");
reader = new StreamReader(stream, encode);
while(true) {
string str = reader.ReadLine();
if (str.IndexOf("<EOF>") > -1)
{
Console.WriteLine("Bye Bye ");
break;
}
Console.WriteLine(str);
str += "\r\n";
byte [] dataWrite = Encoding.Default.GetBytes(str);
stream.Write(dataWrite,0,dataWrite.Length);
}
}
catch (Exception e )
{
Console.WriteLine(e.ToString());
}
finally {
clientSocket.Close();
}
}
}
public class EchoServer
{
public static void Main(string [] arg)
{
TcpListener tcpListener = null;
try
{
//IP주소를 나타내는 객체를 생성,TcpListener를 생성시 인자로 사용할려고
IPAddress ipAd = IPAddress.Parse("172.18.1.186");
//TcpListener Class를 이용하여 클라이언트의 연결을 받아 들인다.
tcpListener = new TcpListener(ipAd, 8000);
tcpListener.Start();
Console.WriteLine("Waiting for connections...");
while(true)
{
// acepting the connection
Socket client = tcpListener.AcceptSocket();
ClientHandler cHandler = new ClientHandler();
// passing value to the thread class
cHandler.clientSocket = client;
// creating a new thread for the client
Thread clientThread = new Thread(new ThreadStart(cHandler.runClient));
clientThread.Start();
}
}
catch(Exception exp)
{
Console.WriteLine("Exception: " + exp);
}
finally {
tcpListener.Stop();
}
}
}
댓글 없음:
댓글 쓰기