Socket 에 Header 정보와 같이 묶어 보내기



정보를 보낼때 헤더는 참 유용하고 필수적이다. 편지를 쓴다고 생각하자면, 받는사람 , 주소 , 우편번호 등등이 헤더에 
해당할것이고 , 동내 구멍가게에서 라면을 사더라도 , 이라면이 무슨라면인지 , 매운맛인지 순한맛인지 ,조리법은 어떻
게 되는지 등등이 해더에 해당하는 정보라고 생각한다.

이처럼 무언가를 보낼때 이것이 어떠한 것이다 라는것을 표현할때는 조금은 바이트 배열을 이해할 필요가 있다.
as3 에서는 ByteArray에 해당할것이고 , c# 에서는 Stream 등에 해당할것이다.

그리고 해더는 Text로 읽을수 있는 정보일것이고, (물론 어느 오브젝트 바이트 배열로 하겠다면 구지 텍스트가 아니어도 된다. ) 컨텐츠 영역은 Text일수도 있고 바이너리 일수도 있다. 

문제는 없다. 뭐 어찌되었든 바이트로 넘어오고 약속된 영역을 텍스트로 치환하느냐, 바이너리로 통과 시키냐의 차이이다. 

아래의 그림은 헤더를 보내는 한가지 아이디어가 될것이다. 무조건 0바이트 부터 128 바이트까지 텍스트로 된 헤더라고 가정하고 있다. 혹 헤더가 128이 채워지지 않았다면 인위적으로 채워 버려 꼭 128을 만들어 버린다. ( 내가 생각하는 헤더에는 경로 , 타입, 기타코멘트 등등해서 128바이트면 충분하다고 생각해서 128이라고 한것, 그뿐이다.)

그리고 129번째 바이트 부터는 원하는 내용을 채우면 된다.
(이러한 해더의 아이디어를 발전시키고 싶다면 유명한 포토샵파일 PSD 의 바이트코드를 분석해 보라. 기가막히게 순수하고 심플하게 되어 있다.)



그럼 위의 그림을 토대로 코드를 한번 보자 

As3 에서 헤더 정보로 경로를 Text형대로 보내고 나머지는 카메라에서 캡쳐 받은 png포멧을 보낸다.
c#은 헤더로 넘어온 것을 FileStream의 경로로 지정하고 내용을 해당 경로에 저장한다.(버퍼의 사용은 이전글을 참고)

c# 서버
using System;
using System.Windows;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Text;

namespace testEncoderRecieve
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
        }

        private Task ServerThread;
        private TcpListener server;
        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            ServerThread = new Task(startServerThreaed);
            server = new TcpListener(System.Net.IPAddress.Parse("127.0.0.1"),5555);
            //
            ServerThread.Start();
        }
        void startServerThreaed()
        {
            //서버 스레드가 시작되고 서버가 시작되었다.
            Console.WriteLine("startServerThread");
            server.Start();

            //컨텐츠 버퍼와 헤더버퍼를 생성하였다.
            Byte[] buffer = new Byte[64];
            Byte[] headerBuffer = new Byte[128];
            int testCount = 0;
            while (true)
            {
                TcpClient client = server.AcceptTcpClient();
                NetworkStream netStream = client.GetStream();
                //netStream 에서 지정된 해더 바이트버퍼 만큼읽어서
                //해더정보를 입수한다.
                //그리고 netStream의 포지션은 128 이 되었다.
                netStream.Read(headerBuffer, 0, headerBuffer.Length);
                String rowHeader = Encoding.ASCII.GetString(headerBuffer);

                //String.Trim 을 이용해 불필요한 공백을 
                //제거하고 딱 필요한 헤더만 추출했다.
                string header = rowHeader.Trim();
                FileInfo fInfo = new FileInfo(header);

                //이전과 같이 파일 스트림을 생성하였고,
                //파일경로로는 헤더에서 넘어온 정보를 사용하였다.
                //그리고 여기서 읽을 netStream의 포지션은 129부터 이다.
                FileStream fs = new FileStream(fInfo.FullName, FileMode.OpenOrCreate, FileAccess.Write);
                int i = 0;
                while ((i = netStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    fs.Write(buffer, 0, i);
                }
                fs.Close();
                netStream.Close();
                client.Close();
                ++testCount;
            }
        }
    }
}


as3 클라이언트
package {
    import flash.events.Event;
    import flash.net.Socket;
    import flash.utils.ByteArray;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.media.Camera;
    import flash.media.Video;
    /**
     * @author superSc_PC
     */
     
    [SWF(width = "1000")]
    public class Main extends Sprite
    {
        private var cam : Camera;
        private var vid : Video;
        private var captureBitmap : Bitmap;
        
        private var socket : Socket;
        private var headerBufferSize : int = 128;
        private var header : ByteArray = new ByteArray();
        private var captureByte : ByteArray;
        public function Main()
        {
            //필요한것들을 생성했다.
            cam = Camera.getCamera();
            vid = new Video();
            vid.attachCamera(cam);
            captureBitmap = new Bitmap(new BitmapData(vid.width, vid.height));
            captureBitmap.x = vid.width;
            addChild(vid);
            addChild(captureBitmap);
            stage.addEventListener(MouseEvent.CLICK    , takePic);
            
            socket = new Socket();
            socket.addEventListener(Event.CONNECT, connectFn);
            
            //header 에 필요한정보를 입력하였다.
            //그리고 바이트의 공백을 매꾸기 위해 while루프로 쓰레기 정보들을
            //입력하였고 마지막 바이트로 줄바꿈"\n"을 입력 하였다.
            header.writeUTFBytes("d:/testAS.png");
            while(header.position < headerBufferSize-1)
            {
                header.writeUTFBytes(" ");
            }
            header.writeUTFBytes("\n");
        }
        
        
        private function connectFn(event : Event) : void {
            if (captureByte != null && captureByte.length > 0)
            {
                //이전과 다르게 소켓에 연달아 2개의 바이트들을 보낸다.
                //처음에는 헤더정보를 다음엔 캡쳐된 png를 보낸다.
                //역시나 보내고 난뒤에 소켓을 죽인다.
                socket.writeBytes(header);
                socket.writeBytes(captureByte);
                socket.flush();
                socket.close();
            }
        }

        private function takePic(event : MouseEvent) : void {
            captureBitmap.bitmapData.draw(vid);
            captureByte = PngEncoder.encode(captureBitmap.bitmapData);
            captureByte.position = 0;
            if(socket.connected == false)
            {
                socket.connect("localhost", 5555);
            }
        }
    }
}


신고
Yamecoder 야매코더_
C# 2011.03.04 23:35
Powerd by Tistory, designed by criuce
rss