블로그 이미지
따시쿵

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

2014. 12. 23. 11:52 C# with TCP/IP

프로그램 설명


클라이언트가 보낸 데이타의 양이 많아서 한 번에 받을 수가 없는 경우가 있습니다. 보낸 데이타를 손실없이 모두 다 받는 방법을 설명합니다.


프로그램 구조의 핵심은 클라이언트가 데이타를 보낼때에 전송 데이타 사이즈를 미리 전송하고, 두 번째로 실제 데이타를 존송합니다.


서버에서는 전송된 데이타 사이즈를 미리 받아서 받을 버퍼 사이즈 크기를 결정하고, 받을 데이타가 모두 전송 될 때까지 루프를 돌면서 메모리 스트림에 기록을 한 후에, 화면에 보여줄 때에 한꺼번에 가져와서 화면에 보여 줍니다.


accept 소켓의 ReceiveBufferSize 속성 값이 65536 (int) 이니 일반적인 텍스트를 주고 받는 데에는 별무리가 없을 것으로 보이고, 단지 파일를 전송할때에는 영향을 받을 것으로 보입니다.


예제는 상당히 긴 텍스트를 전송하기는 것을 시나리오로 작성했습니다.


실행 후





메시지 전송 후







프로그램 작성 순서


1. 소켓/쓰레드과 관련한 네임스페이스를 서버/클라이언트 모두에 포함 시킵니다.

using System.Net;
using System.Net.Sockets;
using System.Threading;


2. 서버 프로그램

        Socket sck;
        Socket acc;

        public MainForm()
        {
            InitializeComponent();
        }

        private void btnListen_Click(object sender, EventArgs e)
        {
            sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            sck.Bind(new IPEndPoint(0, 8));
            sck.Listen(0);

            acc = sck.Accept();

            sck.Close();

            new Thread(() =>
            {
                while(true)
                {
                    try
                    {
                        byte[] sizeBuf = new byte[4];

                        acc.Receive(sizeBuf, 0, sizeBuf.Length, 0);

                        int size = BitConverter.ToInt32(sizeBuf, 0);
                        MemoryStream ms = new MemoryStream();

                        while (size > 0)
                        {
                            byte[] buffer;
                            if (size < acc.ReceiveBufferSize)
                                buffer = new byte[size];
                            else
                                buffer = new byte[acc.ReceiveBufferSize];

                            int rec = acc.Receive(buffer, 0, buffer.Length, 0);

                            size -= rec;

                            ms.Write(buffer, 0, buffer.Length);
                        }

                        ms.Close();

                        byte[] data = ms.ToArray();

                        ms.Dispose();

                        Invoke((MethodInvoker)delegate
                        {
                            richTextBox1.Text = Encoding.UTF8.GetString(data);
                        });
                    }
                    catch
                    {
                        MessageBox.Show("서버: DISCONNECTION!");
                        acc.Close();
                        acc.Dispose();
                        break;
                    }
                }
                Application.Exit();
            }).Start();
        }
    }


3. 클라이언트 프로그램

        Socket sck;
        public MainForm()
        {
            InitializeComponent();
            FormClosing += new FormClosingEventHandler(MainForm_FormClosing);
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (sck.Connected)
                sck.Close();
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                sck.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8));
            }
            catch
            {
                MessageBox.Show("Unable to connect!");
            }
        }

        private void btnSendText_Click(object sender, EventArgs e)
        {
            byte[] data = Encoding.UTF8.GetBytes(richTextBox1.Text);

            sck.Send(BitConverter.GetBytes(data.Length), 0, 4, 0);
            sck.Send(data);
        }

posted by 따시쿵