TCP 화면 전송 예제
TCP 클라이언트/서버 샘플
이번 아티클에서는 TCP 클라이언트와 TCP 서버가 서로 통신하는 간단한 샘플을 소개한다.
이 샘플은 TCP 클라이언트가 화면을 캡처하여 TCP 서버로 전송하는 예제이다.
간단한 예시를 위한 것으로 복잡한 프로토콜을 사용하지는 않았으며,
가장 단순하게 처음 전송 바이트수를 보내고 다음으로 실제 바이트들을 전송하게 된다.
또한, 가능한 한 단순하게 핵심 기능만 포커스하기 위해 에러 체킹 및 부수적인 코드 등은 생략하였다.
TCP 클라이언트 예제
TCP 클라이언트는 스크린 캡처한 Bitmap 이미지를 바이트 배열로 변환하여 이를 TCP 서버 127.0.0.1:7000 으로 전송하는 일을 한다.
전소을 위해 먼저 이미지의 총 바이트수를 전단하여 서버가 얼마만큼의 데이타를 받을 지 알게하고,
이후 실제 이미지 바이트 데이타를 전송한다. 데이타 전송이 모두 끝난 후, TCP 서버가 결과를 리턴하면 이를 받아 전송 성공 여부를 화면에 표시한다.
전송 결과를 간단히 한 바이트로서 1이면 성공, 0이면 실패이다.
using System;
using System.Net.Sockets;
using System.Drawing;
using System.Windows.Forms;
namespace ScrCli
{
class Program
{
static void Main(string[] args)
{
int BUFF_SIZE = 1024;
string server = "127.0.0.1";
int port = 7000;
TcpClient tc = new TcpClient(server, port);
Bitmap bmp = ScreenCapture();
var imgconv = new ImageConverter();
byte[] imgbytes = (byte[]) imgconv.ConvertTo(bmp, typeof(byte[]));
byte[] nbytes = BitConverter.GetBytes(imgbytes.Length);
using (NetworkStream stream = tc.GetStream())
{
// (1) 먼저 데이타 크기 전달
stream.Write(nbytes, 0, nbytes.Length);
// (2) 다음 실제 데이타 전달
int end = imgbytes.Length;
int start = 0;
while (start < end)
{
int n = end - start >= BUFF_SIZE ? BUFF_SIZE : end - start;
stream.Write(imgbytes, start, n);
start += n;
}
// (3) 결과 수신: 성공이면 1, 실패이면 0
byte[] result = new byte[1];
stream.Read(result, 0, result.Length);
Console.WriteLine(result[0]);
}
tc.Close();
}
static Bitmap ScreenCapture()
{
Rectangle rect = Screen.PrimaryScreen.Bounds;
Bitmap scrbmp = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(scrbmp))
{
g.CopyFromScreen(rect.X, rect.Y, 0, 0, scrbmp.Size, CopyPixelOperation.SourceCopy);
}
return scrbmp;
}
}
}
TCP 서버 예제
TCP 서버는 로컬 컴퓨터의 7000 포트를 열고 스크린 이미지를 수신하는 일을 한다.
(프로그램을 처음 실행하면 Firewall 의 7000 포트를 허용하는 다이얼로그가 뜨게 된다)
TCP 클라이언트에서 전송하는 데이타의 순서에 따라 먼저 이미지 크기를 4바이트로 전송받아 이를 int 로 변환한다.
다음으로 총 이미지 바이트수 만큼 계속 루프를 돌며 데이타를 전송받은 후, 이를 파일로 저장한다.
전송이 끝난 후 성공여부를 한 바이트로 송신한다. 여기서 통신상의 에러 등을 체크하여 실패를 체크하는 부분은 생략하였다.
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace ScrSrv
{
class Program
{
static void Main(string[] args)
{
RunServer();
Console.ReadLine();
}
// illustration purpose only
async static void RunServer()
{
int BUFF_SIZE = 1024;
TcpListener listener = new TcpListener(IPAddress.Any, 7000);
listener.Start();
while (true)
{
TcpClient tc = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
NetworkStream stream = tc.GetStream();
// (1) 먼저 데이타 크기 수신
byte[] bytes = new byte[4];
int nb = await stream.ReadAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
if (nb != 4)
{
throw new ApplicationException("Invalid size");
}
int total = BitConverter.ToInt32(bytes, 0);
// (2) 다음 실제 데이타 수신
string filename = Guid.NewGuid().ToString("N") + ".png";
using (var fs = new FileStream(filename, FileMode.CreateNew))
{
var buff = new byte[BUFF_SIZE];
int received = 0;
while (received < total)
{
int n = total - received >= BUFF_SIZE ? BUFF_SIZE : total - received;
nb = await stream.ReadAsync(buff, 0, n).ConfigureAwait(false);
received += nb;
await fs.WriteAsync(buff, 0, nb);
}
}
// (3) 성공 여부 송신 (에러 체크 생략)
byte[] result = new byte[1];
result[0] = 1; // success
await stream.WriteAsync(result, 0, result.Length).ConfigureAwait(false);
stream.Close();
tc.Close();
}
}
}
}