2014년 3월 23일 일요일

[닷넷소켓]C#으로 소켓(Socket) 다루기(2), [닷넷교육/C#교육/ASP.NET닷넷교육/닷넷C#강좌/구로디지털단지C#,ASP.NET/실무.NET,C#교육/재직자닷넷교육]

[닷넷소켓]C#으로 소켓(Socket) 다루기(2), [닷넷교육/C#교육/ASP.NET닷넷교육/닷넷C#강좌/구로디지털단지C#,ASP.NET/실무.NET,C#교육/재직자닷넷교육]

----------------------
Server Socket 작성 하기
----------------------

1. 소스 코드를 작성 하기 전에 우선 전체적인 코드를 개략적으로 이해 하기로 하자 .

우선 서버의 입장에서 로컬 종점을 생성 한다 . 리스닝을 위한 소켓을 열기 전에 로컬 종점 주소를 작성 해야 하며 서비스에 대한 종점을 생성 하기 위해 호스트의 IP 주소와 서비스의 포트 번호를 조합하여 TCP/IP 서비스의 고유 주소를 정의 한다 . Dns 클래스는 로컬네트워크 기기에서 지원하는 네트워크 주소에 대한 정보를 되돌려 주는 메소드를 제공 한다 . 로컬 네트워크 기기가 하나 이상의 네트워크 주소를 가지거나 로컬 시스템이 하나 이상의 네트워크 기기를 지원 한다면 Dns 클래스는 모든 네트워크 주소에 대한 정보를 되돌려 주며 애플리케이션은 아 배열에서 적절한 주소를 선택해야 한다 .

// 소켓에 사용할 종점을 설정
IPHostEntry ipHost = DNS.Resolve(“localhost”);
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

2. 다음은 Socket 클래스의 새로운 인스턴스를 이용하여 스트림소켓을 생성 한다 . 이미 리스닝에 사용 할 로컬 종점을 작성 하였으므로 바로 소켓을 생성 할 수 있다 .

//TCP/IP 소켓을 생성
Socket sListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

AddressFamily 열거형은 Socket 인스턴스가 주소를 해석 하기 위해 사용하는 주소 스키마를 나타낸다 . 몇 가지 값들은 아래와 같다 .
AddressFamily.InterNetwork : IP 버전 4 주소
AddressFamily.InterNetwork V6: IP 버전 6 주소
AddressFamily.Ipx : IPX/SPX 주소
AddressFamily.NetBios: NetBios 주소

SocketType 은 TCP 와 UDP 소켓을 구분 하는데 이용 가능한 값은 아래와 같다 .

SocketType.Dgram : 데이터그램을 지원 , Dgram 은 Udp ProtocolType 과 AddressFamily.InterNetwork 와 함께 사용되어야 한다 .

SocketType.Raw : Raw Socket
SocketType.Stream : 스트림 소켓을 지원 , Stream 은 Tcp ProtocolType 과 AddressFamily.InterNetwork 와 함께 사용되어야 한다 .

세번째 파라미터 , 네번째 파라미터는 소켓에 필요한 프로토콜 형식을 정의 한다 . 그 값은 아래와 같다 .

Raw : Raw 패킷 프로토콜
Tcp : TCP
Udp : UDP
Ip : Internet Protocol

? 다음 단계는 Bind() 메소드를 사용하여 소켓에 이름을 부여 한다 . 생성자를 이용하여 소켓을 개방하면 소켓에 아무런 이름도 할강되어 있지 않다 . 즉 Bind() 메소드를 통해 소켓을 Local 종점에 연결 시키는 것이다 .
try {
sListener.Bind(ipEndPoint);
? 이제 소켓이 생성 되었고 , 이름이 바인딩 되었으므로 Listen() 을 사용하여 들어오는 연결에 대해 리스닝을 수행 할 수 있다 . 이때 파라미터에는 큐에 대기중인 연결의 최대 개수를 지정 한다 .
sListener.Listen(10);
? 위에서 리스닝을 했으므로 이젠 Accept() 를 이용하여 클라이언트의 연결을 수신하여 클라이언트와 서버의 이름 연결을 완료 한다 . Accept() 메소드는 대기중인 요청 큐로 부터 먼저 들어온 연결을 가지고 와 이를 처리할 새로운 소켓을 생성 한다 . 새로운 소켓이 생성 되었다고 하더라도 원래 소켓은 계속 리스닝을 수행 하므로 복수의 클라이언트 요청을 처리하기 위해서는 멀티쓰레드를 사용 한다 .
while(true) {
...
Socket handler = sListener.Accept();
? Send(), Receive() 메소드를 이용하여 데이터를 보내고 , 받는다 .
string data = null;
while(true) {
byte[] bytes = new byte[1024];
// 클라이언트로부터 수신된 데이터
int byteRes = handler.Receive(byte);
// 바이트를 문자열로 변환
data += Encoding.Default.GetString(bytes, 0, byteRec);
// 메시지의 끝인지 확인
if (data.IndexOf(“”) > -1) {
break;
}
}

? 루프를 빠져 나온 후 클라이언트에게 응답을 돌려주기 위해 새로운 바이트 배열을 준비 한다 . 변환을 마친 후 Send() 메소드를 이용하여 데이터를 보내자
string theReply = “Thank you for those ” + data.Length.ToString() + “ characters …”;
byte[] msg = Encoding.Default.GetBytes(theReply);
handler.Send();

? 서버와 클라이언트의 데이터 교환이 끝나면 Close() 를 이용하여 소켓을 종료 한다 . 항상 Close() 를 하기 전에 Shutdown() 을 이용하여 남아 있는 데이터를 확실히 제거 하자 . 각 소켓 인스턴스 마다 Close() 메소드를 호출 해야 한다 .
handler.Shutdown(SocketShutdown.Both);
handler.Close();

SocketShutdown 값은 열거형으로 아래와 같은 값을 취한다 .
Both : 송 . 수신용 소켓 모두
Receive : 수신용
Send : 송신용 소켓


소스 코드는 아래와 같다 .[SocketServer.cs]

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

public class SocketServer
{
public static void Main (string [] args)
{
// establish the local end point for the socket
IPHostEntry ipHost = Dns.Resolve("localhost");
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);
// create a Tcp/Ip Socket
Socket sListener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// bind the socket to the local endpoint and
// listen to the incoming sockets
try
{
sListener.Bind(ipEndPoint);
sListener.Listen(10);
// Start listening for connections
while (true)
{
Console.WriteLine("Waiting for a connection on port {0}",ipEndPoint);
// program is suspended while waiting for an incoming connection
Socket handler = sListener.Accept();
string data = null;
// we got the client attempting to connect
while(true)
{
byte[] bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
data += Encoding.ASCII.GetString(bytes,0,bytesRec);
if (data.IndexOf("") > -1)
{
break;
}
}
// show the data on the console
Console.WriteLine("Text Received: {0}",data);

string theReply = "Thank you for those " + data.Length.ToString()
+ " characters...";
byte[] msg = Encoding.ASCII.GetBytes(theReply);
handler.Send(msg);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
} // end of Main
}



----------------------
Client Socket 작성 하기
----------------------

1. 클라이언트 코드가 서버와 다른 점은 Connect() 메소드 부분이다 . 이것은 클라이언트가 원격의 서버에 연결 하고자 할 때 사용하는 메소드 이다 . 사용하기 위해서는 우선 원격 종점을 설정 해야 한다 .

// 소켓에 사용할 원격 종점을 설정
IPHostEntry ipHost = DNS.Resolve(“127.0.0.1”);
IPAddress ipAddr = ipHost.AddressList[0];

IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);

Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

sender.Connect(ipEndPoint);

Connect() 메소드로 소켓을 종점 파라미터로 지정된 원격 호스트와 연결을 맺는다 . 일단 연결이 이루어 지면 데이터를 보내고 받을 수 있다 .

string theMessage = “This is a test”;
byte[] msg = Encoding.Default.GetBytes(theMessage+””);

// 소켓을 이용하여 데이터를 보냄
int bytesSend = sender.Send(msg);



// 원격으로부터 ( 서버 ) 응답을 수신
int bytesRec = sender.Receive(bytes);



이젠 마지막으로 Shutdown() 을 호출하여 소켓을 해제 한다 . 그리고 Close() 하자

sender.Shutdown(SocketShutdown.Both);
sender.Close();


[ 아래는 SocketClient.cs 의 소스 파일 이다 .]

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

public class SocketClient
{
// If you specify any text as a command-line argument, it will be sent to the server.
// e.g. SocketClient "Send this text" will send that string
// If no command-line arguments are specified, a default string is sent

public static void Main (string [] args)
{
// data buffer for incoming data
byte[] bytes = new byte[1024];
// connect to a Remote device
try
{
// Establish the remote end point for the socket
IPHostEntry ipHost = Dns.Resolve("127.0.0.1");
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000);
Socket sender = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors
sender.Connect(ipEndPoint);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
//string theMessage=Console.ReadLine();
string theMessage;

if (args.Length==0)
theMessage = "This is a test";
else
theMessage = args[0];

byte[] msg = Encoding.ASCII.GetBytes(theMessage+"");
// Send the data through the socket
int bytesSent = sender.Send(msg);
// Receive the response from the remote device
int bytesRec = sender.Receive(bytes);
Console.WriteLine("The Server says : {0}",
Encoding.ASCII.GetString(bytes,0, bytesRec));
// Release the socket
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
catch(Exception e)
{
Console.WriteLine("Exception: {0}", e.ToString());
}
}
}







댓글 없음:

댓글 쓰기