원격 제어 컨트롤러는 원격 제어 호스트의 화면을 주기적으로 수신하여 이를 보면서 제어합니다. 이제 원격 제어 화면을 수신하는 ImageServer 클래스를 구현합시다.
public class ImageServer {
먼저 Listen 소켓과 연결 요청을 대기하고 수용하는 부분을 위한 스레드를 멤버로 선언합시다.
Socket lis_sock; //Listening 소켓 Thread accept_thread = null;
이미지를 수신할 때 이벤트 처리를 위해 RecvImageEventHandler 형식의 이벤트를 선언합시다.
public event RecvImageEventHandler RecvedImage = null;
생성자에서는 IP와 포트 정보를 받습니다.
public ImageServer(string ip, int port) {
TCP 소켓을 생성하세요.
//소켓 생성 lis_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
소켓과 IP 단말 개체와 결합하고 백로그 큐를 설정합니다.
//EndPoint와 소켓 결합 IPAddress ipaddr = IPAddress.Parse(ip); IPEndPoint ep = new IPEndPoint(ipaddr, port); lis_sock.Bind(ep); //Back 로그 큐 크기 설정 lis_sock.Listen(5);
클라이언트 연결 요청을 대기하고 수락하는 스레드를 생성하고 시작합니다.
//연결 수용 Loop을 수행하는 스레드 시작 ThreadStart ts = new ThreadStart(AcceptLoop); accept_thread = new Thread(ts); accept_thread.Start(); }
연결 요청을 대기하고 수락하는 AcceptLoop 메서드를 구현합시다.
void AcceptLoop() { try {
클라이언트 연결 요청을 대기하고 수락하는 부분은 무한 반복합니다.
while (lis_sock != null) {
Listen 소켓의 Accept 메서드를 호출하여 이미지를 수신할 작업 소켓을 구합니다.
Socket do_sock = lis_sock.Accept();//연결 수락
작업 소켓에서 이미지를 수신합니다.
Receive(do_sock);//do_sock으로 이미지 수신 } } catch { Close(); } }
작업 소켓에서 이미지를 수신하는 Receive 메서드를 구현합시다.
void Receive(Socket dosock) {
이미지 길이를 수신합니다.
byte[] lbuf = new byte[4]; //이미지 길이를 수신할 버퍼 dosock.Receive(lbuf); //이미지 길이 수신
수신한 이미지 길이만큼의 버퍼를 생성합니다.
int len = BitConverter.ToInt32(lbuf, 0);//수신한 버퍼의 내용을 정수로 변환 byte[] buffer = new byte[len];//이미지 길이만큼의 버퍼 생성
수신한 이미지 길이만큼의 이미지 데이터를 수신합니다.
int trans = 0; while (trans < len)//수신할 이미지 데이터가 남아있으면 { trans += dosock.Receive(buffer, trans, len - trans, SocketFlags.None);//이미지 수신 }
이미지 수신 이벤트에 등록 개체가 있으면 이미지 수신 이벤트를 발생합니다.
if (RecvedImage != null)//이미지 수신 이벤트가 존재하면 { //이미지 수신 이벤트 발생 IPEndPoint iep = dosock.RemoteEndPoint as IPEndPoint;
수신한 버퍼를 이미지로 변환하여 이벤트 인자를 생성합니다.
RecvImageEventArgs e = new RecvImageEventArgs(iep, ConvertBitmap(buffer));
이미지를 수신한 이벤트를 발생합니다.
RecvedImage(this, e); }
이미지를 수신하였으니 작업 소켓을 닫습니다.
dosock.Close();//소켓 닫기 }
수신한 이미지 버퍼를 이미지로 변환하는 ConvertBitmap 메서드를 구현합시다.
public Bitmap ConvertBitmap(byte[] data) {
byte 배열을 이미지로 변환하기 위해 메모리 스트림 개체를 생성합니다.
MemoryStream ms = new MemoryStream();
메모리 스트림 개체에 수신한 이미지가 있는 버퍼의 내용을 기록합니다.
ms.Write(data, 0, (int)data.Length);//메모리 스트림에 버퍼를 기록
메모리 스트림 개체로 비트맵 개체를 생성하여 반환하세요.
Bitmap bitmap = new Bitmap(ms); //메모리 스트림으로 비트맵 개체 생성 return bitmap; }
이미지 서버를 닫는 메서드도 제공합시다.
public void Close() {
이미 닫혀있을 수도 있으니 존재할 때만 닫습니다.
if (lis_sock != null) { lis_sock.Close();
소켓을 닫았으면 다시 Close 메서드를 호출하여도 아무 작업을 하지 않게 null로 설정하세요.
lis_sock = null; } } }
다음은 이번에 실습한 소스 코드입니다.
//ImageServer.cs using System.Net.Sockets; using System.Threading; using System.Net; using System.Drawing; using System.IO; using System; namespace 원격제어기 { /// <summary> /// 이미지 수신 서버 /// </summary> public class ImageServer { Socket lis_sock; //Listening 소켓 Thread accept_thread = null; /// <summary> /// 이미지 수신 이벤트 /// </summary> public event RecvImageEventHandler RecvedImage = null; /// <summary> /// 생성자 /// </summary> /// <param name="ip">로컬 IP</param> /// <param name="port">포트</param> public ImageServer(string ip, int port) { //소켓 생성 lis_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //EndPoint와 소켓 결합 IPAddress ipaddr = IPAddress.Parse(ip); IPEndPoint ep = new IPEndPoint(ipaddr, port); lis_sock.Bind(ep); //Back 로그 큐 크기 설정 lis_sock.Listen(5); //연결 수용 Loop을 수행하는 스레드 시작 ThreadStart ts = new ThreadStart(AcceptLoop); accept_thread = new Thread(ts); accept_thread.Start(); } void AcceptLoop() { try { while (lis_sock != null) { Socket do_sock = lis_sock.Accept();//연결 수락 Receive(do_sock);//do_sock으로 이미지 수신 } } catch { Close(); } } void Receive(Socket dosock) { byte[] lbuf = new byte[4]; //이미지 길이를 수신할 버퍼 dosock.Receive(lbuf); //이미지 길이 수신 int len = BitConverter.ToInt32(lbuf, 0);//수신한 버퍼의 내용을 정수로 변환 byte[] buffer = new byte[len];//이미지 길이만큼의 버퍼 생성 int trans = 0; while (trans < len)//수신할 이미지 데이터가 남아있으면 { trans += dosock.Receive(buffer, trans, len - trans, SocketFlags.None);//이미지 수신 } if (RecvedImage != null)//이미지 수신 이벤트가 존재하면 { //이미지 수신 이벤트 발생 IPEndPoint iep = dosock.RemoteEndPoint as IPEndPoint; RecvImageEventArgs e = new RecvImageEventArgs(iep, ConvertBitmap(buffer)); RecvedImage(this, e); } dosock.Close();//소켓 닫기 } /// <summary> /// 수신한 버퍼를 비트맵 이미지로 변환 메서드 /// </summary> /// <param name="data">수신한 버퍼</param> /// <returns>비트맵 이미지</returns> public Bitmap ConvertBitmap(byte[] data) { MemoryStream ms = new MemoryStream(); ms.Write(data, 0, (int)data.Length);//메모리 스트림에 버퍼를 기록 Bitmap bitmap = new Bitmap(ms); //메모리 스트림으로 비트맵 개체 생성 return bitmap; } /// <summary> /// 비트맵 이미지 서버 닫기 메서드 /// </summary> public void Close() { if (lis_sock != null) { lis_sock.Close(); lis_sock = null; } } } }