탑크리에듀(www.topcredu.co.kr) 제공 C#, Network 기초강좌 입니다. 이번 강좌는 클라이언트가 서버로 데이터만 전송하는 간단한 TCP 클라이언트 및 서버 작성부터 서버가 다시 클라이언트로 에코우 시키는 예제, 이를 멀티쓰레드로 변경하여 여러 클라이언트를 상대할 수 있도록 소스를 변경하여 적성된 예제 입니다. 동영상으로도 제작될 예정이며 동영상은 http://www.topcredu.co.kr 또는 http://www.facebook.com/topcredu.co.kr, http://ojc.asia 에서 확인하실 수 있습니다.
(C#,네트워크강좌)간단한 TCP 클라이언트/서버 구현, 멀티쓰레드 기반 에코우 클라이언트/서버_C추천#/WPF/자마린실무교육학원
1. 소스코드, 강의자료 및 동영상 보기는 http://www.topcredu.co.kr, http://ojc.asia 에서 가능 합니다.
7. C# Network 프로그래밍
7-1. 간단한 TCP 클라이언트, 서버
TCP Client & Server 만들기
System.Net.Sockets.TCPClient : TCP 네트웍의 클라이언트 서비스를 제공하고 Socket
클래스를 기본으로 작성 되었다. FTP나 HTTP와 같은 애플리케이션 계층 프로토콜을 개
발하는데 주로 사용 된다.
2. 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 네트웍의 클라이언트 접속을 Listening하며 소켓
클래스를 기반으로 TCP 서비스를 제공하기 위한 서버쪽 클래스이다. FTP, HTTP와 같은
프로토콜을 사용하는 애플리케이션 계층은 TcpListener를 기반으로 작성 될 수 있다.
클라이언트는 서버로 글을 보내기만 하고, 서버는 글을 받아서 출력만 하는 간단한 예제
를 작성해 보자.
[클라이언트]
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 연결을 생성하고 데이터를 송수신을
//위한 스트림을 얻는다.
client = new TcpClient();
3. client.Connect("localhost", 5001);
NetworkStream stream = client.GetStream();
StreamWriter writer = new StreamWriter(stream)
{ AutoFlush = true };
string dataToSend = Console.ReadLine();
while (true)
{
writer.WriteLine(dataToSend);
if (dataToSend.IndexOf("<EOF>") > -1) break;
dataToSend = Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
client.Close();
}
}
}
[서버]
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
class Server
{
public static void Main()
{
4. NetworkStream stream = null;
TcpListener tcpListener = null;
Socket clientsocket = null;
StreamReader reader = null;
try
{
//IP주소를 나타내는 객체를 생성,TcpListener를 생성시 인자로 사용할려고
IPAddress ipAd = IPAddress.Parse("127.0.0.1");
//TcpListener Class를 이용하여 클라이언트의 연결을 받아 들인다.
tcpListener = new TcpListener(ipAd, 5001);
tcpListener.Start();
//Client의 접속이 올때까지 블로킹 되는 부분,
//대개 이부분을 Thread로 만들어 보내 버린다.
//백그라운드 Thread에 처리를 맡긴다.
clientsocket = tcpListener.AcceptSocket();
//클라이언트의 데이터를 읽고, 쓰기 위한 스트림을 만든다.
stream = new NetworkStream(clientsocket);
Encoding encode = Encoding.GetEncoding("utf-8");
reader = new StreamReader(stream, encode);
while (true)
{
string str = reader.ReadLine();
Console.WriteLine(str);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
clientsocket.Close();
}
5. }
}
위의 예제는 Client는 단순히 보내기만 하고 Server는 단순히 받기만 한다. 적절히 수정
하여 Client가 보내는 것을 서버는 화면에 출력하고 Client에 다시 보내는 EchoClient와
EchoServer를 작성 해보자. 이 경우 Client 역시 보내고 받는 부분의 처리가 가능해야
한다.
7-2. EchoClient, EchoServer
[클라이언트]
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 stream = client.GetStream();
Encoding encode = Encoding.GetEncoding("utf-8");
StreamReader reader = new StreamReader(stream, encode);
StreamWriter writer = new StreamWriter(stream, encode)
{ AutoFlush = true };
6. string dataToSend = Console.ReadLine();
while (true)
{
writer.WriteLine(dataToSend);
String str = reader.ReadLine();
Console.WriteLine(str);
if (dataToSend.IndexOf("<EOF>") > -1) break;
dataToSend = Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
client.Close();
}
}
}
[서버]
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;
Socket clientsocket = null;
StreamReader reader = null;
StreamWriter writer = null;
7. 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 = Encoding.GetEncoding("utf-8");
reader = new StreamReader(stream, encode);
writer = new StreamWriter(stream, encode) { AutoFlush = true };
while (true)
{
string str = reader.ReadLine();
Console.WriteLine(str);
writer.WriteLine(str);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
clientsocket.Close();
}
}
}
8. [질문] 위의 예제에서 Client를 두 개 이상 만들어서 서버에 접속해보자.
과연 어떤 일이 일어 날까? 그리고 그 해결책은 무엇일까? 아마도 멀티 쓰레드를 이용
하여 블록킹 되는 메소드를 쓰레드로 처리를 해야 할것이다. 직접 실습해 보자..
7-3. MultiThread EchoClient, EchoServer
Client Program은 그대로 두고 서버를 다시 만들자.
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
class ClientHadler
{
Socket socket = null;
NetworkStream stream = null;
StreamReader reader = null;
StreamWriter writer = null;
public ClientHadler(Socket socket)
{
this.socket = socket;
}
public void chat()
{
//클라이언트의 데이터를 읽고, 쓰기 위한 스트림을 만든다.
stream = new NetworkStream(socket);
Encoding encode = Encoding.GetEncoding("utf-8");
reader = new StreamReader(stream, encode);
writer = new StreamWriter(stream, encode) { AutoFlush = true };
9. while (true)
{
string str = reader.ReadLine();
Console.WriteLine(str);
writer.WriteLine(str);
}
}
}
class Server
{
public static void Main()
{
TcpListener tcpListener = 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에 처리를 맡긴다.
while (true)
{
clientsocket = tcpListener.AcceptSocket();
ClientHadler cHandler = new ClientHadler(clientsocket);
Thread t = new Thread(new ThreadStart(cHandler.chat));
t.Start();
}