블로그 이미지
따시쿵

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

2015. 3. 6. 16:46 C# with TCP/IP
프로그램 설명

비동기로 접속을 하고 데이타를 주고 받는 방법중에 method 뒤에 SocketAsyncEventArgs class 를 이용하는 방법입니다.

실행 후



데이타 전송 후




프로그램 작성 순서


1. 서버 프로그램


        #region MainForm
        public MainForm()
        {
            InitializeComponent();
        }
        #endregion

        #region MainForm_Load
        private Socket m_ServerSocket;
        private List m_ClientSocket;
        private byte[] szData;

        private void MainForm_Load(object sender, EventArgs e)
        {
            m_ClientSocket = new List();

            m_ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 10000);
            m_ServerSocket.Bind(ipep);
            m_ServerSocket.Listen(20);

            SocketAsyncEventArgs args = new SocketAsyncEventArgs();
            args.Completed += new EventHandler(Accept_Completed);
            m_ServerSocket.AcceptAsync(args);
        }
        #endregion

        #region Accept_Completed
        private void Accept_Completed(object sender, SocketAsyncEventArgs e)
        {
            Socket ClientSocket = e.AcceptSocket;
            m_ClientSocket.Add(ClientSocket);

            //접속한 클라이언수 보이기
            label1.Text = m_ClientSocket.Count.ToString();

            try
            { 
                if (m_ClientSocket != null)
                {
                    SocketAsyncEventArgs args = new SocketAsyncEventArgs();

                    szData = new byte[1024];
                    args.SetBuffer(szData, 0, szData.Length);
                    args.UserToken = m_ClientSocket;
                    args.Completed += new EventHandler(Receive_Completed);
                    ClientSocket.ReceiveAsync(args);
                }

                e.AcceptSocket = null;
                m_ServerSocket.AcceptAsync(e);
             }
            catch(SocketException se)
            {
                Trace.WriteLine(string.Format("SocketException : {0}", se.Message));
            }
            catch (Exception ex)
            {
                Trace.WriteLine(string.Format("Exception : {0}", ex.Message));
            }
        }
        #endregion

        #region Receive_Completed
        private void Receive_Completed(object sender, SocketAsyncEventArgs e)
        {
            Socket ClientSocket = sender as Socket;

            if (ClientSocket.Connected && e.BytesTransferred > 0)
            {
                byte[] szData = e.Buffer;
                string sData = Encoding.Unicode.GetString(szData);

                sData = sData.Replace("\0", "").Trim();
                SetText(sData);
                e.SetBuffer(szData, 0, 1024);
                ClientSocket.ReceiveAsync(e);
            }
            else
            {
                ClientSocket.Disconnect(false);
                ClientSocket.Dispose();
                m_ClientSocket.Remove(ClientSocket);
            }

            //접속한 클라이언수 보이기
            label1.Text = m_ClientSocket.Count.ToString();
        }
        #endregion

        #region SetText
        private delegate void SetTextCallback(string text);
        private void SetText(string text)
        {
            if (richTextBox1.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                if (richTextBox1.TextLength > 0)
                {
                    richTextBox1.AppendText("\n");
                }

                richTextBox1.AppendText(text);
                richTextBox1.ScrollToCaret();
            }
        }
        #endregion

        #region Dispose
        protected override void Dispose(bool disposing)
        {
            foreach(Socket pBuffer in m_ClientSocket)
            {
                if (pBuffer.Connected)
                    pBuffer.Disconnect(false);
                pBuffer.Dispose();
            }
            m_ServerSocket.Dispose();

            if (disposing && components != null)
                components.Dispose();

            base.Dispose(disposing);
        }
        #endregion


2. 클라이언트 프로그램


        #region MainForm
        public MainForm()
        {
            InitializeComponent();
        }
        #endregion

        private Socket m_ClientSocket = null;

        #region MainForm_Load
        private void MainForm_Load(object sender, EventArgs e)
        {
            m_ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint remoteIP = new IPEndPoint(IPAddress.Parse("192.168.0.12"), 10000);

            SocketAsyncEventArgs args = new SocketAsyncEventArgs();
            args.RemoteEndPoint = remoteIP;

            m_ClientSocket.ConnectAsync(args);
        }
        #endregion

        #region button1_Click method
        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text.Length > 0)
            {
                SocketAsyncEventArgs args = new SocketAsyncEventArgs();
                byte[] szData = Encoding.Unicode.GetBytes(textBox1.Text);

                args.SetBuffer(szData, 0, szData.Length);
                m_ClientSocket.SendAsync(args);

                textBox1.Text = "";
                textBox1.Focus();
            }
        }
        #endregion

        #region Dispose
        protected override void Dispose(bool disposing)
        {
            if (m_ClientSocket.Connected)
                m_ClientSocket.Disconnect(false);
            m_ClientSocket.Dispose();

            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #endregion

posted by 따시쿵
2015. 2. 25. 15:11 C# with TCP/IP
프로그램 설명


codeproject 의 소켓 라이브러리를 이용한 예제를 만들었습니다.


라이브러리에 대한 자세한 설명은 http://www.codeproject.com/Articles/563627/A-full-library-for-a-Socket-Client-Server-system 를 참고하시면 되고, 기본 라이브러리에서 몇가지 수정한 부분이 있습니다.



서버의 기능 


1. 접속자 리스트 관리 - 각 개인별로 메시지를 전송할 수 있음 

   ==> 사용자 이름에 마우스 오른쪽 버튼을 클릭하면 [메시지 전송하기] contextmenu 가 있으며, 

         이것을 이용해서 개별적으로 메시지를 전송할 수 있음


2. [모두에게] 기능을 추가 해서 전체 참석자에게 일괄적으로 메시지를 전송할 수 있음.


3. log4net 라이브러리를 이용해서 폴더에 날짜별로 로그를 쌓을 수 있음


3. log 탭과 message 탭을 따로 두어서, 서버의 작동 상태나 클라이언트의 연결/비연결 상태는 log 탭에

  실시간으로 보여주고, 클라이언트와의 메시지 확인은 message 탭에서 확인이 가능함



클라이언트 기능


1. [Launch clients...] 기능을 두어서 multiple 접속이 가능하게 구현해 두었으며, 서버의 상태를 확인

   가능함


2. 일반 메시지와 비밀글 기능을 두었음



실행 후






메시지 전송 후






프로그램 작성


codeproject 에서 다운을 받으면 실제적인 라이브러리 프로젝트는 AsyncClientServerLib, BaseClientServerLib, SocketServerLib 3개 입니다.


나머지는 테스트용도 입니다.


여기에 올린 프로그램은 Custom_ClientSock, Custom_ServerSocket 두 개입니다.

테스트 용도라면 아이피 부분만 각자의 환경에 맞게 수정하시면 됩니다.





SocketServer_V4.zip





posted by 따시쿵
2015. 2. 9. 12:10 C# with TCP/IP

프로그램 설명


이번 예제는 연결된 클라이언트, 모두에게 메시지를 전송하는 코드입니다.

서버는 접속 커넥션을 기달렸다가 클라이언트가 접속을 하게 되면 각 접속은 새로운 쓰레드가 담당을 관리합니다.


서버는 모든 연결된 클라이언트를 array list 로 관리를 합니다.


클라이언트가 메시지를 서버에게 전달을 하게 되면, 쓰레드가 본인 클라이언트만 제외하고 모든 접속 된 클라이언트에게 메시지를 전달합니다.



실행 후




메시진 전송 후





프로그램 작성 순서


1. 공통 라이브러리


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


2. 서버 프로그램


    class Program
    {
        private static TcpListener server;
        private static List<tcpclient> clientList = new List<tcpclient>();

        static void Main(string[] args)
        {
            server = new TcpListener(IPAddress.Any, 12340);
            server.Start();

            Console.WriteLine("server started\n");
            Console.WriteLine("waiting for a client");

            while(true)
            {                
                TcpClient client = server.AcceptTcpClient();
                clientList.Add(client);

                Thread t_handler = new Thread(new ParameterizedThreadStart(ClientListener));
                t_handler.Start(client);

                // 디버깅 용
                Debug.WriteLine("Thread count = {0}", Process.GetCurrentProcess().Threads.Count);
            }            
        }

        static void ClientListener(object sender)
        {
            TcpClient client = null;
            StreamReader sr = null;

            try
            {
                client = sender as TcpClient;
                sr = new StreamReader(client.GetStream());

                Console.WriteLine("New Client connected\n");

                while (true)
                {
                    string message = sr.ReadLine();
                    if (!string.IsNullOrEmpty(message))
                    { 
                        BroadCast(message, client);
                        Console.WriteLine("received data : {0}\n", message);
                    }
                }
            }
            catch (SocketException se)
            {
                Console.WriteLine("SocketException : {0}\n", se.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception : {0}\n", ex.Message);
            }
            finally
            {
                Console.WriteLine("client disconnected\n");
                clientList.Remove(client);

                sr.Close();
                client.Close();

                Thread.CurrentThread.Abort();
            }
        }

        static void BroadCast(string message, TcpClient excludeClient)
        {
            foreach(TcpClient client in clientList)
            {
                if (client != excludeClient)
                { 
                    StreamWriter sw = new StreamWriter(client.GetStream());
                    sw.WriteLine(message);
                    sw.Flush();
                }
            }
        }
    }


3. 클라이언트 프로그램


        static void Main(string[] args)
        {
            TcpClient client = null;
            StreamWriter sw = null;

            try
            { 
                client = new TcpClient("192.168.0.12", 12340);
                Console.WriteLine("Connected to server.\n");

                Thread c_thread = new Thread(new ParameterizedThreadStart(Client_Read));
                c_thread.Start(client);

                sw = new StreamWriter(client.GetStream());

                while(true)
                {
                    if (client.Connected)
                    {
                        Console.Write("send data : ");
                        string input = Console.ReadLine();
                        sw.WriteLine(input);
                        sw.Flush();
                    }
                    else
                        break;
                }
            }
            catch (SocketException se)
            {
                Console.WriteLine("SocketException : {0}", se.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception : {0}", ex.Message);
            }
            finally
            {
                sw.Close();
                client.Close();
            }

            Console.WriteLine("Press the ENTER key to continue...");
            Console.ReadLine();
        }

        static void Client_Read(object sender)
        {
            TcpClient client = sender as TcpClient;
            StreamReader sr = new StreamReader(client.GetStream());

            try
            {
                while(true)
                {
                    string message = sr.ReadLine();
                    if (!string.IsNullOrEmpty(message))
                        Console.WriteLine("\nreceived data : {0}\n", message);
                }
            }
            catch(SocketException se)
            {
                Console.WriteLine("SocketException : {0}\n", se.Message);
            }
            catch(Exception ex)
            {
                Console.WriteLine("Exception : {0}\n", ex.Message);
            }
            finally
            {
                sr.Close();
                client.Close();
            }
        }


posted by 따시쿵
2015. 1. 31. 09:08 C# with TCP/IP

프로그램 설명


이번 예제는 Binary Serialization / Deserialization 을 이용한 통신 방법을 설명합니다.


클래스에 property 로 5개 필드(Name, Subject, Grade, Memo, SendTime)를 정의 합니다. SendTime 필드는 전송하는 클라이언트의 전송 시각을 기입하고, 서버에서 메시지를 받아서 네트워크 지연 시간을 확인 해 보기 위한 용도로 추가 했습니다. 또한 탭컨트롤을 추가해서 [Log], [Message] 화면을 구분했습니다.


3개의 프로젝트가 필요합니다.


1. 공통 라이브러리 

   ==> 클라이언트와 서버에서 사용할 클래스

   ==> 클래스 이름 위에 [Serializable] 특성을 기입하는 게 중요함.

   ==> DataPacket.cs



2. 클라이언트 프로그램


3. 서버 프로그램



실행 후


메시지 전송 후



프로그램 작성 순서


1. 공통 라이브러리 (Common Libray) 

클라이언트와 서버에서 사용할 어셈블리 코드


    [Serializable]
    public class DataPacket
    {
        public string Name { get; set; }
        public string Subject { get; set; }
        public Int32 Grade { get; set; }
        public string Memo { get; set; }
        public DateTime SendTime { get; set; }
    }

 


2. 서버 프로그램


    public partial class MainForm : Form
    {
        TcpListener server = null;
        public MainForm()
        {
            InitializeComponent();
            FormClosing += new FormClosingEventHandler(WindowsFormClosing);
            InitStart();

            // 탭 페이지 [message] 탭 활성화
            tabControl1.SelectTab("tabPage2");
        }

        private void WindowsFormClosing(object sender, FormClosingEventArgs s)
        {
            if (server != null)
                server = null;

            Application.Exit();
        }
        private void InitStart()
        {
            Thread socketworker = new Thread(new ThreadStart(socketThread));
            socketworker.IsBackground = true;
            socketworker.Start();
        }

        private void socketThread()
        {
            try
            {
                server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
                server.Start();
                updateStatusInfo(string.Format("[{0}] server start", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")));

                while (true)
                {
                    TcpClient client = server.AcceptTcpClient();
                    updateStatusInfo(string.Format("[{0}] new connected", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")));
                    Thread clientworker = new Thread(new ParameterizedThreadStart(clientThread));
                    clientworker.IsBackground = true;
                    clientworker.Start(client);
                }
            }
            catch (SocketException se)
            {
                Debug.WriteLine("SocketException : {0}", se.Message);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception : {0}", ex.Message);
            }
        }

        private void clientThread(object sender)
        {
            string Name = string.Empty;
            string Subject = string.Empty;
            Int32 Grade = 0;
            string Memo = string.Empty;
            DateTime SendTime;
            TimeSpan time = TimeSpan.Zero;

            // 1. 데이타 받기
            TcpClient client = sender as TcpClient;
            NetworkStream stream = client.GetStream();

            byte[] buffer = new byte[8092];
  
            if (client.GetStream().CanRead)
            {                
                IFormatter formatter = new BinaryFormatter();

                DataPacket packet = new DataPacket();
                packet = (DataPacket)formatter.Deserialize(stream);

                Name = packet.Name;
                Subject = packet.Subject;
                Grade = packet.Grade;
                Memo = packet.Memo;
                SendTime = packet.SendTime;

                time = DateTime.Now - SendTime;

                updateStatusInfo(string.Format("[{0}] data received", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")));
            }
            

            stream.Close();
            client.Close();

            updateStatusInfo(string.Format("[{0}] disconnted", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")));

            // 2. 데이타 표시하기
            Invoke((MethodInvoker)delegate
            {
                int count = listView1.Items.Count;
                count++;

                ListViewItem i = new ListViewItem();
                i.Text = count.ToString();
                i.SubItems.Add(Name);
                i.SubItems.Add(Subject);
                i.SubItems.Add(Grade.ToString());
                i.SubItems.Add(Memo);
                i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                i.SubItems.Add(string.Format("{0}.{1} seconds", time.Seconds.ToString(), time.Milliseconds.ToString()));
                listView1.Items.Add(i);

                listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
            });

            Debug.WriteLine("{0} : {1} : {2} : {3} : {4} : {5}", Name, Subject, Grade, Memo, time.Seconds.ToString(), time.Milliseconds.ToString());
            
        }

        private void updateStatusInfo(string content)
        {
            Action del = delegate()
            {
                listBox1.Items.Add(content);
            };
            Invoke(del);
        }

        private void btnDataClear_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("데이타를 모두 삭제 하시겠습니까?", "질문", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK)
            {
                listBox1.Items.Clear();
                listView1.Items.Clear();
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            updateStatusInfo(string.Format("[{0}] server stop", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")));
            Application.Exit();
        }
    }


2. 클라이언트 프로그램


        public MainForm()
        {
            InitializeComponent();

            // 마우스 in / out 이벤트 추가
            btnSend.MouseEnter += new EventHandler(btnSend_MouseEnter);
            btnSend.MouseLeave += new EventHandler(btnSend_MouseLeave);

            // 탭 페이지 [message] 탭 활성화
            tabControl1.SelectTab("tabPage2");
        }

        void btnSend_MouseEnter(object sender, EventArgs e)
        {
            btnSend.UseVisualStyleBackColor = false;
            btnSend.BackColor = Color.FromArgb(255, 255, 165, 00);  // 배경색을 오렌지 색으로 변경함...
            btnSend.ForeColor = Color.White;                        // 글자색을 흰색으로 변경함
        }

        void btnSend_MouseLeave(object sender, EventArgs e)
        {
            btnSend.UseVisualStyleBackColor = true;
            btnSend.BackColor = SystemColors.Control;               // 배경색을 시스템 기본색으로 변경함...
            btnSend.ForeColor = SystemColors.ControlText;           // 글자색을 시스템 기본색으로 변경함...
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            Thread socketworker = new Thread(new ThreadStart(socketThread));
            socketworker.IsBackground = true;
            socketworker.Start();
        }

        private void socketThread()
        {
            // 1. 데이타패킷 조합
            Debug.WriteLine("{0} : {1} : {2} : {3}", txtName.Text, txtSubject.Text, txtGrade.Text, txtMemo.Text);

            DataPacket packet = new DataPacket();

            packet.Name = txtName.Text;
            packet.Subject = txtSubject.Text;

            Int32 outNum;
            if (Int32.TryParse(txtGrade.Text, out outNum))
            {
                packet.Grade = Convert.ToInt32(txtGrade.Text);
            }
            else
            {
                packet.Grade = 0;
            }

            packet.Memo = txtMemo.Text;

            if (string.IsNullOrEmpty(packet.Name))
            {
                MessageBox.Show("[이 름]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtName.Focus();

                });
                return;
            }

            if (string.IsNullOrEmpty(packet.Subject))
            {
                MessageBox.Show("[과 목]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtSubject.Focus();

                });
                return;
            }

            if (packet.Grade == 0)
            {
                MessageBox.Show("[점 수]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtGrade.Focus();

                });
                return;
            }

            if (string.IsNullOrEmpty(packet.Memo))
            {
                packet.Memo = " ";
            }

            packet.SendTime = DateTime.Now;

            Debug.WriteLine("{0} : {1} : {2} : {3} : {4}",
                                        packet.Name, packet.Subject, packet.Grade, packet.Memo, packet.SendTime.ToString("yyyy-MM-dd HH:mm:ss.fff"));

            // 2. TcpClient 생성 및 설정
            TcpClient client = new TcpClient(txtServerIP.Text, Convert.ToInt32(txtServerPort.Text));
            NetworkStream stream = client.GetStream();
            updateStatusInfo(string.Format("[{0}] Connected", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")));

            // 3. 전송하기
            IFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, packet);

            updateStatusInfo(string.Format("[{0}] {1} bytes data sent", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), SizeOf(packet)));

            // 4. 스트림과 소켓 닫기
            stream.Close();
            client.Close();

            updateStatusInfo(string.Format("[{0}] Disconnected", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")));

            // 5. listview 에 추가하기
            Invoke((MethodInvoker)delegate
            {
                int count = listView1.Items.Count;
                count++;

                ListViewItem i = new ListViewItem();
                i.Text = count.ToString();
                i.SubItems.Add(txtName.Text);
                i.SubItems.Add(txtSubject.Text);
                i.SubItems.Add(txtGrade.Text);
                i.SubItems.Add(txtMemo.Text);
                i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                listView1.Items.Add(i);

                listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
            });
        }

        private void updateStatusInfo(string content)
        {
            Action del = delegate()
            {
                listBox1.Items.Add(content);
            };
            Invoke(del);
        }

        public static long SizeOf(object obj)
        {
            long size = 0;

            try
            {
                System.IO.MemoryStream stream = new System.IO.MemoryStream();
                BinaryFormatter objFormatter = new BinaryFormatter();
                objFormatter.Serialize(stream, obj);
                size = stream.Length;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception : {0}", ex.Message);
            }

            return size;
        }


posted by 따시쿵
2015. 1. 28. 17:05 C# with TCP/IP

프로그램 설명


이번 예제는 Binary Serialization / Deserialization 을 이용한 통신 방법을 설명합니다.


클래스에 property 로 5개 필드(Name, Subject, Grade, Memo, SendTime)를 정의 합니다. SendTime 필드는 전송하는 클라이언트의 전송 시각을 기입하고, 서버에서 메시지를 받아서 네트워크 지연 시간을 확인 해 보기 위한 용도로 추가 했습니다.


3개의 프로젝트가 필요합니다.


1. 공통 라이브러리 

   ==> 클라이언트와 서버에서 사용할 클래스

   ==> 클래스 이름 위에 [Serializable] 특성을 기입하는 게 중요함.

   ==> DataPacket.cs


2. 클라이언트 프로그램


3. 서버 프로그램



실행 후

메시지 전송 후



프로그램 작성 순서


1. 공통 라이브러리 (Common Libray) 

클라이언트와 서버에서 사용할 어셈블리 코드


    [Serializable]
    public class DataPacket
    {
        public string Name { get; set; }
        public string Subject { get; set; }
        public Int32 Grade { get; set; }
        public string Memo { get; set; }
        public DateTime SendTime { get; set; }
    }

 


2. 서버 프로그램


        static void Main(string[] args)
        {
            TcpListener server = null;
            try 
            { 
                server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
                server.Start();

                while (true)
                {
                    Console.WriteLine("Waiting for a connection.....");

                    TcpClient client = server.AcceptTcpClient();
                    Console.WriteLine("\nConnected!!");

                    if (client.GetStream().CanRead)
                    {
                        NetworkStream stream = client.GetStream();
                        IFormatter formatter = new BinaryFormatter();

                        DataPacket packet = new DataPacket();
                        packet = (DataPacket)formatter.Deserialize(stream);

                        string Name = packet.Name;
                        string Subject = packet.Subject;
                        Int32 Grade = packet.Grade;
                        string Memo = packet.Memo;
                        DateTime SendTime = packet.SendTime;

                        TimeSpan time = DateTime.Now - SendTime;
   
                        Console.WriteLine("이 름 : {0}", Name);
                        Console.WriteLine("과 목 : {0}", Subject);
                        Console.WriteLine("점 수 : {0}", Grade);
                        Console.WriteLine("메 모 : {0}", Memo);
                        Console.WriteLine("지연된 시간 : {0}.{1} seconds", time.Seconds.ToString(), time.Milliseconds.ToString());
                        Console.WriteLine("");
                        Console.WriteLine("===========================================");
                        Console.WriteLine("");
                        
                        stream.Close();
                        client.Close();
                    }
                }
            }
            catch (SocketException se)
            {
                Console.WriteLine("SocketException : {0}", se.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception : {0}", ex.Message);
            }
            finally
            {
                server.Stop();
            }
        }

 


3. 클라이언트 프로그램


        static void Main(string[] args)
        {
            try
            {
                string Name = string.Empty;
                string Subject = string.Empty;
                Int32 Grade = 0;
                string Memo = string.Empty;

                do
                {
                    // 1. 데이타 입력
                    Console.Write("이름 : ");
                    Name = Console.ReadLine();

                    Console.Write("과목 : ");
                    Subject = Console.ReadLine();

                    Console.Write("점수 : ");
                    string tmpGrage = Console.ReadLine();
                    if (tmpGrage != "")
                    {
                        int outGrade = 0;
                        if (Int32.TryParse(tmpGrage, out outGrade))
                            Grade = Convert.ToInt32(tmpGrage);
                        else
                            Grade = 0;
                    }
                    else
                        Grade = 0;

                    Console.Write("메모 : ");
                    Memo = Console.ReadLine();

                    if (string.IsNullOrEmpty(Name) || string.IsNullOrEmpty(Subject))
                        break;

                    // 2. 구조체 데이타를 바이트 배열로 변환
                    DataPacket packet = new DataPacket();
                    packet.Name = Name;
                    packet.Subject = Subject;
                    packet.Grade = Grade;
                    packet.Memo = Memo;
                    packet.SendTime = DateTime.Now;
                    Debug.WriteLine("{0} : {1} : {2} : {3} : {4}",
                                        packet.Name, packet.Subject, packet.Grade, packet.Memo, packet.SendTime.ToString("yyyy-MM-dd HH:mm:ss.fff"));

                    // 3. 데이타 전송
                    TcpClient client = new TcpClient("192.168.0.12", 13000);
                    Console.WriteLine("Connected...");

                    NetworkStream stream = client.GetStream();

                    IFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(stream, packet);

                    Console.WriteLine("{0} bytes data sent\n", SizeOf(packet));

                    // 4. 스트림과 소켓 닫기
                    stream.Close();
                    client.Close();
                } while (Name != "" && Subject != "");

            }
            catch (SocketException se)
            {
                Console.WriteLine("SocketException : {0} ", se.Message.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception : {0} ", ex.Message.ToString());
            }

            Console.WriteLine("press the ENTER to continue...");
            Console.ReadLine();
        }

        public static long SizeOf(object obj)
        {
            long size = 0;

            try
            {
                System.IO.MemoryStream stream = new System.IO.MemoryStream();
                BinaryFormatter objFormatter = new BinaryFormatter();
                objFormatter.Serialize(stream, obj);
                size = stream.Length;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception : {0}", ex.Message);
            }

            return size;
        }

 


posted by 따시쿵
2015. 1. 27. 07:39 C# with TCP/IP

닷넷 환경에서 구조체를 이용한 소켓 통신을 지원하기 위한 방법은 크게 두 가지로 나뉩니다.


★ 마샬링(Marshaling)을 이용한 구조체 사용.

★ 바이너리 포매터(Binary Formatter)의 사용.


이번에는 바이너리 포매터 기법을 이용한 구조체를 통신하기 위한 방법을 소개합니다.


프로그램 설명


클라이언트가 학생의 4가지 데이타(이름, 과목, 점수, 메모)를 서버로 전송한다고 가정하고 필요한 클래스는 아래와 같습니다.

DataPacket.cs

 

    [Serializable]
    struct DataPacket
    {
        public string Name;
        public string Subject;
        public int Grade;
        public string Memo;
    }


실행 후


메시지 전송 후



프로그램 작성 순서


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

using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.IO;


2. 서버 프로그램

        TcpListener server = null;
        public MainForm()
        {
            InitializeComponent();
            FormClosing += new FormClosingEventHandler(WindowsFormClosing);
            InitStart();
        }

        private void WindowsFormClosing(object sender, FormClosingEventArgs s)
        {
            if (server != null)
                server = null;

            Application.Exit();
        }
        private void InitStart()
        {
            Thread socketworker = new Thread(new ThreadStart(socketThread));
            socketworker.IsBackground = true;
            socketworker.Start();
        }

        private void socketThread()
        {
            try
            {
                server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
                server.Start();

                while (true)
                {
                    TcpClient client = server.AcceptTcpClient();
                    updateStatusInfo("Connected");
                    Thread clientworker = new Thread(new ParameterizedThreadStart(clientThread));
                    clientworker.IsBackground = true;
                    clientworker.Start(client);
                }
            }
            catch (SocketException se)
            {
                Debug.WriteLine("SocketException : {0}", se.Message);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception : {0}", ex.Message);
            }
        }

        private void clientThread(object sender)
        {
            // 1. 데이타 받기
            TcpClient client = sender as TcpClient;
            NetworkStream stream = client.GetStream();

            byte[] buffer = new byte[8092];
            DataPacket packet = new DataPacket();

            while (stream.Read(buffer, 0, buffer.Length) != 0)
            {
                // deserializing; 
                packet = GetBindAck(buffer);
            }

            stream.Close();
            client.Close();

            // 2. 데이타 표시하기
            string Name = packet.Name;
            string Subject = packet.Subject;
            Int32 Grade = packet.Grade;
            string Memo = packet.Memo;

            Debug.WriteLine("{0} : {1} : {2} : {3}", Name, Subject, Grade, Memo);

            Invoke((MethodInvoker)delegate
            {
                int count = listView1.Items.Count;
                count++;

                ListViewItem i = new ListViewItem();
                i.Text = count.ToString();
                i.SubItems.Add(Name);
                i.SubItems.Add(Subject);
                i.SubItems.Add(Grade.ToString());
                i.SubItems.Add(Memo);
                i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                listView1.Items.Add(i);

                listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
            });


            // 3. 상태값 표시하기
            updateStatusInfo("Data Accepted");
        }

        private void updateStatusInfo(string content)
        {
            Action del = delegate()
            {
                lblStatus.Text = content;
            };
            Invoke(del);
        }

        private void btnDataClear_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("데이타를 모두 삭제 하시겠습니까?", "질문", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK)
            {
                listView1.Items.Clear();
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private DataPacket GetBindAck(byte[] btfuffer)
        {
            DataPacket packet = new DataPacket();

            MemoryStream ms = new MemoryStream(btfuffer, false);
            BinaryReader br = new BinaryReader(ms);

            packet.Name = ExtendedTrim(Encoding.UTF8.GetString(br.ReadBytes(20)));
            packet.Subject = ExtendedTrim(Encoding.UTF8.GetString(br.ReadBytes(20)));
            packet.Grade = IPAddress.NetworkToHostOrder(br.ReadInt32());
            packet.Memo = ExtendedTrim(Encoding.UTF8.GetString(br.ReadBytes(100)));

            br.Close();
            ms.Close();

            return packet;
        }

        // 문자열 뒤쪽에 위치한 null 을 제거한 후에 공백문자를 제거한다.
        private string ExtendedTrim(string source)
        {
            string dest = source;
            int index = dest.IndexOf('\0');
            if (index > -1)
            {
                dest = source.Substring(0, index + 1);
            }

            return dest.TrimEnd('\0').Trim();
        }


3. 클라이언트 프로그램


        public MainForm()
        {
            InitializeComponent();

            btnSend.MouseEnter += new EventHandler(btnSend_MouseEnter);
            btnSend.MouseLeave += new EventHandler(btnSend_MouseLeave);
        }

        void btnSend_MouseEnter(object sender, EventArgs e)
        {
            btnSend.UseVisualStyleBackColor = false;
            btnSend.BackColor = Color.FromArgb(255, 255, 165, 00);  // 배경색을 오렌지 색으로 변경함...
            btnSend.ForeColor = Color.White;                        // 글자색을 흰색으로 변경함
        }

        void btnSend_MouseLeave(object sender, EventArgs e)
        {
            btnSend.UseVisualStyleBackColor = true;
            btnSend.BackColor = SystemColors.Control;               // 배경색을 시스템 기본색으로 변경함...
            btnSend.ForeColor = SystemColors.ControlText;           // 글자색을 시스템 기본색으로 변경함...
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            Thread socketworker = new Thread(new ThreadStart(socketThread));
            socketworker.IsBackground = true;
            socketworker.Start();
        }

        private void socketThread()
        {
            // 1. 데이타패킷 조합
            Debug.WriteLine("{0} : {1} : {2} : {3}", txtName.Text, txtSubject.Text, txtGrade.Text, txtMemo.Text);

            DataPacket packet = new DataPacket();

            packet.Name = txtName.Text;
            packet.Subject = txtSubject.Text;

            Int32 outNum;
            if (Int32.TryParse(txtGrade.Text, out outNum))
            {
                packet.Grade = Convert.ToInt32(txtGrade.Text);
            }
            else
            {
                packet.Grade = 0;
            }

            packet.Memo = txtMemo.Text;

            if (string.IsNullOrEmpty(packet.Name))
            {
                MessageBox.Show("[이 름]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtName.Focus();

                });
                return;
            }

            if (string.IsNullOrEmpty(packet.Subject))
            {
                MessageBox.Show("[과 목]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtSubject.Focus();

                });
                return;
            }

            if (packet.Grade == 0)
            {
                MessageBox.Show("[점 수]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtGrade.Focus();

                });
                return;
            }

            if (string.IsNullOrEmpty(packet.Memo))
            {
                packet.Memo = " ";
            }

            // 2. TcpClient 생성 및 설정
            TcpClient client = new TcpClient(txtServerIP.Text, Convert.ToInt32(txtServerPort.Text));
            NetworkStream stream = client.GetStream();
            updateStatusInfo("Connected");

            // 3. 전송하기
            byte[] buffer = GetBytes_Bind(packet);

            stream.Write(buffer, 0, buffer.Length);
            updateStatusInfo(string.Format("{0} data sent", buffer.Length));

            // 4. 스트림과 소켓 닫기
            stream.Close();
            client.Close();

            // 5. listview 에 추가하기
            Invoke((MethodInvoker)delegate
            {
                int count = listView1.Items.Count;
                count++;

                ListViewItem i = new ListViewItem();
                i.Text = count.ToString();
                i.SubItems.Add(txtName.Text);
                i.SubItems.Add(txtSubject.Text);
                i.SubItems.Add(txtGrade.Text);
                i.SubItems.Add(txtMemo.Text);
                i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                listView1.Items.Add(i);

                listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
            });
        }

        private void updateStatusInfo(string content)
        {
            Action del = delegate()
            {
                lblStatus.Text = content;
            };
            Invoke(del);
        }

        // 패킷 사이즈 
        private const int BODY_BIND_SIZE = 20 + 20 + 4 + 100;

        // 인증 패킷 구조체를 바이트 배열로 변환하는 함수
        private byte[] GetBytes_Bind(DataPacket packet)
        {
            byte[] btBuffer = new byte[BODY_BIND_SIZE];

            MemoryStream ms = new MemoryStream(btBuffer, true);
            BinaryWriter bw = new BinaryWriter(ms);

            // Name - string
            try
            {
                byte[] btName = new byte[20];
                Encoding.UTF8.GetBytes(packet.Name, 0, packet.Name.Length, btName, 0);
                bw.Write(btName);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error : {0}", ex.Message.ToString());
            }

            // Subject - string
            try
            {
                byte[] btName = new byte[20];
                Encoding.UTF8.GetBytes(packet.Subject, 0, packet.Subject.Length, btName, 0);
                bw.Write(btName);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error : {0}", ex.Message.ToString());
            }

            // Grade - long
            bw.Write(IPAddress.HostToNetworkOrder(packet.Grade));

            // Memo - string
            try
            {
                byte[] btName = new byte[100];
                Encoding.UTF8.GetBytes(packet.Memo, 0, packet.Memo.Length, btName, 0);
                bw.Write(btName);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error : {0}", ex.Message.ToString());
            }

            bw.Close();
            ms.Close();

            return btBuffer;
        }


posted by 따시쿵
2015. 1. 26. 17:50 C# with TCP/IP

닷넷 환경에서 구조체를 이용한 소켓 통신을 지원하기 위한 방법은 크게 두 가지로 나뉩니다.


★ 마샬링(Marshaling)을 이용한 구조체 사용.

★ 바이너리 포매터(Binary Formatter)의 사용.


이번에는 바이너리 포매터 기법을 이용한 구조체를 통신하기 위한 방법을 소개합니다.


프로그램 설명


클라이언트가 학생의 4가지 데이타(이름, 과목, 점수, 메모)를 서버로 전송한다고 가정하고 필요한 클래스는 아래와 같습니다.

DataPacket.cs

    [Serializable]
    struct DataPacket
    {
        public string Name;
        public string Subject;
        public int Grade;
        public string Memo;
    }


실행 후


메시지 전송 후


프로그램 작성 순서


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

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


2. 서버 프로그램

        static void Main(string[] args)
        {
            TcpListener server = null;
            try
            {
                server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
                server.Start();

                byte[] buffer = new byte[256];

                while(true)
                {
                    Console.WriteLine("Waiting for a connection.....");

                    TcpClient client = server.AcceptTcpClient();
                    Console.WriteLine("\nConnected!!");

                    NetworkStream stream = client.GetStream();                    

                    while(stream.Read(buffer, 0, buffer.Length) != 0)
                    {
                        DataPacket packet = GetBindAck(buffer);

                        string Name = packet.Name;
                        string Subject = packet.Subject;
                        Int32 Grade = packet.Grade;
                        string Memo = packet.Memo;

                        Console.WriteLine("이 름 : {0}", Name);
                        Console.WriteLine("과 목 : {0}", Subject);
                        Console.WriteLine("점 수 : {0}", Grade);
                        Console.WriteLine("메 모 : {0}", Memo);
                        Console.WriteLine("");
                        Console.WriteLine("===========================================");
                        Console.WriteLine("");
                    }

                    stream.Close();
                    client.Close();
                }
            }
            catch(SocketException se)
            {
                Console.WriteLine("SocketException : {0}", se.Message);
            }
            catch(Exception ex)
            {
                Console.WriteLine("Exception : {0}", ex.Message);
            }
        }

        private static DataPacket GetBindAck(byte[] btfuffer)
        {
            DataPacket packet = new DataPacket();

            MemoryStream ms = new MemoryStream(btfuffer, false);
            BinaryReader br = new BinaryReader(ms);
                        
            packet.Name = ExtendedTrim(Encoding.UTF8.GetString(br.ReadBytes(20)));
            packet.Subject = ExtendedTrim(Encoding.UTF8.GetString(br.ReadBytes(20)));
            packet.Grade = IPAddress.NetworkToHostOrder(br.ReadInt32());
            packet.Memo = ExtendedTrim(Encoding.UTF8.GetString(br.ReadBytes(100)));

            br.Close();
            ms.Close();

            return packet;
        }

        // 문자열 뒤쪽에 위치한 null 을 제거한 후에 공백문자를 제거한다.
        private static string ExtendedTrim(string source)
        {
            string dest = source;
            int index = dest.IndexOf('\0');
            if (index > -1)
            {
                dest = source.Substring(0, index + 1);
            }

            return dest.TrimEnd('\0').Trim();
        }


3. 클라이언트 프로그램


        static void Main(string[] args)
        {
            try
            {
                string Name = string.Empty;
                string Subject = string.Empty;
                Int32 Grade = 0;
                string Memo = string.Empty;

                do
                {
                    // 1. 데이타 입력
                    Console.Write("이름 : ");
                    Name = Console.ReadLine();

                    Console.Write("과목 : ");
                    Subject = Console.ReadLine();

                    Console.Write("점수 : ");
                    string tmpGrage = Console.ReadLine();
                    if (tmpGrage != "")
                    {
                        int outGrade = 0;
                        if (Int32.TryParse(tmpGrage, out outGrade))
                            Grade = Convert.ToInt32(tmpGrage);
                        else
                            Grade = 0;
                    }
                    else
                        Grade = 0;

                    Console.Write("메모 : ");
                    Memo = Console.ReadLine();

                    if (string.IsNullOrEmpty(Name) || string.IsNullOrEmpty(Subject))
                        break;

                    // 2. 구조체 데이타를 바이트 배열로 변환
                    DataPacket packet = new DataPacket();
                    packet.Name = Name;
                    packet.Subject = Subject;
                    packet.Grade = Grade;
                    packet.Memo = Memo;

                    byte[] buffer = GetBytes_Bind(packet);

                    // 3. 데이타 전송
                    TcpClient client = new TcpClient();
                    client.Connect("192.168.0.12", 13000);
                    Console.WriteLine("Connected...");

                    NetworkStream stream = client.GetStream();

                    stream.Write(buffer, 0, buffer.Length);
                    Console.WriteLine("{0} data sent\n", buffer.Length);

                    stream.Close();
                    client.Close();
                } while (Name != "" && Subject != "");
            }
            catch (SocketException se)
            {
                Console.WriteLine("SocketException : {0} ", se.Message.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception : {0} ", ex.Message.ToString());
            }

            Console.WriteLine("press the ENTER to continue...");
            Console.ReadLine();
        }


        // 패킷 사이즈 
        public const int BODY_BIND_SIZE = 20 + 20 + 4 + 100;

        // 인증 패킷 구조체를 바이트 배열로 변환하는 함수
        public static byte[] GetBytes_Bind(DataPacket packet)
        {
            byte[] btBuffer = new byte[BODY_BIND_SIZE];

            MemoryStream ms = new MemoryStream(btBuffer, true);
            BinaryWriter bw = new BinaryWriter(ms);

            // Name - string
            try
            {
                byte[] btName = new byte[20];
                Encoding.UTF8.GetBytes(packet.Name, 0, packet.Name.Length, btName, 0);
                bw.Write(btName);
            }
            catch(Exception ex)
            {
                Console.WriteLine("Error : {0}", ex.Message.ToString());
            }

            // Subject - string
            try
            {
                byte[] btName = new byte[20];
                Encoding.UTF8.GetBytes(packet.Subject, 0, packet.Subject.Length, btName, 0);
                bw.Write(btName);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error : {0}", ex.Message.ToString());
            }

            // Grade - long
            bw.Write(IPAddress.HostToNetworkOrder(packet.Grade));

            // Memo - string
            try
            {
                byte[] btName = new byte[100];
                Encoding.UTF8.GetBytes(packet.Memo, 0, packet.Memo.Length, btName, 0);
                bw.Write(btName);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error : {0}", ex.Message.ToString());
            }

            bw.Close();
            ms.Close();

            return btBuffer;
        }


posted by 따시쿵
2015. 1. 22. 11:23 C# with TCP/IP

닷넷 환경에서 구조체를 이용한 소켓 통신을 지원하기 위한 방법은 크게 두 가지로 나뉩니다.


★ 마샬링(Marshaling)을 이용한 구조체 사용.

★ 바이너리 포매터(Binary Formatter)의 사용.


이번에는 마샬링 기법을 이용한 구조체를 통신하기 위한 방법을 소개합니다.


프로그램 설명


클라이언트가 학생의 4가지 데이타(이름, 과목, 점수, 메모)를 서버로 전송한다고 가정하고 필요한 클래스는 아래와 같습니다. 메소드 Serialize(), Deserialize(ref byte[] data) 가 구조체에서 배열로, 배열에서 구조체로 변경해 주는 기능을 담당하고 있습니다.

DataPacket.cs

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    struct DataPacket
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string Name;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string Subject;

        [MarshalAs(UnmanagedType.I4)]
        public int Grade;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
        public string Memo;

        // Calling this method will return a byte array with the contents
        // of the struct ready to be sent via the tcp socket.
        public byte[] Serialize()
        {
            // allocate a byte array for the struct data
            var buffer = new byte[Marshal.SizeOf(typeof(DataPacket))];

            // Allocate a GCHandle and get the array pointer
            var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            var pBuffer = gch.AddrOfPinnedObject();

            // copy data from struct to array and unpin the gc pointer
            Marshal.StructureToPtr(this, pBuffer, false);
            gch.Free();

            return buffer;
        }

        // this method will deserialize a byte array into the struct.
        public void Deserialize(ref byte[] data)
        {
            var gch = GCHandle.Alloc(data, GCHandleType.Pinned);
            this = (DataPacket)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(DataPacket));
            gch.Free();
        }
    }


실행 후



메시지 전송 후



프로그램 작성 순서


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

using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;


2. 서버 프로그램


    public partial class MainForm : Form
    {
        TcpListener server = null;
        public MainForm()
        {
            InitializeComponent();
            FormClosing += new FormClosingEventHandler(WindowsFormClosing);
            InitStart();
        }

        private void WindowsFormClosing(object sender, FormClosingEventArgs s)
        {
            if (server != null)
                server = null;

            Application.Exit();
        }
        private void InitStart()
        {
            Thread socketworker = new Thread(new ThreadStart(socketThread));
            socketworker.IsBackground = true;
            socketworker.Start();
        }

        private void socketThread()
        {
            try
            {
                server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
                server.Start();

                while (true)
                {
                    TcpClient client = server.AcceptTcpClient();
                    updateStatusInfo("Connected");
                    Thread clientworker = new Thread(new ParameterizedThreadStart(clientThread));
                    clientworker.IsBackground = true;
                    clientworker.Start(client);
                }
            }
            catch (SocketException se)
            {
                Debug.WriteLine("SocketException : {0}", se.Message);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception : {0}", ex.Message);
            }
        }

        private void clientThread(object sender)
        {
            // 1. 데이타 받기
            TcpClient client = sender as TcpClient;
            NetworkStream stream = client.GetStream();
            
            byte[] buffer = new byte[8092];
            DataPacket packet = new DataPacket();

            while (stream.Read(buffer, 0, buffer.Length) != 0)
            {
                // deserializing;                
                packet.Deserialize(ref buffer);
            }

            stream.Close();
            client.Close();

            // 2. 데이타 표시하기
            string Name = packet.Name;
            string Subject = packet.Subject;
            Int32 Grade = packet.Grade;
            string Memo = packet.Memo;

            Debug.WriteLine("{0} : {1} : {2} : {3}", Name, Subject, Grade, Memo);

            Invoke((MethodInvoker)delegate
            {
                int count = listView1.Items.Count;
                count++;

                ListViewItem i = new ListViewItem();
                i.Text = count.ToString();
                i.SubItems.Add(Name);
                i.SubItems.Add(Subject);
                i.SubItems.Add(Grade.ToString());
                i.SubItems.Add(Memo);
                i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                listView1.Items.Add(i);

                listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
            });

            
            // 3. 상태값 표시하기
            updateStatusInfo("Data Accepted");
        }

        private void updateStatusInfo(string content)
        {
            Action del = delegate()
            {
                lblStatus.Text = content;
            };
            Invoke(del);
        }

        private void btnDataClear_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("데이타를 모두 삭제 하시겠습니까?", "질문", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK)
            {
                listView1.Items.Clear();
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }


3. 클라이언트 프로그램


        public MainForm()
        {
            InitializeComponent();

            btnSend.MouseEnter += new EventHandler(btnSend_MouseEnter);
            btnSend.MouseLeave += new EventHandler(btnSend_MouseLeave);
        }

        void btnSend_MouseEnter(object sender, EventArgs e)
        {
            btnSend.UseVisualStyleBackColor = false;
            btnSend.BackColor = Color.FromArgb(255, 255, 165, 00);  // 배경색을 오렌지 색으로 변경함...
            btnSend.ForeColor = Color.White;                        // 글자색을 흰색으로 변경함
        }

        void btnSend_MouseLeave(object sender, EventArgs e)
        {
            btnSend.UseVisualStyleBackColor = true;
            btnSend.BackColor = SystemColors.Control;               // 배경색을 시스템 기본색으로 변경함...
            btnSend.ForeColor = SystemColors.ControlText;           // 글자색을 시스템 기본색으로 변경함...
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            Thread socketworker = new Thread(new ThreadStart(socketThread));
            socketworker.IsBackground = true;
            socketworker.Start();
        }

        private void socketThread()
        {
            // 1. 데이타패킷 조합
            Debug.WriteLine("{0} : {1} : {2} : {3}", txtName.Text, txtSubject.Text, txtGrade.Text, txtMemo.Text);

            DataPacket packet = new DataPacket();

            packet.Name = txtName.Text;
            packet.Subject = txtSubject.Text;

            Int32 outNum;
            if (Int32.TryParse(txtGrade.Text, out outNum))
            {
                packet.Grade = Convert.ToInt32(txtGrade.Text);
            }
            else
            {
                packet.Grade = 0;
            }

            packet.Memo = txtMemo.Text;

            if (string.IsNullOrEmpty(packet.Name))
            {
                MessageBox.Show("[이 름]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtName.Focus();

                });
                return;
            }

            if (string.IsNullOrEmpty(packet.Subject))
            {
                MessageBox.Show("[과 목]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtSubject.Focus();

                });
                return;
            }

            if (packet.Grade == 0)
            {
                MessageBox.Show("[점 수]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtGrade.Focus();

                });
                return;
            }

            if (string.IsNullOrEmpty(packet.Memo))
            {
                packet.Memo = " ";
            }

            // 2. TcpClient 생성 및 설정
            TcpClient client = new TcpClient(txtServerIP.Text, Convert.ToInt32(txtServerPort.Text));
            NetworkStream stream = client.GetStream();
            updateStatusInfo("Connected");

            // 3. 전송하기
            byte[] buffer = packet.Serialize();

            stream.Write(buffer, 0, buffer.Length);
            updateStatusInfo(string.Format("{0} data sent", buffer.Length));

            // 4. 스트림과 소켓 닫기
            stream.Close();
            client.Close();

            // 5. listview 에 추가하기
            Invoke((MethodInvoker)delegate
            {
                int count = listView1.Items.Count;
                count++;

                ListViewItem i = new ListViewItem();
                i.Text = count.ToString();
                i.SubItems.Add(txtName.Text);
                i.SubItems.Add(txtSubject.Text);
                i.SubItems.Add(txtGrade.Text);
                i.SubItems.Add(txtMemo.Text);
                i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                listView1.Items.Add(i);

                listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
            });
        }

        private void updateStatusInfo(string content)
        {
            Action del = delegate()
            {
                lblStatus.Text = content;
            };
            Invoke(del);
        }

    }

posted by 따시쿵
2015. 1. 21. 16:37 C# with TCP/IP

닷넷 환경에서 구조체를 이용한 소켓 통신을 지원하기 위한 방법은 크게 두 가지로 나뉩니다.


★ 마샬링(Marshaling)을 이용한 구조체 사용.

★ 바이너리 포매터(Binary Formatter)의 사용.


이번에는 마샬링 기법을 이용한 구조체를 통신하기 위한 방법을 소개합니다.


프로그램 설명


클라이언트가 학생의 4가지 데이타(이름, 과목, 점수, 메모)를 서버로 전송한다고 가정하고 필요한 클래스는 아래와 같습니다. 메소드 Serialize(), Deserialize(ref byte[] data) 가 구조체에서 배열로, 배열에서 구조체로 변경해 주는 기능을 담당하고 있습니다.

DataPacket.cs


    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    struct DataPacket
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string Name;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string Subject;

        [MarshalAs(UnmanagedType.I4)]
        public int Grade;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
        public string Memo;

        // Calling this method will return a byte array with the contents
        // of the struct ready to be sent via the tcp socket.
        public byte[] Serialize()
        {
            // allocate a byte array for the struct data
            var buffer = new byte[Marshal.SizeOf(typeof(DataPacket))];

            // Allocate a GCHandle and get the array pointer
            var gch = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            var pBuffer = gch.AddrOfPinnedObject();

            // copy data from struct to array and unpin the gc pointer
            Marshal.StructureToPtr(this, pBuffer, false);
            gch.Free();

            return buffer;
        }

        // this method will deserialize a byte array into the struct.
        public void Deserialize(ref byte[] data)
        {
            var gch = GCHandle.Alloc(data, GCHandleType.Pinned);
            this = (DataPacket)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(DataPacket));
            gch.Free();
        }
    }


실행 후



메시지 전송 후



프로그램 작성 순서


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


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


2. 서버 프로그램


        static void Main(string[] args)
        {
            TcpListener server = null;

            try
            {
                server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
                server.Start();

                byte[] buffer = new byte[1024];
                
                while (true)
                {
                    Console.WriteLine("Waiting for a connection.....");

                    TcpClient client = server.AcceptTcpClient();
                    Console.WriteLine("\nConnected!!");

                    NetworkStream stream = client.GetStream();

                    while (stream.Read(buffer, 0, buffer.Length) != 0)
                    {
                        // deserializing;
                        DataPacket packet = new DataPacket();
                        packet.Deserialize(ref buffer);

                        string Name = packet.Name;
                        string Subject = packet.Subject;
                        Int32 Grade = packet.Grade;
                        string Memo = packet.Memo;
                        
                        Console.WriteLine("이 름 : {0}", Name);
                        Console.WriteLine("과 목 : {0}", Subject);
                        Console.WriteLine("점 수 : {0}", Grade);
                        Console.WriteLine("메 모 : {0}", Memo);
                        Console.WriteLine("");
                        Console.WriteLine("===========================================");
                        Console.WriteLine("");
                    }

                    stream.Close();
                    client.Close();
                }
            }
            catch (SocketException se)
            {
                Console.WriteLine(se.Message.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }

            Console.ReadLine();
        }


3. 클라이언트 프로그램


        static void Main(string[] args)
        {
            try 
            {
                string Name = string.Empty;
                string Subject = string.Empty;
                Int32 Grade = 0;
                string Memo = string.Empty;

                do
                {
                    // 1. 데이타 입력
                    Console.Write("이름 : ");
                    Name = Console.ReadLine();

                    Console.Write("과목 : ");
                    Subject = Console.ReadLine();

                    Console.Write("점수 : ");
                    string tmpGrage = Console.ReadLine();
                    if (tmpGrage != "")
                    {
                        int outGrade = 0;
                        if (Int32.TryParse(tmpGrage, out outGrade))
                            Grade = Convert.ToInt32(tmpGrage);
                        else
                            Grade = 0;
                    }
                    else
                        Grade = 0;

                    Console.Write("메모 : ");
                    Memo = Console.ReadLine();

                    if (string.IsNullOrEmpty(Name) || string.IsNullOrEmpty(Subject))
                        break;

                    // 2. 구조체 데이타를 바이트 배열로 변환
                    DataPacket packet = new DataPacket();
                    packet.Name = Name;
                    packet.Subject = Subject;
                    packet.Grade = Grade;
                    packet.Memo = Memo;

                    byte[] buffer = packet.Serialize();

                    // 3. 서버에 접속
                    TcpClient client = new TcpClient();
                    client.Connect("192.168.0.12", 13000);
                    Console.WriteLine("Connected...");

                    NetworkStream stream = client.GetStream();

                    // 4. 데이타 전송
                    stream.Write(buffer, 0, buffer.Length);
                    Console.WriteLine("{0} data sent", buffer.Length);
                    Console.WriteLine("===============================\n");

                    // 5. 스트림&소켓 닫기
                    stream.Close();
                    client.Close();

                } while (Name != "" && Subject != "");
            }
            catch (SocketException se)
            {
                Console.WriteLine("SocketException : {0} ", se.Message.ToString());
            }
            catch(Exception ex)
            {
                Console.WriteLine("Exception : {0} ", ex.Message.ToString());
            }
            Console.ReadLine();
        }

posted by 따시쿵
2015. 1. 20. 10:33 C# with TCP/IP

.닷넷 환경에서 구조체를 이용한 소켓 통신을 지원하기 위한 방법은 크게 두 가지로 나뉩니다.


★ 마샬링(Marshaling)을 이용한 구조체 사용.

★ 바이너리 포매터(Binary Formatter)의 사용.


이번에는 마샬링 기법을 이용한 구조체를 통신하기 위한 방법을 소개합니다.


프로그램 설명


클라이언트가 학생의 4가지 데이타(이름, 과목, 점수, 메모)를 서버로 전송한다고 가정하고 필요한 클래스는 아래와 같습니다.


클라스 파일은 DataPacket.cs 파일입니다.

DataPacket.cs


    class DataPacket
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string Name;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string Subject;

        [MarshalAs(UnmanagedType.I4)]
        public int Grade;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
        public string Memo;
    }


실행 후



메시지 전송 후



프로그램 작성 순서


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

using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;


2. 서버 프로그램


        TcpListener server = null;            
        public MainForm()
        {
            InitializeComponent();
            FormClosing += new FormClosingEventHandler(WindowsFormClosing);
            InitStart();
        }

        private void WindowsFormClosing(object sender, FormClosingEventArgs s)
        {
            if (server != null)
                server = null;

            Application.Exit();
        }
        private void InitStart()
        {
            Thread socketworker = new Thread(new ThreadStart(socketThread));
            socketworker.IsBackground = true;
            socketworker.Start();
        }

        private void socketThread()
        {
            try
            {
                server = new TcpListener(IPAddress.Parse("192.168.0.12"), 13000);
                server.Start();

                while(true)
                { 
                    TcpClient client = server.AcceptTcpClient();
                    updateStatusInfo("Connected");
                    Thread clientworker = new Thread(new ParameterizedThreadStart(clientThread));
                    clientworker.IsBackground = true;
                    clientworker.Start(client);
                }              

            }
            catch(SocketException se)
            {
                Debug.WriteLine("SocketException : {0}", se.Message);
            }
            catch(Exception ex)
            {
                Debug.WriteLine("Exception : {0}", ex.Message);
            }
        }

        private void clientThread(object sender)
        {
            // 1. 데이타 받기
            TcpClient client = sender as TcpClient;
            NetworkStream stream = client.GetStream();

            byte[] buffer = new byte[8092];
            DataPacket packet = new DataPacket();

            while (stream.Read(buffer, 0, Marshal.SizeOf(packet)) != 0)
            {
                unsafe
                {
                    fixed (byte* fixed_buffer = buffer)
                    {
                        Marshal.PtrToStructure((IntPtr)fixed_buffer, packet);
                    }
                }
            }

            stream.Close();
            client.Close();

            // 2. 데이타 표시하기
            string Name = packet.Name;
            string Subject = packet.Subject;
            Int32 Grade = packet.Grade;
            string Memo = packet.Memo;

            Debug.WriteLine("{0} : {1} : {2} : {3}", Name, Subject, Grade, Memo);

            Invoke((MethodInvoker)delegate
            {
                int count = listView1.Items.Count;
                count++;

                ListViewItem i = new ListViewItem();
                i.Text = count.ToString();
                i.SubItems.Add(Name);
                i.SubItems.Add(Subject);
                i.SubItems.Add(Grade.ToString());
                i.SubItems.Add(Memo);
                i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                listView1.Items.Add(i);

                listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
            });

            // 3. 상태값 표시하기
            updateStatusInfo("Data Accepted");
        }

        private void updateStatusInfo(string content)
        {
            Action del = delegate()
            {
                lblStatus.Text = content;
            };
            Invoke(del);
        }

        private void btnDataClear_Click(object sender, EventArgs e)
        {
            if(MessageBox.Show("데이타를 모두 삭제 하시겠습니까?","질문", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK)
            {
                listView1.Items.Clear();
            }
        }


3. 클라이언트 프로그램


        public MainForm()
        {
            InitializeComponent();

            btnSend.MouseEnter += new EventHandler(btnSend_MouseEnter);
            btnSend.MouseLeave += new EventHandler(btnSend_MouseLeave);
        }

        void btnSend_MouseEnter(object sender, EventArgs e)
        {
            btnSend.UseVisualStyleBackColor = false;
            btnSend.BackColor = Color.FromArgb(255, 255, 165, 00);  // 배경색을 오렌지 색으로 변경함...
            btnSend.ForeColor = Color.White;                        // 글자색을 흰색으로 변경함
        }

        void btnSend_MouseLeave(object sender, EventArgs e)
        {
            btnSend.UseVisualStyleBackColor = true;
            btnSend.BackColor = SystemColors.Control;               // 배경색을 시스템 기본색으로 변경함...
            btnSend.ForeColor = SystemColors.ControlText;           // 글자색을 시스템 기본색으로 변경함...
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            Thread socketworker = new Thread(new ThreadStart(socketThread));
            socketworker.IsBackground = true;
            socketworker.Start();
        }

        private void socketThread()
        {
            // 1. 데이타패킷 조합
            Debug.WriteLine("{0} : {1} : {2} : {3}", txtName.Text, txtSubject.Text, txtGrade.Text, txtMemo.Text);

            DataPacket packet = new DataPacket();

            packet.Name = txtName.Text;
            packet.Subject = txtSubject.Text;

            Int32 outNum;
            if(Int32.TryParse(txtGrade.Text, out outNum))
            {
                packet.Grade = Convert.ToInt32(txtGrade.Text);
            }
            else
            {
                packet.Grade = 0;
            }
            
            packet.Memo = txtMemo.Text;

            if (string.IsNullOrEmpty(packet.Name))
            {
                MessageBox.Show("[이 름]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtName.Focus();
                    
                });
                return;
            }

            if (string.IsNullOrEmpty(packet.Subject))
            {
                MessageBox.Show("[과 목]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtSubject.Focus();

                });
                return;
            }

            if (packet.Grade == 0)
            {
                MessageBox.Show("[점 수]을 입력하시기 바랍니다", "경고", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Invoke((MethodInvoker)delegate
                {
                    txtGrade.Focus();

                });
                return;
            }

            if (string.IsNullOrEmpty(packet.Memo))
            {
                packet.Memo = " ";
            }

            // 2. TcpClient 생성 및 설정
            TcpClient client = new TcpClient(txtServerIP.Text, Convert.ToInt32(txtServerPort.Text));
            NetworkStream stream = client.GetStream();
            updateStatusInfo("Connected");

            // 3. 전송하기
            byte[] buffer = new byte[Marshal.SizeOf(packet)];

            unsafe
            {
                fixed (byte* fixed_buffer = buffer)
                {
                    Marshal.StructureToPtr(packet, (IntPtr)fixed_buffer, false);
                }
            }

            stream.Write(buffer, 0, Marshal.SizeOf(packet));
            updateStatusInfo(string.Format("{0} data sent", Marshal.SizeOf(packet)));

            // 4. 스트림과 소켓 닫기
            stream.Close();
            client.Close();

            // 5. listview 에 추가하기
            Invoke((MethodInvoker)delegate
            {
                int count = listView1.Items.Count;
                count++;

                ListViewItem i = new ListViewItem();
                i.Text = count.ToString();
                i.SubItems.Add(txtName.Text);
                i.SubItems.Add(txtSubject.Text);
                i.SubItems.Add(txtGrade.Text);
                i.SubItems.Add(txtMemo.Text);
                i.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                listView1.Items.Add(i);

                listView1.Items[this.listView1.Items.Count - 1].EnsureVisible();
            });
        }

        private void updateStatusInfo(string content)
        {
            Action del = delegate()
            {
                lblStatus.Text = content;
            };
            Invoke(del);
        }

posted by 따시쿵
prev 1 2 3 4 5 6 next