실버라이트와 통신하는 소켓 통신 서버 규칙
943 포트를 통해 보아 정책 파일을 제공해야 한다.
4502~4534 사이의 포트를 이용해야 한다.
에코 서버 작성하기
에코 서버는 클라이언트로부터 문자열을 전송받아 다시 클라이언트에게 전송하는 역할을 합니다.
에코 서버는 실버라이트가 아닌 닷넷 기반의 콘솔 애플리케이션 위에서 작동하므로 먼저 C#콘솔 애플리케이션 프로젝트를 생성해야 합니다.
새 프로젝트 - C# / Windows / Console Application 선택합니다.
이름에 EchoServer를 입력하고 프로젝트가 저장될 Location은 임의로 저장합니다.
그다음 클래스를 생성하기 위해 위 프로젝트 에서 마우스 오른 클릭을 하여 추가-클래스 를 클릭합니다.
이름 입력 상자에 EchoServer.cs로 입력한 후 확인을 누릅니다.
EchoServer.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace EchoServer
{
class EchoServer
{
public void StartServer()
{
Console.WriteLine("EchoServer를 시작합니다.");
// SocketServer 생성
// 포트 4530
TcpListener listener = new TcpListener(IPAddress.Any, 4530);
listener.Start();
while (true)
{
byte[] buffer = new byte[512];
// 클라이언트 접속 기다림
Socket clientSocket = listener.AcceptSocket();
Console.WriteLine("클라이언트가 접속했습니다.");
while (true)
{
// 클라이언트로부터 문장 수신
int receiveLength =
clientSocket.Receive(buffer, 512, SocketFlags.None);
// 클라이언트로 다시 문장 전송
if (receiveLength > 0)
clientSocket.Send(buffer, 512, SocketFlags.None);
else
{
clientSocket.Shutdown(SocketShutdown.Both);
break;
}
}
}
}
}
}Program.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace EchoServer
{
class Program
{
static void Main(string[] args)
{
EchoServer server = new EchoServer();
server.StartServer();
}
}
}보안 정책 서버 작성하기
실버라이트는 네트워크 통신을 하기 위해서 반드시 보안 정책 파일이 있어야 합니다.
특히 소켓을 이용하는 실버라이트 클라이언트는 이용하고자 하는 소켓 서버의 943 포트로 보안 정책 파일을 요청합니다. 943 포트를 이용해 보안 정채 서버를 작동시키기 위해 위 서버 프로젝트에 하나의 프로젝트를 더 추가하도록 하겠습니다.
새 프로젝트 - Windows - 콘솔 Application 선택
이름 입력상자에 PolicyServer라고 입력하고 Location을 임의로 지정합니다.
그리고 중요한 부분으로 Solution은 Add to Solution을 선택해 현재 솔루션에 프로젝트가 추가할 수 있도록 지정합니다.
다음으로 보안 파일을 생성합니다.
PsolicyServer 프로젝트위에서 마우스 오른쪽 버튼을 클릭해서 추가-새 항목 추가를 클릭합니다.
나타나는 대화창에서 XML File을 선택하고, 이름을 clientaccesspolicy.xml로 입력합니다.
clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8"?> <access-policy> <cross-domain-access> <policy> <allow-from> <domain uri="*" /> </allow-from> <grant-to> <socket-resource port="4530" protocol="tcp" /> </grant-to> </policy> </cross-domain-access> </access-policy>
* 다수의 포트를 사용할 때에는 4530-4532와 같이 범위로 입력할 수 있습니다.
다음으로 PolicyServer 클래스를 생성합니다.
(추가-클래스 - 이름을 PolicyServer로 입력)
PolicyServer.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
namespace PolicyServer
{
class PolicyServer
{
private string policyRequestString = "<policy-file-request/>";
private string policyFilePath = @"..\..\clientaccesspolicy.xml";
private byte[] policy;
public void StartServer()
{
Console.WriteLine("PolicyServer를 시작합니다.");
// Policy 파일의 내용을 읽습니다.
FileStream policyStream = new FileStream(policyFilePath, FileMode.Open);
policy = new byte[policyStream.Length];
policyStream.Read(policy, 0, policy.Length);
policyStream.Close();
// SocketServer 생성
// 포트 943
TcpListener listener = new TcpListener(IPAddress.Any, 943);
listener.Start();
while (true)
{
byte[] buffer = new byte[512];
// 클라이언트 접속 기다림
Socket clientSocket = listener.AcceptSocket();
Console.WriteLine("클라이언트가 접속했습니다.");
// 클라이언트로부터 문장 수신
int receiveLength = clientSocket.Receive(buffer, 512, SocketFlags.None);
if (receiveLength > 0)
{
string receiveString = System.Text.Encoding.UTF8.GetString(buffer, 0, receiveLength);
// 클라이언트로부터 받은 문장이
// <policy-file-request/>라면
// 클라이언트에게 보안 정책 파일 전송
if (receiveString.Equals(policyRequestString)) clientSocket.Send(policy, 0, policy.Length, SocketFlags.None);
}
// 클라이언트와 연결 종료
clientSocket.Close();
}
}
}
}
마지막으로 PolicyServer를 작동하기 위해 Program.cs를 열어 아래와 같이 입력합니다.
Program.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace PolicyServer
{
class Program
{
static void Main(string[] args)
{
PolicyServer server = new PolicyServer();
server.StartServer();
}
}
}마지막으로 EchoServer와 PolicyServer를 동시에 시작하게 하기 위해서,
솔루션에서 오른클릭하여 Properties를 클릭합니다.
대화창에서 EchoServer와 PolicyServer의 Action을 Start 로 변경합니다.
에코 클라이언트 작성하기
Echoclient라는 이름의 실버라이트 프로젝트를 생성하고, 다음과 같이 코드를 입력합니다.
Main.xaml
<Grid x:Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBox x:Name="tbSendString" Grid.Row="0" Grid.Column="0"/> <Button x:Name="btSend" Content="전송" Grid.Row="1" Grid.Column="0"/> <TextBlock x:Name="tbReceiveString" Grid.Row="0" Grid.Column="1"/> </Grid>
MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Net.Sockets;
namespace EchoClient
{
public partial class MainPage : UserControl
{
Socket socket;
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
btSend.Click += new RoutedEventHandler(btSend_Click);
}
void btSend_Click(object sender, RoutedEventArgs e)
{
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.Completed += new EventHandler<SocketAsyncEventArgs>(SocketCompleted);
byte[] response = System.Text.Encoding.UTF8.GetBytes(tbSendString.Text);
args.SetBuffer(response, 0, response.Length);
socket.SendAsync(args);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
DnsEndPoint endPoint = new DnsEndPoint("127.0.0.1", 4530);
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.RemoteEndPoint = endPoint;
args.Completed += new EventHandler<SocketAsyncEventArgs>(SocketCompleted);
socket.ConnectAsync(args);
}
void SocketCompleted(object sender, SocketAsyncEventArgs e)
{
// 서버에 접속한 경우
if (e.LastOperation == SocketAsyncOperation.Connect)
{
if (e.SocketError != SocketError.Success)
{
Dispatcher.BeginInvoke(() => MessageBox.Show("서버에 접속할 수 없습니다."));
return;
}
}
else if (e.LastOperation == SocketAsyncOperation.Send)
{
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.Completed += new EventHandler<SocketAsyncEventArgs>(SocketCompleted);
byte[] response = new byte[512];
args.SetBuffer(response, 0, response.Length);
socket.ReceiveAsync(args);
}
else if (e.LastOperation == SocketAsyncOperation.Receive)
{
string receiveString = System.Text.Encoding.UTF8.GetString(e.Buffer, 0, e.Buffer.Length);
Dispatcher.BeginInvoke(() => tbReceiveString.Text = receiveString);
}
}
}
}