2014. 12. 26. 16:47
C# with TCP/IP
프로그램 설명
msdn 사이트에 있는 예제를 조금 수정해서 작성했습니다.
원본 소스는 아래와 같습니다.
비동기 서버 예제 : http://msdn.microsoft.com/ko-kr/library/bew39x2a(v=vs.110).aspx
비동기 클라이언트 예제 : http://msdn.microsoft.com/ko-kr/library/fx6588te(v=vs.110).aspx
비동기로 소켓을 실행하기 위해 ManualResetEvent 클래스를 사용해서 thread 간 통신을 하며, StateObject class 를 만들어서 받을 데이타를 정의하는 부분이 추가 되었으며, 비동기 호출 method 들(beginAccept, beginReceive, beginSend)을 호출합니다.
다른 부분들은 동기 서버/클라이언트의 추가 함수들을 같이 사용했습니다.(문자열 자르기, 로컬 아이피 가져오기)
초기에 실행하면 다른점이 보이는데 이 부분이 실제로 비동기 호출을 담당하는 부분이며 소켓을 통해서 데이타를 주고 받는 부분이 비동기로 구현되어 있습니다.
실행 후
메시지 전송 후
프로그램 작성 순서
1. 소켓/쓰레드과 관련한 네임스페이스를 서버/클라이언트 모두에 포함 시킵니다.
using System.Net; using System.Net.Sockets; using System.Threading;
2. 서버 프로그램
// State object for reading client data asynchronously public class StateObject { // Client socket public Socket workSocket = null; // Size of receive buffer public const int BufferSize = 1024; // Receive buffer public byte[] buffer = new byte[BufferSize]; // Received data string public StringBuilder sb = new StringBuilder(); } class Program { // Thread signal public static ManualResetEvent allDone = new ManualResetEvent(false); public static string TruncateLeft(string value, int maxLength) { if (string.IsNullOrEmpty(value)) return value; return value.Length <= maxLength ? value : value.Substring(0, maxLength); } // Get local IP public static string LocalIPAddress() { IPHostEntry host; string localIP = ""; host = Dns.GetHostEntry(Dns.GetHostName()); foreach (IPAddress ip in host.AddressList) { if (ip.AddressFamily == AddressFamily.InterNetwork) { localIP = ip.ToString(); return localIP; } } return "127.0.0.1"; } private static void StartListening() { // Data buffer for incoming data byte[] bytes = new byte[1024]; // Establish the local endpoint for the socket // running the listener is "192.168.0.12" 테스트 아이치 IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(LocalIPAddress()), 11000); // Create a TCP/IP socket Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Bind the socket to the local endpoint and listen for incoming connecions. try { listener.Bind(localEndPoint); listener.Listen(100); while(true) { // Set the event to nonsignaled state allDone.Reset(); // Start an asynchronous socket to listen for connections. Console.WriteLine("\nWaiting for a connections..."); listener.BeginAccept(new AsyncCallback(AcceptCallback) , listener); // Wait until a connection is made before running allDone.WaitOne(); } } catch (SocketException se) { Console.WriteLine("StartListening[SocketException] Error : {0} ", se.Message.ToString()); } catch (Exception ex) { Console.WriteLine("StartListening[Exception] Error : {0} ", ex.Message.ToString()); } Console.WriteLine("\nPress ENTER to continue.....\n"); Console.ReadLine(); } public static void AcceptCallback(IAsyncResult ar) { // Signal the main thread to continue. allDone.Set(); // Get the socket that handles the client socket Socket listener = (Socket)ar.AsyncState; Socket handler = listener.EndAccept(ar); // Create the socket object StateObject state = new StateObject(); state.workSocket = handler; handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); } public static void ReadCallback(IAsyncResult ar) { string content = string.Empty; // Retrieve the state object and the handler socket // from the asynchronous state object StateObject state = (StateObject)ar.AsyncState; Socket handler = state.workSocket; // Read data from the client socket int bytesRead = handler.EndReceive(ar); if (bytesRead > 0) { // There might be more data, so store the data received so far state.sb.Append(Encoding.UTF8.GetString(state.buffer, 0, bytesRead)); // Check for end-of-file tag. If it it not there, read more data content = state.sb.ToString(); if (content.IndexOf("<eof>") > -1) { // All the data has been read from the // client. DIsplay it on the console. content = TruncateLeft(content, content.Length - 5); Console.WriteLine("Read {0} bytes from socket \nData : {1}", content.Length, content); // Echo the data back to the client Send(handler, content); } else { // Not all data received. Get more handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0 , new AsyncCallback(ReadCallback), state); } } } private static void Send(Socket handler, string data) { // Convert the string data to bytes data using UTF8 encoding byte[] byteData = Encoding.UTF8.GetBytes(data); // Being sending the data to the remote device handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback) , handler); } private static void SendCallback(IAsyncResult ar) { try { // Retrieve the socket from the state object Socket handler = ar.AsyncState as Socket; // Complete sending the data to the remote device int bytesSent = handler.EndSend(ar); Console.WriteLine("Sent {0} bytes to client.", bytesSent); handler.Shutdown(SocketShutdown.Both); handler.Close(); } catch (SocketException se) { Console.WriteLine("SendCallback[SocketException] Error : {0} ", se.Message.ToString()); } catch (Exception ex) { Console.WriteLine("SendCallback[Exception] Error : {0} ", ex.Message.ToString()); } } static void Main(string[] args) { StartListening(); } }
3. 클라이언트 프로그램
#region State object define // State object for receiving data from reomte device public class StateObject { // Client socket public Socket workSocket = null; // Size of receive buffer public const int BufferSize = 256; // Receive buffer public byte[] buffer = new byte[BufferSize]; // Received data string public StringBuilder sb = new StringBuilder(); } #endregion class Program { // The port number for the remote device private const int port = 11000; // ManaulResetEvent instances signal completion private static ManualResetEvent connectDone = new ManualResetEvent(false); private static ManualResetEvent sendDone = new ManualResetEvent(false); private static ManualResetEvent receiveDone = new ManualResetEvent(false); // The response from the remote device private static String response = String.Empty; private static void StartClient() { // Connect to a remote device try { // Establish the remote endpoint for the socket // The name of // remote device 아이피 "192.168.0.12" : 테스트 목적 IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("192.168.0.12"), port); // Create a TCP/IP socket Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Connect to the remote endpoint client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client); connectDone.WaitOne(); // Send user input data to the remote device Console.Write("전송할 메시지를 입력해 주세요 : "); string sendData = Console.ReadLine() + "<eof>"; Send(client, sendData); sendDone.WaitOne(); // Receive the response from the remote device. Receive(client); receiveDone.WaitOne(); // Write the response to the console Console.WriteLine("Response received : {0}", response); // Release the socket client.Shutdown(SocketShutdown.Both); client.Close(); } catch (SocketException se) { Console.WriteLine("StartClient SocketException Error : {0} ", se.Message.ToString()); } catch (Exception ex) { Console.WriteLine("StartClient Exception Error : {0} ", ex.Message.ToString()); } } private static void ConnectCallback(IAsyncResult ar) { try { // Retrieve the socket from the state object Socket client = (Socket)ar.AsyncState; // Complete the connection client.EndConnect(ar); Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString()); // Signal that the connection has been made connectDone.Set(); } catch (SocketException se) { Console.WriteLine("ConnectCallback SocketException Error : {0} ", se.Message.ToString()); } catch(Exception ex) { Console.WriteLine("ConnectCallback Exception Error : {0} ", ex.Message.ToString()); } } private static void Receive(Socket client) { try { // Create the state object StateObject state = new StateObject(); state.workSocket = client; // Begin receiving the data from the remote device client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); } catch (SocketException se) { Console.WriteLine("Receive SocketException Error : {0} ", se.Message.ToString()); } catch (Exception ex) { Console.WriteLine("Receive Exception Error : {0} ", ex.Message.ToString()); } } private static void ReceiveCallback(IAsyncResult ar) { try { // Retrieve the state object and the client socket // from the asynchronous state object StateObject state = (StateObject)ar.AsyncState; Socket client = state.workSocket; // Read data from the remote device int bytesRead = client.EndReceive(ar); if (bytesRead > 0) { // There might be more data, so store the data received so far state.sb.Append(Encoding.UTF8.GetString(state.buffer, 0, bytesRead)); // Get the rest of the data client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); } else { // All the data has arrived; put it in response if (state.sb.Length > 1) response = state.sb.ToString(); // Signal that all bytes have been received. receiveDone.Set(); } } catch (SocketException se) { Console.WriteLine("ReceiveCallback SocketException Error : {0} ", se.Message.ToString()); } catch (Exception ex) { Console.WriteLine("ReceiveCallback Exception Error : {0} ", ex.Message.ToString()); } } private static void Send(Socket client, string data) { // Convert the string data to byte data using UTF8 encoding byte[] byteData = Encoding.UTF8.GetBytes(data); // Being sending the data to the remote device client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), client); } private static void SendCallback(IAsyncResult ar) { try { // Retrieve the socket from the state object Socket client = ar.AsyncState as Socket; // Complete sending the data to the remote device int bytesSent = client.EndSend(ar); Console.WriteLine("Sent {0} bytes to server", bytesSent); // Signal that all bytes have been sent sendDone.Set(); } catch (SocketException se) { Console.WriteLine("SendCallback SocketException Error : {0} ", se.Message.ToString()); } catch (Exception ex) { Console.WriteLine("SendCallback Exception Error : {0} ", ex.Message.ToString()); } } static void Main(string[] args) { StartClient(); Console.ReadLine(); } }
'C# with TCP/IP' 카테고리의 다른 글
[Program C#]Socket 통신 - Multiple Connection/Accepting Connections (0) | 2015.01.03 |
---|---|
[Program C#]비동기 서버/클라이언트 msdn 예제 - 윈도우 버전 (3) | 2015.01.02 |
[Program C#]동기 서버/클라이언트 msdn 예제 - 윈도우 버전 (0) | 2014.12.23 |
[Program C#]동기 서버/클라이언트 msdn 예제 - 콘솔 버전 (0) | 2014.12.23 |
[Program C#]Socket 통신 - 버퍼 사이즈보다 많은 양의 데이타를 받을 시 (0) | 2014.12.23 |