프로그램 설명
이번 예제는 Binary Serialization / Deserialization 을 이용한 통신 방법을 설명합니다.
클래스에 property 로 5개 필드(Name, Subject, Grade, Memo, SendTime)를 정의 합니다. SendTime 필드는 전송하는 클라이언트의 전송 시각을 기입하고, 서버에서 메시지를 받아서 네트워크 지연 시간을 확인 해 보기 위한 용도로 추가 했습니다. 또한 탭컨트롤을 추가해서 [Log], [Message] 화면을 구분했습니다.
3개의 프로젝트가 필요합니다.
1. 공통 라이브러리
==> 클라이언트와 서버에서 사용할 클래스
==> 클래스 이름 위에 [Serializable] 특성을 기입하는 게 중요함.
==> DataPacket.cs
2. 클라이언트 프로그램
3. 서버 프로그램
실행 후
메시지 전송 후
프로그램 작성 순서
1. 공통 라이브러리 (Common Libray)
클라이언트와 서버에서 사용할 어셈블리 코드
1 2 3 4 5 6 7 8 9 | [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. 서버 프로그램
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | 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. 클라이언트 프로그램
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | 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; } |
'C# with TCP/IP' 카테고리의 다른 글
[Program C#] 라이브러리를 이용한 클라이언트-서버 소켓 (0) | 2015.02.25 |
---|---|
[Program C#]Client-Server Broadcast 예제 - 콘솔버전 (0) | 2015.02.09 |
[Program C#]Binary Serialization 을 이용한 소켓통신 - 콘솔버전 (0) | 2015.01.28 |
[Program C#]구조체를 이용한 소켓통신3 - 바이너리 포매터 방법 - 윈도우 버전 (0) | 2015.01.27 |
[Program C#]구조체를 이용한 소켓통신3 - 바이너리 포매터 방법 - 콘솔 버전 (0) | 2015.01.26 |