[TCPSocket] 안전한 Socket 연결과 버퍼데이터를 설정한 데이터전송 (C# <-> As3)


소켓사용을 꺼려하는 이유중 하나는 연결의 지속성을 보장하기가 까다롭기 때문이다. 또한 그것을 서로 스로스 체킹

하는 코드를 작성하기가 번거럽기 때문이기도 하다.

하지만 생각을 바꾸어 왜? 소켓을 항상 연결시켜 놔야 할까? 물론 실시간 데이터전송 같은경우 , 즉 마우스 좌표에 따라 무었을 지속적으로 움직여야 한다거나 하는 실시간적인 반응이 필요한 경우로 생각할수 있겠다.

하지만 데이터의 전송, 어느 순간 상태의 알림 등등의 경우에는 연결을 지속적으로 유지해야 할 필요가 없다.
본 모델은 이미 

에서 사용하였고 지금까지 별 탈없이 사용한 모델을, UTF텍스트가 아닌 바이너리를  전송하는 경우로 생각하여 바꾸어 보았다.

목표는 
1) 예전에 철없던 시절의 소켓서버 ( http://www.scripter.co.kr/entry/socket-c-server-as3-client )의 비효율성을 타파하여 좀더 세련된 방법으로 소켓을 구성하는 법.

2) "1)"의 연속적인 개념으로, 지속적인 연결이 아닌 한방에 한번씩 연결하여 전송하고 연결을 종료하는 방법.

3)큰 파일을 무리없이 전송하기 위해 버퍼를 설정하여 끊어 읽어 기록하는 방법

을 정리해보겠다.


우선 간단한 순서도를 보면 이러하다.


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

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);
            //TcpListener를 생성하고, 서버 스레드가 시작되었다
            ServerThread.Start();
        }
        void startServerThreaed()
        {
            //서버를 시작시킨다.
            server.Start();

            //버퍼를 설정한다. 우선64바이트 만큼만...
            Byte[] buffer = new Byte[64];

            int testCount = 0;
            while (true)
            {
                //클라이언트를 대기한다. 클라이언트로 부터 접속신호가 있기 전까지 루프는 여기서 멈춤.
                TcpClient client = server.AcceptTcpClient();
                //클라이언트가 접속하고 스트림을 가져 온다.
                NetworkStream netStream = client.GetStream();
                //파일스트림을 생성하여 FileAccess.write로 한다.
                FileStream fs = new FileStream(@"d:\test" + testCount + ".png", FileMode.OpenOrCreate , FileAccess.Write);
                int i = 0;
                while ((i = netStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    //여기서 정수i가 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;
        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); } //인코딩을 담을 바이트배열 변수 를 선언한다. private var captureByte : ByteArray; private function connectFn(event : Event) : void { //연결이 되었다. 간단한 유효성검사후 전송한다. if (captureByte != null && captureByte.length > 0) { socket.writeBytes(captureByte); socket.flush(); socket.close(); } //연결이 종료되었다. } private function takePic(event : MouseEvent) : void { captureBitmap.bitmapData.draw(vid); captureByte = PngEncoder.encode(captureBitmap.bitmapData); //화면이 클릭되고 캡쳐된 비트맵은 png로 인코딩된다. captureByte.position = 0; //바이트배열 포지션을 처음으로 돌려주고 //소켓을 연결한다. if(socket.connected == false) { //소켓이 연결되면 위에서 선언한이벤트에 의해 connectFn이 실행된다. socket.connect("localhost", 5555); } } } }


아직까지는 as3 에서 버퍼단위로 전송하는 writeByte의 기능은 없는듯하다. 버퍼를 이용하기 위해선
인위적으로 해더 정보를 보내서 서버에서 끝어 읽기 하는 알고리즘이 필요하다
Yamecoder 야매코더_
C# 2011.03.04 18:52

[XNA3.1 index buffer vertex buffter] 교과서와는 다른 버퍼메모리 사용법


한참을 방황했다.. 버퍼가 안되서..

DrawUserIndexPrimitives  vs  DrawIndexPrimitives   라는 주제를 한번쯤 보았을것이다.

물론 후자쪽이 빠르다. 그런데, 가지고 있는 한글번역판 책들은 죄다 xna1.0 버전이라,, 그런지

xna3 에서는 사용법이 달랐다.




Created with colorer-take5 library. Type 'csharp'

public void setVertices()
        {
            
           // vertices 들 ~//
            //vertexBuff 라는 멤버 변��가 있겠죠..
            vertexBuff = new VertexBuffer(device.GraphicsDevice, VertexPositionNormalTexture.SizeInBytes * vertices.Length, BufferUsage.WriteOnly);
            vertexBuff.SetData(vertices);
        }
        public void setIndices()
        {

           //index들  ~//
            //indexBuff 라는 멤버 변��가 있겠죠..
            indexBuff = new IndexBuffer(device.GraphicsDevice, typeof(int), indices.Length, BufferUsage.WriteOnly);
            indexBuff.SetData<int>(indices);
        }
        

         //메인클��스에 update()에 넣어야 함
        public void update()
        {
            device.GraphicsDevice.Vertices[0].SetSource(vertexBuff, 0, VertexPositionNormalTexture.SizeInBytes);
            device.GraphicsDevice.Indices = indexBuff;
        }

        //메인클��스에 draw()에 넣어야함
        public void render(Matrix view , Matrix projection)
        {
            effect.World = Matrix.Identity; ;
            effect.View = view;
            effect.Projection = projection;

            effect.Begin();

            /* //여러개일경우
            foreach (EffectPass p in effect.CurrentTechnique.Passes)
            {
                p.Begin();
                device.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertices.Length, 0, indices.Length / 3);
                p.End();
            }*/

            effect.CurrentTechnique.Passes[0].Begin();
            device.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertices.Length, 0, indices.Length / 3);
            effect.CurrentTechnique.Passes[0].End();

            effect.End();
           
        }
물론 여러가지 방법이야 있겠지만 꾀나 골머리를 썩은 문제이므로 일단 이대로 ..

update 부분은 render 에도 해도 되나 그냥 로직과 분리를 하고 싶은 마음에서 한거다.

한가지 덧붙이자면

effect.World 라던지 effect.View 라던지 effect.Projection 은 변경사항이 없다면

따로 메소드를 빼서 루프를 돌리지 않는 방법도 있다.





( 첫째도 퍼포먼스 둘째도 퍼포먼스 셋째는 수면... ? )

Yamecoder 야매코더_
XNA 2010.12.04 02:20
Powerd by Tistory, designed by criuce
rss