public class SearchTextHighlightConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfoculture)
        {
            RichTextBox rtb = values[0] as RichTextBox;
            string message = values[1].ToString();
            long messageSN = 0; Int64.TryParse(values[2].ToString(), out messageSN);
            string searchedText = values[3].ToString();
            long matchedMessageSN = 0; Int64.TryParse(values[4].ToString(), outmatchedMessageSN);

            TextRange range = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd);
            range.Text = message;



            if (string.IsNullOrEmpty(searchedText))
            {
                rtb.BorderBrush = new SolidColorBrush();
                rtb.BorderThickness = new Thickness(0);
                DetectURLs(rtb, message);
                return rtb;
            }

            if(messageSN != 0 & matchedMessageSN != 0 && messageSN== matchedMessageSN)
            {
                rtb.BorderBrush = new SolidColorBrush(Colors.Red);
                rtb.BorderThickness = new Thickness(2);
            }
            else
            {
                rtb.BorderBrush = new SolidColorBrush();
                rtb.BorderThickness = new Thickness(0);
            }

            Regex reg = new Regex(searchedText, RegexOptions.Compiled | RegexOptions.IgnoreCase);

            var start = rtb.Document.ContentStart;
            while (start != null && start.CompareTo(rtb.Document.ContentEnd) < 0)
            {
                if (start.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
                {
                    DetectURLs(rtb, message);
                    var match = reg.Match(start.GetTextInRun(LogicalDirection.Forward));

                    var textrange = new TextRange(start.GetPositionAtOffset(match.Index,LogicalDirection.Forward), start.GetPositionAtOffset(match.Index + match.Length,LogicalDirection.Backward));
                    textrange.ApplyPropertyValue(TextElement.ForegroundProperty, newSolidColorBrush(Colors.White));
                    textrange.ApplyPropertyValue(TextElement.BackgroundProperty, newSolidColorBrush(Colors.Black));
                    textrange.ApplyPropertyValue(TextElement.FontWeightProperty,FontWeights.Bold);
                    start = textrange.End;
                }
                start = start.GetNextContextPosition(LogicalDirection.Forward);
            }


            return rtb;


           
        }

        private static readonly Regex UrlRegex = new Regex(@"(?#Protocol)(?:(?:ht|f)tp(?:s?)://|~/|/)?(?#Username:Password)(?:w+:w+@)?(?#Subdomains)(?:(?:[-w]+.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?#Port)(?::[d]{1,5})?(?#Directories)(?:(?:(?:/(?:[-w~!$+|.,=]|%[a-fd]{2})+)+|/)+|?|#)?(?#Query)(?:(?:?(?:[-w~!$+|.,*:]|%[a-fd{2}])+=(?:[-w~!$+|.,*:=]|%[a-fd]{2})*)(?:&amp;(?:[-w~!$+|.,*:]|%[a-fd{2}])+=(?:[-w~!$+|.,*:=]|%[a-fd]{2})*)*)*(?#Anchor)(?:#(?:[-w~!$+|.,*:=]|%[a-fd]{2})*)?");


        //단락 반복 및 하이퍼 링크 만들기
        public static void DetectURLs(RichTextBox rtb, string message)
        {
            string paragraphText = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd).Text;
            paragraphText = message;
            // Split the paragraph by words
            foreach (string word in paragraphText.Split(' ').ToList())
            {
                if (IsHyperlink(word))
                {
                    Uri uri = new Uri(word, UriKind.RelativeOrAbsolute);

                    if (!uri.IsAbsoluteUri)
                    {
                        // Prepend it with http
                        uri = new Uri(@"http://" + word, UriKind.Absolute);
                    }

                    if (uri != null)
                    {
                        var position = rtb.Document.ContentStart;

                        // 단락에서 단어 찾기
                        while (position != null)
                        {
                            Console.WriteLine("포지션 = "+ position.GetPointerContext(LogicalDirection.Forward));
                            Console.WriteLine("포지션2 = " + TextPointerContext.Text);
                            if (position.GetPointerContext(LogicalDirection.Forward) ==TextPointerContext.Text)
                            {
                                string textRun = position.GetTextInRun(LogicalDirection.Forward);

                                // "word"와 일치하는 모든 하위 문자열의 시작 인덱스 찾기.
                                int indexInRun = textRun.IndexOf(word);
                                if (indexInRun == 0)
                                {
                                    TextPointer start = position.GetPositionAtOffset(indexInRun);
                                    TextPointer end = start.GetPositionAtOffset(word.Length);
                                    var link = new Hyperlink(start, end)
                                    {
                                        NavigateUri = uri,

                                    };
                                    link.Click += Hyperlink_Click;
                                }
                            }

                            position = position.GetNextContextPosition(LogicalDirection.Forward);
                        }
                    }
                }
            }
        }

        //String가 유효한 URL인지 확인
        public static bool IsHyperlink(string word)
        {
            // First check to make sure the word has at least one of the characters we need to make a hyperlink
            if (word.IndexOfAny(@":./".ToCharArray()) != -1)
            {
                if (Uri.IsWellFormedUriString(word, UriKind.Absolute))
                {
                    // The string is an Absolute URI
                    return true;
                }
                else if (UrlRegex.IsMatch(word))
                {
                    Uri uri = new Uri(word, UriKind.RelativeOrAbsolute);

                    if (!uri.IsAbsoluteUri)
                    {
                        // rebuild it it with http to turn it into an Absolute URI
                        uri = new Uri(@"http://" + word, UriKind.Absolute);
                    }

                    if (uri.IsAbsoluteUri)
                    {
                        return true;
                    }
                }
                else
                {
                    Uri wordUri = new Uri(word);

                    // Check to see if URL is a network path
                    if (wordUri.IsUnc || wordUri.IsFile)
                    {
                        return true;
                    }
                }
            }

            return false;

        }


        public static void Hyperlink_Click(object sender, EventArgs e)
        {
            Process.Start((sender as Hyperlink).NavigateUri.AbsoluteUri);
        }



        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfoculture)
        {
            return null;
        }
    }

}


저작자 표시
신고

'프로그래밍 언어 > C#' 카테고리의 다른 글

URI 넣기  (0) 2017.03.28
[C#] WPF 란?  (0) 2017.03.22
WPF 의존 프로퍼티(dependency property)  (0) 2017.03.16
OpenGeo Suite 란 무엇입니까?  (0) 2017.02.24
C++ 프로그래밍  (0) 2017.02.23
객체 지향 프로그래밍  (0) 2017.02.20

WPF(Windows Presentation Foundation)란 닷넷 3.0과 함께 소개된 마이크로소프트의 UI, 미디어 및 문서가 통합된 강력한 Windows 스마트 클리이언트 사용자 환경을 만들기 위한 통합 프로그래밍 모델이다.


새로운 프레젠테이션 시스템이다.


마이크로소프트는 윈도우 출시와 더불어 몇 가지 프레젠테이션 시스템을 제공해 왔다. Window 1.0과 함께 Windows API를 제공했고 지금까지 많은 개발자들이 이용하고 있다. User.dll와 GDI.dll을 이용한 프로그래밍 모델로 오랜 시간 동안 Windows 프로그램잉의 근간이 되고 있다. 그 후 비주얼베이직의 출시와 더불어 좀 더 편안한 GUI 프로그래밍의 근간이 되고 있다. 그 후 비주얼베이직의 출시와 더불어 좀 더 편안한 GUI 프로그래밍 모델을 마이크로소프트는 제공했다. 하지만 기능면에서 다소 제한적이라는 아쉬움이 있었다.

닷넷과 더불어 GDI+라는 새로운 기능과 함께 Windows Forms라는 프레젠테이션 시스템이 소개되었다. 하지만 Windows Form은 GDI+와 User32.dll의 관리 코드의 한계를 벗어나지 못했다. GDI와 GDI+의 프로그래밍 모델은 매우 흡사해서 기존의 개발자들이 큰 혼란 없이 수용이 가능한 장점이 있었다. 닷넷 3.0과 함께 WPF라는 새로운 프레젠테이션  시스템을 마이크로소프트는 소개했다. 더 이상 GDI와 GDI+에 의존하지 않는 새로운 닷넷 기반의 프레젠테이션 시스템으로 시기적으로는 RIA가 주목받기 시작한 시점에 출시되었고 프레임워크의 모습을 갖추고 있다. GDI나 GDI+ 같은 API 수준의 모습을 하고 있지는 않다.


미디어, 문서, 어플리케이션 인터페이스를 통합할 수 있다.

WPF 이전의 시스템에서 미디어와 문서 인터페이스를 하나로 통합하는 것은 복잡하고 귀찮은 일 중의 하나 였다. 예를 들어 버튼의 표면에 동영상을 배치하거나 버튼을 3차원 공간에서 기울어져 보이게 하는 것 혹은 각종 문서 데이터를 사용자 인터페이스에 표시하고 원하는 형태의 인쇄를 지원하는 것은 많은 시간과 개발의 부하를 발생시켰다.

많은 개발자들은 이런 문제를 프레임워크로 개발해 재활용하거나 3rd party 컴포넌트를 구매해 해결해 온 것이 현실이다. 이런 상황에서 전체적인 개발 공정에서 일관성이 결여되고 사후 관리에 많은 문제점을 드러내 왔다. 일관성 있고 통합된 프로그래밍 모델은 플랫폼으로 제공될 때 가장 효율적이며 이러한 요소구가 반영된 것이 WPF의 미디어, 문서, 인터페이스의 통합 모델이다. 하나의 인터페이스상에서 웹 문서, 멀티미디어 자료, 사용자 자신의 고유한 자료, 오피스 등의 기존형식을 가진 문서 등이 모두 표시되어야 한다. 또한 XML 혹은  업계 표준들과 호환되는 문서 모델도 요구되고 있다. WPF는 하나의 UI에서 XPS문서, Graphics, 비디오, 애니메이 등을 쉽게 표현할 수 있다. 개발자들이 더 이상의 고민 없이 WPF의 지원을 받아 다양한 데이터를 담을 수 있는 어플리케이션을 작성할 수 있다.


브라우저와 데스크톱에서 동시에 실행될 수 있는 프로그래밍 모델을 제공한다.

WPF 이전의 Window 클라이언트 환경에서는 SDI 혹은 MDI라는 문서 인터페이스를 지원했다. 단일 문서 혹은 다중 문서로 번역이 되는데 인터넷 시대 이전에 개발된 문서 인터페이스로 웹 브라우저 형태의 문서 인터페이스는 지원하지 않는다. 웹 브라우저 컨트롤 정도를 지원하지만 나머지문제는 고스란히 사용자의 몫이다. SDI에서는 문서가 각각 하나이므로 공유 데이터는 고려의 대상이 아니다. MDI에서는 하나의 부모뭄ㄴ서와 다수의 자식 문서들로 이루어지므로 부모 문서 기반의 데이터 공유 방법을 주로 사용한다. 웹 브라우저 컨트롤로 브라우징을 할 때 여러 페이지를 로딩해야 하는 다양한 탐색 모델을 지원할 수 있는 방법은 없다. 만약 지원을 원한다면 개발자가 구현해야한다. 인터넷 프로그램의 확산과 함께 많은 개발자와 사용자들이 브라우저 환경에 익숙해져 있고 브라우저 환경과 데스크톱 환경을 동시에 지원하는 개발 플랫폼이 필요하게 되었다. WPF는 두 플랫폼의 장점을 모두 지원하는 개발 플랫폼을 지원한다. 웹 프로그래밍 모델에서 세션, 탐색 등은 이미 익숙한 개념들이다. WPF에서는 이러한 기본적인 기능을 충분히 지원한다.



저작자 표시
신고

'프로그래밍 언어 > C#' 카테고리의 다른 글

URI 넣기  (0) 2017.03.28
[C#] WPF 란?  (0) 2017.03.22
WPF 의존 프로퍼티(dependency property)  (0) 2017.03.16
OpenGeo Suite 란 무엇입니까?  (0) 2017.02.24
C++ 프로그래밍  (0) 2017.02.23
객체 지향 프로그래밍  (0) 2017.02.20

소개


안녕하십니까, 며칠 전에 콘솔 응용 프로그램에서 모든 것을 관리하는 서버 / 클라이언트 응용 프로그램을 만들려고 생각했습니다. 10MB 미만의 메모리 만 사용할 수있었습니다. .NET Framework에서 객체를 처리하는 몇 가지 프로토콜로 해결할 수 있었고 문제의 해답은 System.Net 네임 스페이스 컬렉션이었습니다. 그러나 주로 우리는 System.Net.Sockets 네임 스페이스에 대해서 언급하고 그에 대해서 이야기 할 것 입니다. 이 네임 스페이스는 네이티브 TCP / IP 프로토콜을 사용하는 응용 프로그램을 작성하는 데 사용할 수있는 프로그래밍 개체를 제공하며 네트워킹 기능을 관리 할 수있는 응용 프로그램을 작성하는 데 사용할 수 있습니다. 응용 프로그램을 작성하여 소켓 ( 인터넷 소켓,

 

이 기사에서는 .NET Framework가 TCP 프로토콜 인 전송 제어 프로토콜을 사용하여 처리하는 TCP를 살펴 보겠습니다 . 이 기사의 끝 부분 에서 네이티브 .NET의 System.Net.Sockets 네임 스페이스에 웹 서비스 ( 또는 서버 / 클라이언트 응용 프로그램 모델이라고도 함 )를 작성할 수 있습니다. 이 네임 스페이스를 충분히 이해하면 WCF 프레임 워크가 더 이상 필요하지 않습니다. WCF는 동일한 프로토콜과 동일한 개체를 사용하지만 기본 스레드 및 프로세스 처리를 추상화하므로 수행 방법을 관리하는 대신 수행하려는 작업을 작성할 수 있습니다. 


전송 제어 프로토콜

전송 제어 프로토콜 자체에 대한 개요를 보자.이 프로토콜은 Wikipedia에서 명명 한 인터넷 프로토콜 집합의 일부이며 OSI 모델의 전송 계층에서 널리 사용되는 프로토콜이다. OSI 모델은 컴퓨터 네트워킹 및 컴퓨터가 네트워크를 사용하여 서로 통신하는 방법을 고안 한 매우 유명한 모델입니다. OSI 모델은 개발 된 표준 기반 모델로 컴퓨터에 적용됩니다. 여기에는 데이터가 처리되는 방식을 제어하는 ​​다음 7 개의 레이어가 포함됩니다.

물리 계층

데이터 계층

네트워크 계층

전송 층

세션 계층

프리젠 테이션 레이어

응용 프로그램 계층

이 레이어는 별도의 추상 환경에서 작동하며 다른 레이어와 간섭하지 않습니다. OSI 모델은 전송 된 데이터가 항상 반대쪽에서 수신되도록합니다. 이 기사에서는 소개로서 내가 전송 레이어에 대해서만 이야기 할 것이다. TCP 및 IP 두 프로토콜은 데이터가 실제받는 사람인받는 사람에게 문제없이 전송되도록합니다. 그러나 우리의 서버 / 클라이언트 응용 프로그램의 경우 IP 프로토콜 만 남겨두고 TCP 프로토콜에 대해서만 이야기 할 것입니다. 또한 IP 프로토콜 은 네트워크 계층 에서 작동 하지만 TCP 프로토콜  은 전송 계층 에서 작동합니다  . 

 

이 모든 계층은 네트워킹에서 다양한 기능을 관리하는 데있어 고유 한 작업을 수행합니다. 일반적으로 TCP 프로토콜은 IP 프로토콜과 함께 사용되어 안정적이고 체계적이며 순차적이며 오류가없는 데이터 전송을 보장합니다. TCP 프로토콜은 World Wide Web ( HTTP ), 파일 전송 ( FTP ) 및 기타 통신 모델 및 프로토콜에 이르는 다양한 일상적인 기능을 제공합니다. TCP 프로토콜의 몇 가지 핵심 정보는 다음과 같습니다.

연결 설정 및 종료


데이터 


전송 1. 안정적인 데이터 전송, 바이트 시퀀스 및 패킷 구조 관리. 

2. 오류 감지, 손실 된 패킷 재전송. 

3. 흐름 제어, 패킷이 안정적 으로 전송 될 수있는 속도를 예측합니다 .


수신 확인 및 기타 플래그.

다음 섹션에서는이 프로토콜을 사용하는 방법과 두 개의 샘플 프로젝트를 만드는 방법을 배웁니다. 하나는 서버 역할을하고 다른 하나는 클라이언트 역할을하는 것입니다. 그런 다음 클라이언트를 사용하여 서버에 요청을 보내면 서버는 요청과 함께 전송 된 데이터에 대해 작업을 수행하고 클라이언트에 응답을 반환합니다. 클라이언트는 서버가 보낸 메시지를 표시합니다. TCP는 다른 프로토콜과 마찬가지로 두 응용 프로그램 인 서버와 클라이언트 또는 네트워크를 통해 통신하는 다른 유사한 프로그램간에 네트워크 연결을 유지하는 데 사용되는 프로토콜입니다.


이 그림은 한 응용 프로그램이 다른 응용 프로그램과 데이터를 공유하는 방법을 설명합니다. 응용 프로그램 계층에서 프로토콜 기반의 데이터 인코딩 및 변환이 시작되면 전송 계층은 데이터, 바이트 순서 및 오류 제어를 관리하는 데 중요한 역할을하지만 물리 계층은 한 응용 프로그램에서 다른 응용 프로그램으로 전송되는 비트를 관리합니다 . 다른 끝에서 같은 일이 발생하지만 반대쪽에서는 비트가 패킷으로 변환되고 오류 검사가 실행되며 바이트가 정렬되어 데이터로 변환 될 수 있습니다. 그러면 데이터가 사용자와 공유됩니다. 그것이 네트워킹이 작동하는 방법입니다.

 

대신 레이어 이름 지정을 건너 뛰었습니다. 대신 응용 프로그램 레이어 (응용 프로그램, 프리젠 테이션 및 세션 레이어), 전송 레이어 (전송 레이어를 명확하게 설명해야하므로 TCP에 대해 토론해야하므로) 및 물리적 레이어 네트워크, 데이터 및 물리적 레이어). 항상 이들을 별도의 레이어로 간주해야합니다.  

 

Clint-server Model


클라이언트 - 서버 (또는 서버 / 클라이언트) 모델은 매우 오랜 기간 동안 개발 게임에있었습니다. 클라이언트 - 서버 응용 프로그램 모델은 프로그래머에게 두 가지 버전으로 프레임 워크를 구축 할 수있는 기회를 제공합니다. 한 응용 프로그램은 서버 역할을하지만 다른 응용 프로그램은 클라이언트 역할을합니다. 

서버


서버는 네트워크를 통해 연결된 장치에 리소스를 제공하는 응용 프로그램, 프로그램 또는 컴퓨터입니다.


클라이언트


클라이언트는 리소스를 얻기 위해 서버에 의존하는 응용 프로그램, 프로그램 및 컴퓨터입니다. 

이 모델에서 클라이언트는 동일한 컴퓨터 나 위치에있을 수도 있고있을 수도 있습니다. 클라이언트와 서버는 인터넷 연결 또는 리소스를 공유 할 수있는 다른 컴퓨터 네트워크를 통해 서로 통신합니다. 일반적으로 서버에는 프린터와 같은 하드웨어 자원이 사무실에 설치되어 있습니다. 또한 서버에는 비즈니스를 실행하는 데 필요한 소프트웨어 응용 프로그램이 있습니다. 클라이언트 응용 프로그램에서 데이터가 처리되고 응답이 생성되어 클라이언트로 다시 전송되는 서버로 보낼 수 있습니다. 

 

클라이언트 서버 모델의 작업


클라이언트 - 서버 모델은 매우 간단한 방식으로 동작하는 클라이언트 애플리케이션은 자원, 소프트웨어 애플리케이션 및 다른 하드웨어 컴포넌트를위한 서버에 의존하는 것이다. 별도의 다른 컨텍스트에있을 수도 있고 활동을 위해 동일한 서버에 설치할 수도 있습니다. 서버 응용 프로그램 (장치, 프로그램 또는 기계)은 하드웨어 자원, 소프트웨어 응용 프로그램 및 기타 비즈니스 데이터를 제어하며이를 사용하여 작업 할 수 있습니다. 클라이언트는 서버에 요청을 보내고 서버는 클라이언트의 추가 컨텐츠를 요구할 수도 있고하지 않을 수도 있습니다. 그것은 전적으로 서버와 클라이언트의 구성 방법에 달려 있습니다. 클라이언트가 서버에 연결되면 서버는 요청에 따라 서버를 작동시킵니다. 다양한 명령을 사용하여 서버에서 다양한 기능을 시작하고 트리거 할 수 있습니다. 서버가 클라이언트의 데이터 및 요청 작업을 완료하면 응답을 생성합니다. 응답은 클라이언트에 의해 표시되거나 표시되지 않을 수 있으며 서버는 응답을 보내거나 보내지 않고 연결 자체를 닫을 수 있습니다. 연결이 닫히면 다른 트래픽이 연결되어 데이터를 공유 할 수 있습니다.

 

일부 시각 효과에 대해서는이 과정의 데모를 만들었습니다.


이 이미지는 클라이언트와 서버가 서로 통신하는 방법을 보여줍니다. 서버에는 비즈니스 로직을 실행하는 데 사용되는 모든 스크립트 및 기타 자원에 대한 데이터 소스 및 소스 코드의 정의가 들어 있습니다.

 

이렇게하면 클라이언트와 서버가 분산 응용 프로그램 프레임 워크 역할을합니다. 사용자는 서버가있는 모든 위치에서 서버와 통신 할 수 있습니다.

 

클라이언트 - 서버 모델의 장점은


이제 클라이언트 - 서버 모델을 알고 있는지, 내가 (이 모델의 몇 가지 이점을 지적하자 내가 도움이 발견 ) 

전체 응용 프로그램 모델은 두 개의 서로 다른 프로젝트에 분산되어 있습니다. 데이터를 공유하는 각각의 방법과 각자가 네트워크의 데이터를 받아들이는 방식을 쉽게 구성 할 수 있습니다.


비즈니스 로직을 서버 응용 프로그램에 작성하고 여기에 함수를 실행할 수 있습니다. 의 드라이 규칙 유지하기 자신을 반복하지 마십시오 .


친구와 클라이언트 응용 프로그램을 공유하고 서버를 계속 실행할 수 있습니다. 서버를 실행하는 데 10MB 미만이 소요되며 작고 컴팩트 한 애플리케이션에 적합합니다. 원하는 경우 클라이언트의 여러 요청을 수락하는 비동기 프로그래밍과 같은 기능을 추가 할 수 있습니다.

 

다양한 응용 프로그램에서 플랫폼 간 데이터 공유. 

이러한 장점 외에도 클라이언트와 서버 기반의 로직을 서로 다른 두 가지 응용 프로그램에 배포하는 프레임 워크를 구축하는 데있어 다른 좋은 점이 있습니다. 원하는 경우 클라이언트를 청취하기 위해 서버를 가동하여 실행할 수 있습니다. 클라이언트 응용 프로그램을 실행할 필요가 없습니다. 

 

또한 서버가 클라이언트에 비해 더 많은 리소스를 가지고있는 응용 프로그램을 빌드 할 필요가 없음을 기억하십시오. 이는 완전히 잘못되었지만 대부분의 경우 앱이이를 염두에두고 제작되었습니다. 그러나 서버에는 더 많은 리소스가 필요하지 않습니다. 예를 들어 클라이언트 응용 프로그램에 비즈니스 논리를 모두 작성하고 유효성 검사를 실행 한 다음 데이터를 서버로 보내 파일 시스템에 데이터를 저장하기 만하면됩니다. 키를 누를 때마다 서버에 데이터를 보내고 데이터를 확인하고 다른 논리를 수행 할 필요가 없습니다. 많은 논리로 네트워크 트래픽도 많이 발생합니다.

 

.NET에서 클라이언트 - 서버 응용 프로그램 빌드 


.NET Framework에는 웹 서비스, Windows 통신 기반 을 만들기위한 매우 효율적이고 강력한 프레임 워크가 포함되어 있습니다. WCF를 사용하면 서버 응용 프로그램을 생성 할 수있는 응용 프로그램의 클라이언트 - 서버 모델을 만들 수 있습니다. 일반적으로 콘솔 프로젝트는 짧은 메모리 요구 사항과 효율성 때문에 WPF 또는 WinForms를 사용할 수 있기 때문에 WCF에서 서버 인스턴스를 만드는 데 사용됩니다. 또한 다양한 방법으로 클라이언트 응용 프로그램을 만들 수 있습니다. 

콘솔 응용 프로그램 


보다 간단한 클라이언트 응용 프로그램.


Windows Presentation Foundation (또는 Windows Forms) 


훨씬 복잡하고 GUI 지향적 인 응용 프로그램의 경우.


ASP.NET 웹 응용 프로그램 


인터넷에서 호스팅 할 수있는 응용 프로그램의 경우 클라이언트는 인터넷을 사용하여 응용 프로그램에 연결할 수 있습니다. 이 옵션을 사용하면 비 Windows 플랫폼 사용자는 .NET Framework가없는 Android 장치 등의 웹 서비스를 사용할 수 있습니다. 

이 외에도 .NET Framework는 .NET Framework에서 네트워크 지향 응용 프로그램을 만드는 데 사용할 수있는 네이티브 .NET 라이브러리 및 어셈블리를 제공합니다. System.Net의 네임 스페이스는 우리가 .NET 응용 프로그램에서 네트워크 및 프로토콜 주위에 작업하는 데 사용할 수있는 어셈블리와 함께 우리를 제공합니다. 이 네임 스페이스 아래에 많은 네임 스페이스가 있습니다. 이 기사에서 소개하거나 언급 한 네임 스페이스는 다음과 같습니다.

System.Net


.NET Framework의 네트워킹을위한 핵심 어셈블리입니다. 또한 샘플 프로젝트에서 사용됩니다.


System.Net.Mail


이 네임 스페이스는 전자 메일 보내기, SMTP 서버에 연결 및 기타 필요한 작업에 사용되는 개체를 보유합니다.


System.Net.Security


SSL 기반 스트림을 생성하는 데 필요한 객체를 제공합니다.


System.Net.Sockets


이 네임 스페이스는 TCP 또는 UDP 클라이언트의 개체 와 이러한 프로토콜을 기반으로 네트워크를 사용하여 작업하기위한 클라이언트 및 수신기를 보유 합니다. 

앞에서 설명한 네임 스페이스를 사용하고 서버 및 클라이언트 사용을위한 응용 프로그램을 만듭니다. 이 두 시나리오에서 우리는 콘솔 프로젝트를 사용하고 적절한 코드를 작성하여 서버 및 클라이언트 응용 프로그램을 유지 관리합니다. 

샘플 프로젝트

이 샘플에서는 클라이언트의 데이터를 받아들이는 샘플 프로젝트를 만들 것입니다. 클라이언트는 데이터를 JSON 형식으로 전송하여 클라이언트의 이름, 전자 메일 주소 및 메시지를 서버로 보냅니다. 서버 (이 예제의 경우)는 사람에게 전자 메일을 보냅니다 (전자 메일 주소 사용).

 

클라이언트는 사용자가 이름, 전자 메일 및 메시지를 묻습니다. 이 클라이언트 응용 프로그램을 네트워크의 모든 사용자와 공유 할 수 있습니다. 서버는 데이터를 수락하고 필요에 따라 응답합니다.  

서버 응용 프로그램 작성

서버 애플리케이션은 클라이언트의 새로운 요청을 수용하기 위해 호스트되어야합니다. 응용 프로그램을 호스팅하려면 응용 프로그램이 수신 대기 할 주소와 포트를 제공해야합니다. 우리는 TcpListener 객체를 사용하여 서버 인스턴스를 생성 할 수 있습니다 . 생성자에 대한 매개 변수로 서버의 호스팅 주소로 사용될 IP 주소 끝점을 전달합니다. 클라이언트는이 주소를 사용하여이 서버 응용 프로그램에 연결할 것이므로이 주소를 알아야합니다. 서버와 클라이언트의 역할을하기 위해 내 컴퓨터를 사용할 것이므로 루프백 주소 ( 127.0.0.1 )와 샘플 포트 번호 ( 1234 )를 사용하고 있습니다. 다른 IP 주소 또는 포트를 사용하여 자체 서버를 구성하고 네트워크의 클라이언트를 위해 서버에 대한 액세스를 제공 할 수 있습니다. 

IPEndPoint ep =  새  IPEndPoint (IPAddress.Loopback, 1234); // 주소  

TcpListener listener =  새  TcpListener (ep); // 객체 인스턴스화  

listener.Start (); // 듣기 시작 ...  

이 단계에서 서버가 가동되어 TCP 클라이언트의 새로운 요청을 수락 할 준비가됩니다. 네트워크는 바이트와 함께 작동하며 바이트 형식으로 데이터를 읽습니다. 바이트를 수락 한 후 데이터를 적절한 유형, 텍스트, 이미지 또는 오디오로 변환하기 위해 디코딩이 수행됩니다. 이 샘플에서는 텍스트 만 표시 할 수 있습니다. 다른 객체 (예 : File)를 사용하고 " image / jpeg "등 의 형식을 제공하는 바이트를 사용하여 데이터를 이미지 유형으로 변환 할 수 있습니다 . 

 

다음으로 클라이언트를 청취합니다. 클라이언트가 요청을 보낼 때까지는 진행할 수 없습니다. 데이터를 받아들이려면 클라이언트가 보낸 데이터를 저장할 메모리 위치가 있어야합니다. 또한 메시지의 문자열 표현도 저장해야합니다. 내가 어떻게했는지 아래를보십시오.

// 몇 개의 변수 만  

const int  bytesize = 1024 * 1024; // 상수, 나중에 변경하지 않을 것입니다.   

문자열  메시지 =  null ;  

byte [] buffer =  새 바이트 [bytesize];   

  

/ * 여기서 만 진행할 수 있습니다. 

 * 고객이 신청서를 요청할 경우. 

 * 요청을 받으면이 줄에서 진행해야합니다. * /  

var sender = listener.AcceptTcpClient ();   

  

// 네트워크에서 바이트를 읽습니다.  

sender.GetStream (). Read (buffer, 0, bytesize);  

앞의 코드는 서버가 새로운 요청을 수락하고 클라이언트가 보낸 데이터를 읽을 수있게합니다. 지금까지 우리는 서버에서 오는 새로운 요청을 시작, 실행 및 청취 할 수 있도록 응용 프로그램을 구성했습니다. 우리 서버는 현재 동기식이며 하나의 요청 만 수락 할 수 있으며 연결이 종료되지 않는 한 다른 요청을 수락하지 않습니다.


비동기 프로그래밍 모델을 사용하여 여러 클라이언트의 여러 요청을 수락 할 수 있습니다. 동기 모드에서는 여러 요청을 허용 할 수 없습니다. 하나의 요청으로 작업하고 요청을 완료하고 응답을 보내거나 연결을 종료 한 후 다음 요청이나 클라이언트로 이동할 수 있습니다. 

 

바이트 만 보내거나 받았다고 했으므로 다른 데이터 유형은 우리가 사용하는 멋진 항목입니다. 이제이 바이트를 설명 데이터로 변환해야합니다. 클라이언트가 문자열 데이터를 전송할 것이므로 문자열 형식으로 데이터를 디코딩 할 수 있습니다. 또한 버퍼 크기가 매우 커서 모든 데이터를 수용 할 수 있습니다. 원한다면 단축 할 수 있습니다 . 이 많은 바이트 데이터는 문자가없는 곳에서는 항상 널 문자를 포함합니다. 널 문자는 콘솔에 많은 공간을 필요로합니다. 문자열에 null 문자를 제거하기위한 함수를 작성했습니다. 

// 매개 변수로 바이트 배열 전달  

개인 정적 문자열  cleanMessage ( byte [] bytes)    

{  

    // 바이트에서 메시지 문자열 가져 오기  

    string  message = System.Text.Encoding.Unicode.GetString (bytes);  

  

    string  messageToPrint =  null ;  

    // 해당 메시지의 각 문자를 반복합니다.  

    foreach는  (var에 nullChar  의  메시지)  

    {  

        // null 문자가 아닌 문자 만 저장합니다.  

        if  (nullChar! =  '\ 0' )  

        {  

             messageToPrint + = nullChar;  

        }  

    }  

      

    // null 문자없이 메시지를 반환합니다.   

    return  messageToPrint;  

}  

우리는 서버와 클라이언트에서이 기능을 사용할 것입니다. 보내거나받은 메시지에서 Null 문자를 제거합니다. 이 외에도 서버의 다양한 기능을 처리하는 데 사용되는 또 다른 두 가지 기능이 있습니다. 하나는 응답을 생성하여 보내고, 다른 하나는 응답으로 사용자에게 전자 메일을 보냅니다. 

전자 메일 보내기

이 예에서 우리는 사용자에 대한 응답으로 전자 메일을 사용합니다. 우리는 우리에게 보낸 데이터를받은 사실을 알리기 위해 사용자에게 전자 메일을 보냅니다. .NET Framework에서 전자 메일을 보내는 방법에 대한 자세한 내용은이 모듈의 내용을 설명하지 않습니다 . 이 기사 를 읽으십시오 .  

// 또한 사용자에게 배달 사실을 알리는 전자 메일을 보냅니다.  

사용  (려면 SmtpClient 클라이언트 =  새로운  려면 SmtpClient ( "<당신의-SMTP 서버>" , 25))  

{  

       // 몇 가지 설정  

       client.EnableSsl =  true ;  

       client.Credentials =  new  NetworkCredential ( "<email>" ,   

                                         "<password>" );  

  

        클라이언트.  

                 새로운  MailMessage ( "<email-address>" , p.Email,  

                        "웹 서비스를 이용해 주셔서 감사합니다" ,  

                        문자열 .Format (  

    @ "  우리 웹 서비스, {0} 을 이용해 주셔서 감사합니다  .    

  

귀하의 메시지  '{1}'이 접수되었습니다. ", p.Name, p.Message  

                        )  

                 )  

         );  

}  

이 기능은이 메시지와 함께 이메일 주소로 고객에게 이메일을 보냅니다. 이 이메일 주소를 변경하거나 클라이언트가 통신 할 때 서버가 작동하는 방식을 변경할 수 있습니다. 

응답 보내기

모든 것이 끝나면 클라이언트에 보낼 응답을 생성 할 차례입니다. 마찬가지로, 응용 프로그램이 텍스트 또는 서버가 보낸 다른 데이터로 다시 변환 할 수 있도록 바이트를 클라이언트로 보냅니다. 

 

고객이 아직 연결되어있는 경우에만 고객에게 응답을 보낼 수 있습니다. 연결이 끊어지면 클라이언트에게 응답을 보낼 수 없습니다. 우리는 클라이언트를 연결 했으므로 데이터의 바이트를 변환하고 클라이언트로 스트리밍하기 위해 별도의 함수를 생성 할 수 있습니다.

// 제공된 바이트와 TCP 클라이언트를 사용하여 메시지 문자열을 보냅니다.  

개인 정적 무효  sendMessage ( 바이트 [] 바이트, TcpClient 클라이언트)    

{  

    // 클라이언트가 연결되어야합니다.   

    client.GetStream () // 스트림을 얻어  바이트를 씁니다.  

          .Write (바이트, 0,   

          bytes.Length); // 스트림을 보냅니다.  

}  

지금까지 우리는 메시지를 호스팅하고 수락하고 응답을 보낼 수있는 서버 응용 프로그램을 만들었으며 전자 메일 주소를 사용하여 사용자에게 알릴 수도 있습니다.

완벽한 서버 프로그램 

콘솔 프로젝트의 전체 서버 프로그램은 다음과 같습니다.

 시스템 사용 ;  

using  System.Collections.Generic;  

using  System.Linq;  

using  System.Text;  

using  System.Threading.Tasks;  

 System.Net.Sockets 사용 ;  

using  System.Net;  

사용  System.Net.Mail을;  

 Newtonsoft.Json을 사용하여 ;  

  

네임  스페이스 TcpServer  

{  

    수업  프로그램  

    {  

        static void  Main ( string [] args)   

        {  

            IPEndPoint ep =  새  IPEndPoint (IPAddress.Loopback, 1234);  

            TcpListener listener =  새  TcpListener (ep);  

            listener.Start ();  

  

            Console.WriteLine (@ "  

            ======================================================================================================================================================== =  

                   {0} : {1}에서 요청 듣기를 시작했습니다.  

            ======================================================================================================== = ",   

            ep.Address, ep.Port);  

  

            // 루프를 계속 실행합니다. 이것은 서버입니다.  

            while  ( true )  

            {  

                const int  bytesize = 1024 * 1024;   

  

                문자열  메시지 =  null ;  

                byte [] buffer =  새 바이트 [bytesize];   

  

                var sender = listener.AcceptTcpClient ();  

                sender.GetStream (). Read (buffer, 0, bytesize);  

  

                // 메시지를 읽고 다른 작업 수행  

                메시지 = cleanMessage (버퍼);  

  

                // 클라이언트가 보낸 데이터를 저장합니다.  

                사람 person = JsonConvert.DeserializeObject <사람> (메시지); // deserialize  

  

                byte [] bytes = System.Text.Encoding.Unicode.GetBytes ( "감사합니다."  + person.Name);  

                sender.GetStream (). Write (bytes, 0, bytes.Length); // 응답을 보냅니다.  

  

                sendEmail (사람);  

            }  

        }  

  

        개인 정적 무효  sendEmail (사람 p)    

        {  

            시험  

            {  

                // 또한 사용자에게 배달 사실을 알리는 전자 메일을 보냅니다.  

                사용  (려면 SmtpClient 클라이언트 =  새로운  려면 SmtpClient ( "<당신의-SMTP>" , 25))  

                {  

                    client.EnableSsl =  true ;  

                    client.Credentials =  new  NetworkCredential ( "<email>" , "<pass>" );  

  

                    클라이언트.  

                        새로운  MailMessage ( "<email-from>" , p.Email,  

                            "웹 서비스를 이용해 주셔서 감사합니다" ,  

                            문자열 .Format (  

    @ "  우리 웹 서비스, {0} 을 이용해 주셔서 감사합니다  .    

  

귀하의 메시지  '{1}'이 접수되었습니다. ", p.Name, p.Message  

                            )  

                        )  

                    );  

                }  

  

                Console.WriteLine ( "전자 메일은"  + p.Email "로 전송되었습니다. ); // 이메일이 성공적으로 전송되었습니다.  

            }  

            잡기  (예외 e)  

            {  

                Console.WriteLine (e.Message);  

            }  

        }  

  

        개인 정적 문자열  cleanMessage ( byte [] bytes)    

        {  

            string  message = System.Text.Encoding.Unicode.GetString (bytes);  

  

            string  messageToPrint =  null ;  

            foreach는  (var에 nullChar  의  메시지)  

            {  

                if  (nullChar! =  '\ 0' )  

                {  

                    messageToPrint + = nullChar;  

                }  

            }  

            return  messageToPrint;  

        }  

  

        // 제공된 바이트를 사용하여 메시지 문자열을 보냅니다.  

        개인 정적 무효  sendMessage ( 바이트 [] 바이트, TcpClient 클라이언트)    

        {  

            client.GetStream ()  

                .Write (바이트, 0,   

                bytes.Length); // 스트림을 보냅니다.  

        }  

    }  

  

    계급  사람  

    {  

        public string  Name {  get ; 세트 ; }   

        public string  Email {  get ; 세트 ; }   

        공용 문자열  Message {  get ; 세트 ; }   

    }  

}  

우리의 응용 프로그램은 한번 실행하면 다음과 같이 보입니다.

 

 

 

참고 : 대부분의 줄은 콘솔에서 멋진 텍스트입니다. 그들에게 필요한 분야를 고려하지 마십시오. 나는 클라이언트 애플리케이션에서 person 클래스를 설명 할 것이다. 또한 Newtonsoft.Json 라이브러리를 사용하여 JSON의 데이터를 객체로 변환했으며 잠시 후에 설명 할 것입니다. 계속 읽고! 

클라이언트 응용 프로그램 작성

이제 서버가 가동되어 이제는 클라이언트 역할을하는 응용 프로그램을 만들어야합니다. 클라이언트는 서버에 연결하여 데이터를 보내면 서버가 클라이언트 응용 프로그램에 응답을 보낼 때까지 기다립니다. 이 신청서에서는 고객에게 이름, 이메일 주소 및 메시지를 요청합니다. 그런 다음이 세부 정보를 Person 객체의 멤버로 제출 합니다. 사람의 사물이 서버에서 사용되며 적절한 기능이 실행됩니다. 

 

우리의 person 객체에는 다음과 같은 3 가지 멤버가 있습니다.

계급  사람  

{  

    public string  Name {  get ; 세트 ; }  // 이름   

    public string  Email {  get ; 세트 ; }  // 이메일 주소   

    공용 문자열  Message {  get ; 세트 ; }  // 일부 메시지 텍스트   

}  

우리는 서버에서이 객체를 사용할 것입니다. 이전에 설명하지 않았으므로 요청을 생성하기 위해이 멤버를 사용할 것이기 때문에 앞으로 할 것입니다. 우리의 응용 프로그램은 사용자의 이름, 전자 메일 주소 및 메시지가 있는지 묻습니다. 그런 다음 해당 메시지를 서버로 보내고 서버는 전자 메일을 응답으로 보냅니다.

// 사용자로부터 세부 정보를 가져와 저장합니다.  

사람 =  새로운  사람 ();  

  

Console.Write ( "이름 입력 :" );  

person.Name = Console.ReadLine ();  

Console.Write ( "귀하의 이메일 주소 입력 :" );  

person.Email = Console.ReadLine ();  

Console.Write ( "귀하의 메시지 입력 :" );  

person.Message = Console.ReadLine ();  

  

// 메시지를 보냅니다.  

byte [] bytes = sendMessage (System.Text.Encoding.Unicode.GetBytes (person.ToJSON ()));  

클라이언트에서는 서버에 메시지를 보내는 함수도 만들었습니다. 이 함수에서는 서버가 실행되고있는 주소와 포트를 사용하여 서버에 연결합니다. 그런 다음 데이터를 서버에 바이트 단위로 보냅니다. 서버는 동일한 기능의 요청에 응답합니다. 이것이 함수가 바이트 배열의 반환 유형을 갖는 이유입니다. 

개인 정적 바이트 [] sendMessage ( 바이트 [] messageBytes)    

{  

    const int  bytesize = 1024 * 1024;   

    try // 연결하여 메시지 바이트를 보내라.   

    {  

         System.Net.Sockets.TcpClient 클라이언트 =  새  System.Net.Sockets.TcpClient ( "127.0.0.1" , 1234); // 새 연결 만들기  

         NetworkStream stream = client.GetStream ();  

  

         stream.Write (messageBytes, 0, messageBytes.Length); // 바이트를 씁니다.  

         Console.WriteLine ( "============================" );  

         Console.WriteLine ( "= 서버에 연결 =" );  

         Console.WriteLine ( "============================" );  

         Console.WriteLine ( "응답 대기 중 ..." );  

  

         messageBytes =  새로운 바이트 [bytesize]; // 메시지 지우기    

  

         // 바이트 스트림을받습니다.  

         stream.Read (messageBytes, 0, messageBytes.Length);  

  

         // 정리  

         stream.Dispose ();  

         client.Close ();  

    }  

    catch  (Exception e)  // 예외 잡기  

    {  

        Console.WriteLine (e.Message);  

    }  

  

    return  messageBytes; // 응답을 반환합니다.  

}  

앞의 코드에서 클라이언트 응용 프로그램은 서버에 연결을 시도하고 제공된 데이터와 함께 서버에 요청을 보냅니다. 서버는 데이터를 읽고 작동 한 다음 바이트 형식으로 응답 문자열을 제공합니다. 우리는 이러한 바이트를 반환하므로 응용 프로그램에서 데이터를 정리하고 화면에 표시 할 수 있습니다. 또한 서버를 사용할 수 없으므로 try catch 블록 에서 사용해야합니다  . 응용 프로그램을 중단하는 대신 단순히 서버가 종료되었음을 표시하고 응용 프로그램을 닫아야합니다. 

 

신청서를 실행하면이 화면이 표시됩니다.

 

 

제출할 때 응용 프로그램은 연결하여 데이터를 서버로 보냅니다. 서버가 우리에게 제공 한 정보는이 프로그램에서 볼 수 없습니다. 대신 우리는 서버 응용 프로그램으로 이동하여 현재 진행중인 작업을 확인해야합니다.

 


응용 프로그램을 실행하는 동안 인터넷에 연결되어 있지 않았으므로 오류 메시지가 표시되었습니다. 연결시 두 번째 성공 메시지를받을 수있었습니다.  

 

이 코드 행 뒤에 서버는 클라이언트에 응답을 되돌려 보냅니다. 클라이언트 응용 프로그램은 사용자에게 콘솔 화면에 다음 메시지를 표시 할 수 있습니다.

 

 

 

그래서, 지금까지는 위대합니다. 서버 및 클라이언트 응용 프로그램이 현재 작업을 수행하고 있습니다.

가볼만한 곳 

이 기사에서는 네이티브 .NET Framework 라이브러리 및 어셈블리를 사용하여 웹 서비스 또는 서버 / 클라이언트 응용 프로그램을 만드는 방법을 설명했습니다. 중앙 집중식 서버 및 분산 클라이언트 응용 프로그램을 사용하는 다양한 유형의 프로젝트를 만들 수 있습니다.

 

보안을 위해, 당신은 항상 사용하는 것이 좋습니다  SslStream의 로부터 객체를 System.Net.Security의 네임 스페이스. 또한이 유형의 응용 프로그램 프레임 워크는 동기식입니다. 한 번에 하나의 클라이언트 만 연결할 수 있습니다. 다른 클라이언트가 연결해야하는 경우 추가 요청 및 프로세스를 위해 서버가 해제 될 때까지 대기합니다. async / await 연산자를 사용하여 현재 모델을 비동기 모델로 변환 할 수 있습니다. 또한 MSDN 갤러리에 소스 코드를 게시하여 다운로드하여 사용할 수 있습니다. 

 

처음에는 10MB의 RAM 소비량으로 실행되는 프로그램을 만들고 싶습니다.이 응용 프로그램 집합을 실행 한 후 (서버와 클라이언트 모두에서) 모두 5MB의 RAM 소비로 실행된다는 것을 알 수 있습니다. 나중에 업로드가 시작되고 이메일이 전송 될 때 메모리 벤치 마크가 10MB로 늘어날 수 있지만 여전히 찾고있는 것입니다. :)

 

 

 

TcpClient는 실행 중이며 사용자에게 입력을 요청하는 클라이언트 프로그램입니다. vshost32.exe (Visual Studio 사용 경험이있는 경우)는 TcpServer를 실행하기위한 디버거로 연결된 프로그램입니다. 

 

나는이 기사로 당신을 도왔기를 바랍니다. :) 앞으로이 프레임 워크 유형에 대해 더 많은 코드를 공유 할 것입니다.  

저작자 표시
신고

+ Recent posts