프로젝트/원격 제어 프로그램 만들기

화면 캡쳐 및 이미지 송신 클라이언트 및 수신 서버 구현하기

언제나휴일 2020. 5. 12. 21:26
반응형

 

원격제어 프로그램 만들기에서 구현한 이미지 송수신 부분을 라이브러리로 만들고 이를 이용하여 클라이언트와 서버 응용을 만드는 실습입니다.

ImageClient.cs

//http://ehpub.co.kr
//원격 제어 프로그램
//7. 이미지 전송 클라이언트

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace 원격제어_프로그램
{
    /// <summary>
    /// 이미지 전송 클라이언트
    /// </summary>
    public class ImageClient
    {
        Socket sock;
        /// <summary>
        /// 연결 메서드
        /// </summary>
        /// <param name="ip">연결할 서버 측 IP주소</param>
        /// <param name="port">연결할 서버 측 Port</param>
        public void Connect(string ip,int port)
        {
            sock = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);

            IPAddress ipaddr = IPAddress.Parse(ip);
            IPEndPoint ep = new IPEndPoint(ipaddr, port);
            sock.Connect(ep);
        }

        
        /// <summary>
        /// 이미지 전송 메서드
        /// </summary>
        /// <param name="img">전송할 이미지</param>
        /// <returns>전송 성공 여부</returns>
        public bool SendImage(Image img)
        {
            if(sock == null)
            {
                return false;
            }
            MemoryStream ms = new MemoryStream();
            img.Save(ms, ImageFormat.Jpeg);
            byte[] data = ms.GetBuffer();
            try
            {
                int trans = 0;
                byte[] lbuf = BitConverter.GetBytes(data.Length);
                sock.Send(lbuf);//전송할 이미지 길이를 먼저 전송

                while(trans <data.Length)
                {                    
                    trans += sock.Send(data, trans, data.Length - trans, SocketFlags.None);
                }
                sock.Close();
                sock = null;
                return true;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// 비동기로 이미지를 전송하는 메서드
        /// </summary>
        /// <param name="img">전송할 이미지</param>
        /// <param name="callback">이미지 전송을 완료하였을 때 처리할 콜백</param>
        public void SendImageAsync(Image img, AsyncCallback callback)
        {
            SendImageDele dele = SendImage;
            dele.BeginInvoke(img, callback, this);
        }
        public void Close()
        {
            if(sock != null)
            {
                sock.Close();
                sock = null;
            }
        }
    }
    /// <summary>
    /// 이미지를 비동기로 전송하기 위해 정의한 대리자
    /// </summary>
    /// <param name="img">전송할 이미지</param>
    /// <returns>이미지 전송 성공  여부</returns>
    public delegate bool SendImageDele(Image img);
}

ImageServerc.cs

using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace 원격제어_프로그램
{
    public class ImageServer
    {
        Socket lis_sock;
        public event RecvImageEventHandler RecvedImage = null;

        public ImageServer(string ip,int port)
        {
            lis_sock = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipaddr = IPAddress.Parse(ip);
            IPEndPoint ep = new IPEndPoint(ipaddr, port);
            lis_sock.Bind(ep);
            lis_sock.Listen(5);
            lis_sock.BeginAccept(DoAccept, null);
        }
        void DoAccept(IAsyncResult result)
        {
            if(lis_sock == null)
            {
                return;
            }
            try
            {
                Socket dosock = lis_sock.EndAccept(result);
                Recevice(dosock);
                lis_sock.BeginAccept(DoAccept, null);
            }
            catch
            {
                Close();
            }
        }

        public void Close()
        {
            if(lis_sock!=null)
            {
                lis_sock.Close();
                lis_sock = null;
            }
        }

        private void Recevice(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 ep = dosock.RemoteEndPoint as IPEndPoint;
                RecvImageEventArgs e = new RecvImageEventArgs(ep, ConvertBitmap(buffer));
                RecvedImage(this, e);
            }

        }
        public Bitmap ConvertBitmap(byte[] data)
        {
            MemoryStream ms = new MemoryStream();
            ms.Write(data, 0, (int)data.Length);
            Bitmap bitmap = new Bitmap(ms);
            return bitmap;
        }
    }
}

RecvImageEventArgs.cs

using System;
using System.Drawing;
using System.Net;

namespace 원격제어_프로그램
{
    /// <summary>
    /// 이미지 수신 처리를 위한 대리자
    /// </summary>
    /// <param name="sender">이벤트 통보 개체(게시자)</param>
    /// <param name="e">이벤트 처리 인자</param>
    public delegate void RecvImageEventHandler(object sender, RecvImageEventArgs e);
    
    /// <summary>
    /// 이미지 수신 이벤트 인자 클래스
    /// </summary>
    public class RecvImageEventArgs:EventArgs
    {
        /// <summary>
        /// IP 단말 - 가져오기
        /// </summary>
        public IPEndPoint IPEndPoint
        {
            get;
            private set;
        }
        /// <summary>
        /// IP 주소 - 가져오기
        /// </summary>
        public IPAddress IPAddress
        {
            get
            {
                return IPEndPoint.Address;
            }
        }
        /// <summary>
        /// IP 주소 문자열 - 가져오기
        /// </summary>
        public string IPAddressStr
        {
            get
            {
                return IPAddress.ToString();
            }
        }
        /// <summary>
        /// 포트 - 가져오기
        /// </summary>
        public int Port
        {
            get
            {
                return IPEndPoint.Port;
            }
        }
        /// <summary>
        /// 이미지 - 가져오기
        /// </summary>
        public Image Image
        {
            get;
            private set;
        }
        /// <summary>
        /// 이미지 크기 - 가져오기
        /// </summary>
        public Size Size
        {
            get
            {
                return Image.Size;
            }
        }
        /// <summary>
        /// 이미지 폭 - 가져오기
        /// </summary>
        public int Width
        {
            get
            {
                return Image.Width;
            }
        }
        /// <summary>
        /// 이미지 높이 - 가져오기
        /// </summary>
        public int Height
        {
            get
            {
                return Image.Height;
            }
        }
        /// <summary>
        /// 이미지 수신 이벤트 인자 클래스
        /// </summary>
        /// <param name="remote_iep">상대측 EndPoint</param>
        /// <param name="image">이미지</param>
        public RecvImageEventArgs(IPEndPoint ep, Image image)
        {
            IPEndPoint = ep;
            Image = image;            
        }
        /// <summary>
        /// ToString 메서드
        /// </summary>
        /// <returns>IP주소 및 이미지 크기를 문자열로 반환</returns>
        public override string ToString()
        {
            return string.Format("IP:{0} width:{1} Height:{2}", IPAddressStr, Width, Height);
        }
    }
}

이미지 서버의 Form1.cs

using System;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
using 원격제어_프로그램;

namespace 이미지_수신_서버
{
    public partial class Form1 : Form
    {        
        public Form1()
        {
            InitializeComponent();
        }

        ImageServer ims;
        int imgcnt = 0;
        private void Form1_Load(object sender, EventArgs e)
        {
            ims = new ImageServer(DefaultIP, 10200);
            ims.RecvedImage += Ims_RecvedImage;
        }

        private void Ims_RecvedImage(object sender, RecvImageEventArgs e)
        {
            imgcnt++;
            e.Image.Save(string.Format("{0}.bmp", imgcnt));
            lbox_fno.Items.Add(imgcnt);
        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(lbox_fno.SelectedIndex == -1)
            {
                return;
            }
            int icnt = (int)lbox_fno.SelectedItem;
            pbox.ImageLocation = string.Format("{0}.bmp", icnt);
        }
        static string DefaultIP
        {
            get
            {          
                //호스트 이름 구하기
                string host_name = Dns.GetHostName();
                //호스트 엔트리 구하기
                IPHostEntry host_entry = Dns.GetHostEntry(host_name);
                //호스트 주소 목록 반복
                foreach (IPAddress ipaddr in host_entry.AddressList)
                {
                    //주소 체계가 InterNetwork일 때
                    if (ipaddr.AddressFamily == AddressFamily.InterNetwork)
                    {
                        return ipaddr.ToString();//IP 주소 문자열 반환
                    }
                }
                return string.Empty;//빈 문자열 반환
            }
        }
    }
}

화면 캡쳐 및 이미지 전송 클라이언트의 Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using 원격제어_프로그램;

namespace 이미지_캡쳐_및_전송_클라이언트
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }


        string ip;
        ImageClient ic;
        private void Form1_Load(object sender, EventArgs e)
        {
            ic = new ImageClient();
            tbar_x1.Maximum = tbar_x2.Maximum = Screen.PrimaryScreen.Bounds.Width;
            tbox_y1.Maximum = tbary2.Maximum = Screen.PrimaryScreen.Bounds.Height;
        }

        private void but_setting_ip_Click(object sender, EventArgs e)
        {
            ip = tbox_server_ip.Text;
        }

        private void but_capture_send_Click(object sender, EventArgs e)
        {
            if(ic == null)
            {
                return;
            }
            int left = tbar_x1.Value;
            int right = tbar_x2.Value;
            if(left>right)
            {
                int temp = left;
                left = right;
                right = temp;
            }
            int top = tbox_y1.Value;
            int bottom = tbary2.Value;
            if(top>bottom)
            {
                int temp = top;
                top = bottom;
                bottom = temp;
            }
            int width = right - left;
            int height = bottom - top;
            if((width == 0)||(height==0))
            {
                return;
            }
            Bitmap bitmap = new Bitmap(width, height);
            Graphics gr = Graphics.FromImage(bitmap);
            Size size = new Size(width, height);
            gr.CopyFromScreen(new Point(left, top), new Point(0, 0), size);
            ic.Connect(ip, 10200);
            ic.SendImage(bitmap);
            ic.Close();
            pbox.Image = bitmap;
        }
    }
}

 

 

화면 캡쳐/이미지 전송 클라이언트와 이미지 수신 서버 만들기 – 언제나 휴일

안녕하세요. 언제나 휴일에 언휴예요. 이번 강의는 화면 캡쳐와 이미지를 전송하는 클라이언트 및 이미지를 수신하는 서버를 만들어 볼게요. 원격 제어 프로그램을 만들다가 갑자기 엉뚱한 걸 만든다고 생각하시나요? 7~9강까지 다룬 내용은 ImageClient, RecvImageEventArgs, ImageServer입니다. 이들은 이미지를 전송하고 수신하는 서버를 만들 때 사용할 수 있어요. 이번 강의는 이들을 라이브러리 형태로 만들고 이를 이용하는 프로그램을

ehpub.co.kr

 

반응형