Windows Forms 프로그래밍
방법: 스레드로부터 안전한 방식으로 Windows Forms 컨트롤 호출

Windows Forms 응용 프로그램의 성능 향상을 위해 다중 스레딩을 사용할 경우 스레드로부터 안전한 방식으로 컨트롤을 호출하도록 주의해야 합니다.

예제

Windows Forms 컨트롤에 대한 액세스는 기본적으로 스레드로부터 안전하지 않습니다. 컨트롤 상태를 조작하는 스레드가 두 개 이상 있는 경우 컨트롤이 일관성 없는 상태가 될 수 있습니다. 경합 상태, 교착 상태 등의 다른 스레드 관련 버그가 발생할 수 있습니다. 따라서 컨트롤에 대한 액세스가 스레드로부터 안전한 방식으로 수행되는지 확인해야 합니다.

.NET Framework에서는 사용자가 스레드로부터 안전하지 않은 방식으로 컨트롤에 액세스할 경우 이를 감지할 수 있습니다. 디버거에서 응용 프로그램을 실행할 때 컨트롤을 만든 스레드가 아닌 스레드에서 해당 컨트롤을 호출하려고 하면 디버거에서 InvalidOperationException [ http://msdn2.microsoft.com/ko-kr/library/system.invalidoperationexception(VS.80).aspx ] 을 발생시키고 "control name 컨트롤이 자신이 만들어진 스레드가 아닌 스레드에서 액세스되었습니다."라는 메시지를 표시합니다.

이 예외는 일부 환경에서 런타임에 디버깅하는 동안 안정적으로 발생합니다. 이 예외가 발생할 경우 문제를 수정하는 것이 좋습니다. 이 예외는 .NET Framework 2.0 이전 버전에서 작성한 응용 프로그램을 디버깅할 때 발생할 수 있습니다.

Note참고

CheckForIllegalCrossThreadCalls [ http://msdn2.microsoft.com/ko-kr/library/system.windows.forms.control.checkforillegalcrossthreadcalls(VS.80).aspx ] 속성 값을 false로 설정하여 이 예외를 비활성화할 수 있습니다. 그러면 컨트롤이 Visual Studio 2003에서와 같은 방식으로 실행됩니다.

다음 코드 예제에서는 작업자 스레드에서 스레드로부터 안전한 방식과 스레드로부터 안전하지 않은 방식으로 Windows Forms 컨트롤을 호출하는 방법을 보여 줍니다. 또한 스레드로부터 안전하지 않은 방식으로 TextBox [ http://msdn2.microsoft.com/ko-kr/library/system.windows.forms.textbox(VS.80).aspx ] 컨트롤의 Text [ http://msdn2.microsoft.com/ko-kr/library/system.windows.forms.control.text(VS.80).aspx ] 속성을 설정하는 방법과 스레드로부터 안전한 방식으로 Text 속성을 설정하는 두 가지 방법을 보여 줍니다.

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;

namespace CrossThreadDemo
{
    public class Form1 : Form
    {
        // This delegate enables asynchronous calls for setting
        // the text property on a TextBox control.
        delegate void SetTextCallback(string text);

        // This thread is used to demonstrate both thread-safe and
        // unsafe ways to call a Windows Forms control.
        private Thread demoThread = null;

        // This BackgroundWorker is used to demonstrate the
        // preferred way of performing asynchronous operations.
        private BackgroundWorker backgroundWorker1;

        private TextBox textBox1;
        private Button setTextUnsafeBtn;
        private Button setTextSafeBtn;
        private Button setTextBackgroundWorkerBtn;

        private System.ComponentModel.IContainer components = null;

        public Form1()
        {
            InitializeComponent();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        // This event handler creates a thread that calls a
        // Windows Forms control in an unsafe way.
        private void setTextUnsafeBtn_Click(
            object sender,
            EventArgs e)
        {
            this.demoThread =
                new Thread(new ThreadStart(this.ThreadProcUnsafe));

            this.demoThread.Start();
        }

        // This method is executed on the worker thread and makes
        // an unsafe call on the TextBox control.
        private void ThreadProcUnsafe()
        {
            this.textBox1.Text = "This text was set unsafely.";
        }

        // This event handler creates a thread that calls a
        // Windows Forms control in a thread-safe way.
        private void setTextSafeBtn_Click(
            object sender,
            EventArgs e)
        {
            this.demoThread =
                new Thread(new ThreadStart(this.ThreadProcSafe));

            this.demoThread.Start();
        }

        // This method is executed on the worker thread and makes
        // a thread-safe call on the TextBox control.
        private void ThreadProcSafe()
        {
            this.SetText("This text was set safely.");
        }

        // This method demonstrates a pattern for making thread-safe
        // calls on a Windows Forms control.
        //
        // If the calling thread is different from the thread that
        // created the TextBox control, this method creates a
        // SetTextCallback and calls itself asynchronously using the
        // Invoke method.
        //
        // If the calling thread is the same as the thread that created
        // the TextBox control, the Text property is set directly.

        private void SetText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.textBox1.InvokeRequired)
            {   
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.textBox1.Text = text;
            }
        }

        // This event handler starts the form's
        // BackgroundWorker by calling RunWorkerAsync.
        //
        // The Text property of the TextBox control is set
        // when the BackgroundWorker raises the RunWorkerCompleted
        // event.
        private void setTextBackgroundWorkerBtn_Click(
            object sender,
            EventArgs e)
        {
            this.backgroundWorker1.RunWorkerAsync();
        }
       
        // This event handler sets the Text property of the TextBox
        // control. It is called on the thread that created the
        // TextBox control, so the call is thread-safe.
        //
        // BackgroundWorker is the preferred way to perform asynchronous
        // operations.

        private void backgroundWorker1_RunWorkerCompleted(
            object sender,
            RunWorkerCompletedEventArgs e)
        {
            this.textBox1.Text =
                "This text was set safely by BackgroundWorker.";
        }

        #region Windows Form Designer generated code

        private void InitializeComponent()
        {
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.setTextUnsafeBtn = new System.Windows.Forms.Button();
            this.setTextSafeBtn = new System.Windows.Forms.Button();
            this.setTextBackgroundWorkerBtn = new System.Windows.Forms.Button();
            this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
            this.SuspendLayout();
            //
            // textBox1
            //
            this.textBox1.Location = new System.Drawing.Point(12, 12);
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(240, 20);
            this.textBox1.TabIndex = 0;
            //
            // setTextUnsafeBtn
            //
            this.setTextUnsafeBtn.Location = new System.Drawing.Point(15, 55);
            this.setTextUnsafeBtn.Name = "setTextUnsafeBtn";
            this.setTextUnsafeBtn.TabIndex = 1;
            this.setTextUnsafeBtn.Text = "Unsafe Call";
            this.setTextUnsafeBtn.Click += new System.EventHandler(this.setTextUnsafeBtn_Click);
            //
            // setTextSafeBtn
            //
            this.setTextSafeBtn.Location = new System.Drawing.Point(96, 55);
            this.setTextSafeBtn.Name = "setTextSafeBtn";
            this.setTextSafeBtn.TabIndex = 2;
            this.setTextSafeBtn.Text = "Safe Call";
            this.setTextSafeBtn.Click += new System.EventHandler(this.setTextSafeBtn_Click);
            //
            // setTextBackgroundWorkerBtn
            //
            this.setTextBackgroundWorkerBtn.Location = new System.Drawing.Point(177, 55);
            this.setTextBackgroundWorkerBtn.Name = "setTextBackgroundWorkerBtn";
            this.setTextBackgroundWorkerBtn.TabIndex = 3;
            this.setTextBackgroundWorkerBtn.Text = "Safe BW Call";
            this.setTextBackgroundWorkerBtn.Click += new System.EventHandler(this.setTextBackgroundWorkerBtn_Click);
            //
            // backgroundWorker1
            //
            this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
            //
            // Form1
            //
            this.ClientSize = new System.Drawing.Size(268, 96);
            this.Controls.Add(this.setTextBackgroundWorkerBtn);
            this.Controls.Add(this.setTextSafeBtn);
            this.Controls.Add(this.setTextUnsafeBtn);
            this.Controls.Add(this.textBox1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion


        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.Run(new Form1());
        }

    }
}

스레드로부터 안전하지 않은 Windows Forms 컨트롤 호출

스레드로부터 안전하지 않은 Windows Forms 컨트롤을 호출하는 방법은 작업자 스레드에서 직접 호출하는 것입니다. 응용 프로그램을 디버깅할 때 디버거에서는 InvalidOperationException을 발생시키고 컨트롤 호출이 스레드로부터 안전하지 않다는 경고를 표시합니다.

// This event handler creates a thread that calls a // Windows Forms control in an unsafe way. private void setTextUnsafeBtn_Click( object sender, EventArgs e) { this.demoThread = new Thread(new ThreadStart(this.ThreadProcUnsafe)); this.demoThread.Start(); } // This method is executed on the worker thread and makes // an unsafe call on the TextBox control. private void ThreadProcUnsafe() { this.textBox1.Text = "This text was set unsafely."; }

스레드로부터 안전한 방식으로 Windows Forms 컨트롤 호출

스레드로부터 안전한 방식으로 Windows Forms 컨트롤을 호출하려면

  1. 컨트롤의 InvokeRequired [ http://msdn2.microsoft.com/ko-kr/library/system.windows.forms.control.invokerequired(VS.80).aspx ] 속성을 쿼리합니다.
  2. InvokeRequiredtrue를 반환하는 경우에는 컨트롤을 실제로 호출하는 대리자를 사용하여 Invoke [ http://msdn2.microsoft.com/ko-kr/library/system.windows.forms.control.invoke(VS.80).aspx ] 를 호출합니다.
  3. InvokeRequiredfalse를 반환하는 경우에는 컨트롤을 직접 호출합니다.

다음 코드 예제에서는 SetText라는 유틸리티 메서드에서 이 논리를 구현합니다. SetTextDelegate 대리자 형식은 SetText 메서드를 캡슐화합니다. TextBox 컨트롤의 InvokeRequiredtrue를 반환하면 SetText 메서드는 SetTextDelegate 인스턴스를 만들고 폼의 Invoke 메서드를 호출합니다. 그러면 TextBox 컨트롤을 만든 스레드에서 SetText 메서드가 호출되고 이 스레드 컨텍스트에서 Text 속성이 직접 설정됩니다.

// This event handler creates a thread that calls a
// Windows Forms control in a thread-safe way.
private void setTextSafeBtn_Click(
    object sender,
    EventArgs e)
{
    this.demoThread =
        new Thread(new ThreadStart(this.ThreadProcSafe));

    this.demoThread.Start();
}

// This method is executed on the worker thread and makes
// a thread-safe call on the TextBox control.
private void ThreadProcSafe()
{
    this.SetText("This text was set safely.");
}


// This method demonstrates a pattern for making thread-safe
// calls on a Windows Forms control.
//
// If the calling thread is different from the thread that
// created the TextBox control, this method creates a
// SetTextCallback and calls itself asynchronously using the
// Invoke method.
//
// If the calling thread is the same as the thread that created
// the TextBox control, the Text property is set directly.

private void SetText(string text)
{
    // InvokeRequired required compares the thread ID of the
    // calling thread to the thread ID of the creating thread.
    // If these threads are different, it returns true.
    if (this.textBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText);
        this.Invoke(d, new object[] { text });
    }
    else
    {
        this.textBox1.Text = text;
    }
}
 

BackgroundWorker를 사용하여 스레드로부터 안전한 방식으로 호출

응용 프로그램에서 다중 스레딩을 구현하는 기본 방법은 BackgroundWorker [ http://msdn2.microsoft.com/ko-kr/library/system.componentmodel.backgroundworker(VS.80).aspx ] 구성 요소를 사용하는 것입니다. BackgroundWorker 구성 요소는 다중 스레딩의 이벤트 구동 모델을 사용합니다. 작업자 스레드는 DoWork [ http://msdn2.microsoft.com/ko-kr/library/system.componentmodel.backgroundworker.dowork(VS.80).aspx ] 이벤트 처리기를 실행하고 컨트롤을 만드는 스레드는 ProgressChanged [ http://msdn2.microsoft.com/ko-kr/library/system.componentmodel.backgroundworker.progresschanged(VS.80).aspx ] 및 RunWorkerCompleted [ http://msdn2.microsoft.com/ko-kr/library/system.componentmodel.backgroundworker.runworkercompleted(VS.80).aspx ] 이벤트 처리기를 실행합니다. DoWork 이벤트 처리기에서 컨트롤을 호출하지 마십시오.

다음 코드 예제에는 비동기적으로 수행되는 작업이 없으므로 DoWork 이벤트 처리기 구현이 없습니다. TextBox 컨트롤의 Text 속성은 RunWorkerCompleted 이벤트 처리기에서 직접 설정됩니다.


// This event handler starts the form's
// BackgroundWorker by calling RunWorkerAsync.
//
// The Text property of the TextBox control is set
// when the BackgroundWorker raises the RunWorkerCompleted
// event.
private void setTextBackgroundWorkerBtn_Click(
    object sender,
    EventArgs e)
{
    this.backgroundWorker1.RunWorkerAsync();
}

// This event handler sets the Text property of the TextBox
// control. It is called on the thread that created the
// TextBox control, so the call is thread-safe.
//
// BackgroundWorker is the preferred way to perform asynchronous
// operations.

private void backgroundWorker1_RunWorkerCompleted(
    object sender,
    RunWorkerCompletedEventArgs e)
{
    this.textBox1.Text =
        "This text was set safely by BackgroundWorker.";
}

Windows Forms의 ActiveX 컨트롤

폼에서 ActiveX 컨트롤을 사용하는 경우 디버거에서 실행할 때 크로스 스레드 InvalidOperationException이 발생할 수 있습니다. 이런 경우에는 ActiveX 컨트롤에서 다중 스레딩을 지원하지 않습니다. Windows Forms에서의 ActiveX 컨트롤 사용에 대한 자세한 내용은 Windows Forms 및 관리되지 않는 응용 프로그램 [ http://msdn2.microsoft.com/ko-kr/library/ms229610(VS.80).aspx ] 을 참조하십시오.

Visual Studio를 사용하는 경우에는 Visual Studio 호스팅 프로세스를 비활성화하여 이 예외가 발생하지 않도록 만들 수 있습니다.

자세한 내용은 다음을 참조하십시오. How to: Disable the Hosting Process [ http://msdn2.microsoft.com/ko-kr/ms185330(vs.90).aspx ] 및 방법: 호스팅 프로세스 비활성화 [ http://msdn2.microsoft.com/ko-kr/ms185330(vs.80).aspx ] .

강력한 프로그래밍

Caution note주의

어떤 종류의 다중 스레딩을 사용하든지 코드가 매우 심각하고 복잡한 버그에 노출될 수 있습니다. 다중 스레딩을 사용하는 솔루션을 구현하기 전에 관리되는 스레딩을 구현하는 최선의 방법 [ http://msdn2.microsoft.com/ko-kr/library/1c9txz50(VS.80).aspx ] 에서 자세한 내용을 참조하십시오.

참고 항목

작업

방법: 백그라운드에서 작업 실행 [ http://msdn2.microsoft.com/ko-kr/library/hybbz6ke(VS.80).aspx ]
방법: 백그라운드 작업을 사용하는 폼 구현 [ http://msdn2.microsoft.com/ko-kr/library/waw3xexc(VS.80).aspx ]

참조

BackgroundWorker [ http://msdn2.microsoft.com/ko-kr/library/system.componentmodel.backgroundworker(VS.80).aspx ]

기타 리소스

.NET Framework에서 사용자 지정 Windows Forms 컨트롤 개발 [ http://msdn2.microsoft.com/ko-kr/library/6hws6h2t(VS.80).aspx ]
Windows Forms 및 관리되지 않는 응용 프로그램 [ http://msdn2.microsoft.com/ko-kr/library/ms229610(VS.80).aspx ]


원본 :
http://msdn2.microsoft.com/ko-kr/library/ms171728(VS.80).aspx
2007/10/10 09:26 2007/10/10 09:26
1. ping 명령을 사용하여 TCP/IP 구성 테스트
1. 컴퓨터의 TCP/IP를 빠르게 구성하려면 명령 프롬프트를 연 다음 ipconfig를 입력합니다.
2. 명령 프롬프트에 ping 127.0.0.1를 입력하여 루프백 주소를 ping합니다.
   ping 명령이 실패하면 TCP/IP가 설치되고 구성된 후 컴퓨터를 다시 시작하였었는지를 확인합니다.
3. 컴퓨터의 IP 주소를 ping합니다.
   ping 명령이 실패하면 TCP/IP가 설치되고 구성된 후 컴퓨터를 다시 시작하였었는지를 확인합니다.
4. 기본 게이트웨이의 IP 주소를 ping합니다.
   ping 명령이 실패하면 기본 게이트웨이 IP 주소가 올바르고 게이트웨이(라우터)가 작동되는지 확인합니다.
5. 원격 호스트(다른 서브넷 상의 호스트)의 IP 주소를 ping합니다.
   ping 명령이 실패하면 원격 호스트 IP 주소가 올바른지, 원격 호스트가 작동되는지, 이 컴퓨터와 원격 호스트 간의 모든 게이트웨이(라우터)가 작동되는지 확인합니다.
6. DNS 서버의 IP 주소를 ping합니다.
   ping 명령이 실패하면 DNS 서버 IP 주소가 올바른지, DNS 서버가 작동되는지, 이 컴퓨터와 DNS 서버 사이의 모든 게이트웨이(라우터)가 작동되는지 확인합니다.
참고
*명령 프롬프트를 열려면 시작을 클릭하고 프로그램, 보조프로그램을 차례로 가리킨 다음 명령 프롬프트를 클릭합니다.
*ping 명령이 없거나 실패하면 이벤트 뷰어를 사용하여 시스템 로그를 확인하여 설정 또는 인터넷 프로토콜(TCP/IP) 서비스에 의해 보고된 문제를 찾을 수 있습니다.

2. ping 명령과 net view 명령을 사용하여 TCP/IP 연결 테스트
1. ping 명령을 사용하여 TCP/IP 연결성을 테스트하려면 명령 프롬프트를 연 다음 IP 주소를 사용하여 원하는 호스트를 ping합니다.
   ping 명령이 실패하여 "요청 시간이 초과되었습니다."라는 메시지가 표시되면 호스트 IP 주소가 올바른지, 호스트가 작동되는지, 이 컴퓨터와 호스트 간의 모든 게이트웨이(라우터)가 작동되는지 확인합니다.
2. ping 명령을 사용하여 호스트 이름 확인을 테스트하려면 해당 호스트 이름을 사용하고 이름 확인을 원하는 호스트를 ping합니다.
   ping 명령이 실패하여 "알 수 없는 호스트"라는 메시지가 표시되면 호스트 이름이 올바른지, 사용자의 DNS 서버가 호스트 이름을 확인할 수 있는지를 확인합니다.
3. net view 명령을 사용하여 TCP/IP 연결을 테스트하려면 명령 프롬프트를 연 다음 net view computername을 입력합니다. net view 명령은 임시 NetBIOS 연결을 만들어 Windows 2000을 실행하는 컴퓨터의 파일 및 인쇄 공유를 목록으로 표시합니다. 지정된 컴퓨터에 파일 또는 인쇄 공유가 없으면 net view 명령은 "목록에 항목이 없습니다."라는 메시지를 표시합니다.
   net view 명령이 실패하여 "시스템 오류 53이 발생했습니다."라는 메시지가 표시되면 computername이 올바른지, Windows 2000을 실행하는 컴퓨터가 작동되는지, 이 컴퓨터와 Windows 2000을 실행하는 컴퓨터 사이의 모든 게이트웨이(라우터)가 작동되는지 확인합니다.
이 연결성 문제를 더 자세히 해결하려면 아래와 같은 작업을 수행합니다.
*ping 명령을 사용하여 computername을 ping합니다.
 ping 명령이 실패하여 "알 수 없는 호스트"라는 메시지가 표시되면 해당 IP 주소에서 computername을 확인할 수 없습니다.
*net view 명령 및 Windows 2000을 실행하는 컴퓨터의 IP 주소를 아래와 같이 사용합니다.
 net view IP address
net view 명령이 성공하면 잘못된 IP 주소에 computername이 연결되어 있습니다.
Windows 2000을 실행하는 컴퓨터가 Microsoft 네트워크용 파일 및 프린터 공유 서비스를 실행하고 있지 않으면 net view 명령이 실패하여 "시스템 오류 53이 발생하였습니다."라는 메시지가 표시됩니다.
참고
*명령 프롬프트를 열려면 시작을 클릭하고 프로그램, 보조프로그램을 차례로 가리킨 다음 명령 프롬프트를 클릭합니다.
*ping 명령이 없거나 실패하면 이벤트 뷰어를 사용하여 시스템 로그를 확인하여 설정 또는 인터넷 프로토콜(TCP/IP) 서비스에 의해 보고된 문제를 찾을 수 있습니다.

3. tracert 명령을 사용하여 경로 추적
*명령 프롬프트를 연 다음 아래와 같이 입력합니다.
 tracert host_name
또는  tracert ip_address를 입력합니다.
여기서 host_name 또는 ip_address는 각각 원격 컴퓨터의 호스트 이름 또는 IP 주소입니다.
예를 들어, 이 컴퓨터에서 www.microsoft.com으로 연결 경로를 추적하려면 명령 프롬프트에 아래와 같이 입력합니다.
참고
*명령 프롬프트를 열려면 시작을 클릭하고 프로그램, 보조프로그램을 차례로 가리킨 다음 명령 프롬프트를 클릭합니다.
*tracert 명령은 이 컴퓨터에서 다른 원격 컴퓨터까지의 TCP/IP 패킷의 경로를 추적합니다. tracert 명령은 ICMP echo 요청 및 응답 메시지(ping 명령과 비슷)를 사용하여 각 홉에 대한 왕복 이동 시간(RTT) 및 전달되는 각 라우터에 대한 명령줄 보고서를 출력합니다.
*tracert가 성공하지 못하면, 명령 출력을 사용하여 전달에 실패하거나 느려진 중간 라우터를 결정하는 것을 도울 수 있습니다.

4. nbtstat 명령을 사용하여 NetBIOS 이름 테이블 보기
1. 명령 프롬프트를 엽니다.
2. 명령 프롬프트에서 아래와 같이 입력합니다.
 nbtstat -n
이 컴퓨터의 NetBIOS 로컬 이름 테이블은 명령줄 출력으로 표시됩니다. 이름 형식이 표시되어 각각의 이름이 고유 이름인지 또는 그룹 이름인지 나타냅니다. 또한 이름이 네트워크에 등록되었는지의 여부를 나타내는 각 이름의 상태가 표시됩니다.
참고
*명령 프롬프트를 열려면 시작을 클릭하고 프로그램, 보조프로그램을 차례로 가리킨 다음 명령 프롬프트를 클릭합니다.
*nbtstat 명령은 TCP/IP(NetBT) 연결에서 NetBIOS가 사용하는 통계 및 이름 정보를 표시합니다. -n 옵션은 이 컴퓨터에 대한 로컬 NetBIOS 이름만 목록으로 표시하는 데 사용됩니다. nbtstat를 사용하여 아래와 같은 작업을 수행할 수도 있습니다.
*원격 컴퓨터의 NetBIOS 이름 테이블 목록 표시
*이 컴퓨터 또는 다른 원격 컴퓨터에 NetBIOS 이름 캐시의 내용 표시
*Lmhosts 파일에 있는 항목을 #PRE 옵션과 함께 사용하여 NetBIOS 이름 캐시 수동으로 로드 또는 다시 로드
*TCP/IP 세션 통계에서 NetBIOS 목록 표시
*WINS에서 NetBIOS 이름 해제 및 새로 고침

5. nbtstat 명령을 사용하여 NetBIOS 이름을 해제하고 새로 고치기
1. 명령 프롬프트를 엽니다.
2. 명령 프롬프트에서 아래와 같이 입력합니다.
 nbtstat -RR
해제 및 새로 고침 작업의 진행률은 명령줄 출력으로 표시됩니다. 이 정보는 이 컴퓨터에 대해 WINS에 현재 등록된 모든 로컬 NetBIOS 이름이 WINS 서버로 등록을 해제하고 갱신하였는지 나타냅니다.
참고
*명령 프롬프트를 열려면 시작을 클릭하고 프로그램, 보조프로그램을 차례로 가리킨 다음 명령 프롬프트를 클릭합니다.
*NetBIOS 이름은 WINS와 함께 등록되며 일반적으로 컴퓨터가 정상적으로 종료될 때 해제됩니다. 컴퓨터가 정상적으로 종료되지 않았거나 컴퓨터 이름을 종료 및 해제하는 동안 WINS 서버를 연결할 수 없었으면 이 명령을 사용하여 이 컴퓨터에 대한 로컬 이름을 WINS에서 새로 고치고 업데이트할 수 있습니다. 이것은 네트워크의 다른 위치들 사이에서 이동되는 이동식 컴퓨터 또는 휴대용 컴퓨터에 유용합니다.
*nbtstat 명령을 사용하여 아래와 같은 작업을 할 수도 있습니다.
이 컴퓨터 또는 다른 원격 컴퓨터에 등록된 NetBIOS 이름 목록 표시
이 컴퓨터 또는 다른 원격 컴퓨터에 NetBIOS 이름 캐시의 내용 표시
#PRE 옵션과 함께 Lmhosts 파일에 있는 항목을 사용하여 NetBIOS 이름 캐시 수동으로 로드 또는 다시 로드
TCP/IP 세션 통계에서 NetBIOS 목록 표시

6. ARP(Address Resolution Protocol) 캐시 보기
1. 명령 프롬프트를 엽니다.
2. 명령 프롬프트에 arp -a를 입력합니다.
예를 들어, 최근에 ping 명령을 사용하여 이 컴퓨터에서 IP 주소 10.0.0.99인 호스트 컴퓨터으로의 연결을 테스트 및 확인한 경우에는 ARP 캐시에 아래 항목이 표시됩니다.
인터페이스: 인터페이스 0x1의 10.0.0.1
인터넷 주소 실제 주소 형식
10.0.0.99 00-e0-98-00-7c-dc dynamic
이 예에서 캐시 항목은 10.0.0.99의 원격 호스트 컴퓨터가 원격 컴퓨터의 네트워크 어댑터 하드웨어에 지정된 미디어 액세스 제어 주소 00-e0-98-00-7c-dc로 확인됨을 나타냅니다. 미디어 액세스 제어 주소는 네트워크에서 컴퓨터가 이 원격 TCP/IP 호스트와의 실제 통신에 사용한 주소입니다.
참고
*명령 프롬프트를 열려면 시작을 클릭하고 프로그램, 보조프로그램을 차례로 가리킨 다음 명령 프롬프트를 클릭합니다.
*Windows 2000은 나중에 사용할 수 있도록 하드웨어-투-소프트웨어 주소 매핑의 캐시를 유지하여 네트워크에서 ARP 브로드캐스트 트래픽을 최소화합니다. 이 캐시에는 아래와 같은 두 가지 종류의 항목이 포함됩니다.
*동적 ARP 캐시 항목
이 항목들은 원격 컴퓨터에서 TCP/IP 세션을 정상적으로 사용하는 동안 자동으로 추가되고 삭제됩니다. 동적 항목은 2분 내에 다시 사용되지 않으면 캐시에서 만료됩니다. 동적 항목을 2분 내에 다시 사용하는 경우에는 동적 항목이 캐시에 남아 있을 수 있고 ARP 브로드캐스트 작업을 사용하여 제거하거나 캐시 갱신을 요청할 때까지 최대 캐시 수명인 10분까지 유지될 수 있습니다.
정적 ARP 캐시 항목
이 항목은 arp 명령을 -s 옵션과 함께 사용하여 수동으로 추가됩니다. 정적 항목은 컴퓨터가 다시 시작될 때까지 ARP 캐시에 남아 있습니다.

7. 정적 ARP 캐시 항목 추가
명령 프롬프트를 엽니다.
명령 프롬프트에서 아래와 같이 입력합니다.
arp -s ip_address mac_address
각각의 의미는 아래와 같습니다.
ip_address   같은 서브넷의 로컬 TCP/IP 노드의 IP 주소를 지정합니다.
mac_address 로컬 TCP/IP 노드에 설치되어 사용되는 네트워크 어댑터의 미디어 액세스 제어 주소를 지정합니다.
예를 들어, 00-10-54-CA-E1-40의 미디어 액세스 제어 주소를 확인하는 10.0.0.200의 IP 주소를 사용하여 로컬 TCP/IP 노드에 정적 ARP 항목을 추가하려면 명령 프롬프트에 아래와 같이 입력합니다.
arp -s 10.0.0.200 00-10-54-CA-E1-40
참고
*명령 프롬프트를 열려면 시작을 클릭하고 프로그램, 보조프로그램을 차례로 가리킨 다음 명령 프롬프트를 클릭합니다.
*정적 ARP 항목은 자주 사용되는 호스트에 대한 빠른 액세스를 도와 줄 수 있습니다.
*정적 항목은 Windows 2000이 다시 시작될 때 까지만 유효합니다. 정적 ARP 캐시 항목을 영구적으로 만들기 위해 arp 명령을 시스템이 시작할 때 실행되는 일괄 파일에 추가할 수 있습니다.

8. 현재 TCP/IP 프로토콜 및 연결 통계 보기
1. 명령 프롬프트를 엽니다.
2. 명령 프롬프트에서 아래와 같이 입력합니다.
netstat
참고
*명령 프롬프트를 열려면 시작을 클릭하고 프로그램, 보조프로그램을 차례로 가리킨 다음 명령 프롬프트를 클릭합니다.
*netstat 명령줄 옵션을 보려면 아래와 같이 입력합니다.
netstat /?
2007/09/15 16:53 2007/09/15 16:53
사용자 삽입 이미지


SQL Server Configuration Manager 를 실행후,
- 1.SQL Server 2005 Network Configuration 선택
- 2. Protocols for [DB이름] 선택
- 3. TCP/IP 선택후 오른쪽 버튼 클릭,
- 4. IP Addresses 탭 선택
- 5. IP All -> TCP Port 에 포트 설정(Ex :: 1433)
2007/09/10 15:46 2007/09/10 15:46
단일 테이블 연결
SqlDataAdapter myadapter=new SqlDataAdapter("select * from address", 
"server=(local);Trusted_connection=yes;database=ado"); DataSet mydataset=new DataSet(); myadapter.Fill(mydataset, "address"); dataGrid1.DataSource=mydataset.Tables["address"].DefaultView; 행의 추가 SqlDataAdapter myadapter=new SqlDataAdapter("select * from address",
"server=(local);Trusted_connection=yes;database=ado"); SqlCommandBuilder mycommandbuilder=new SqlCommandBuilder(myadapter); DataSet mydataset=new DataSet(); myadapter.Fill(mydataset, "address"); DataRow myrow=mydataset.Tables["address"].NewRow(); myrow["name"]=textBox1.Text; myrow["phone"]=textBox2.Text; myrow["email"]=textBox3.Text; mydataset.Tables["address"].Rows.Add(myrow); myadapter.Update(mydataset, "address"); dataGrid1.DataSource=mydataset.Tables["address"].DefaultView; 행의 삭제 SqlDataAdapter myadapter=new SqlDataAdapter("select * from address",
"server=(local);Trusted_connection=yes;database=ado"); SqlCommandBuilder mycommandbuilder=new SqlCommandBuilder(myadapter); DataSet mydataset=new DataSet(); myadapter.Fill(mydataset, "address"); curRow=dataGrid1.CurrentRowIndex; if (curRow >-1) mydataset.Tables["address"].Rows[curRow].Delete(); myadapter.Update(mydataset.GetChanges(DataRowState.Deleted), "address"); dataGrid1.DataSource=mydataset.Tables["address"].DefaultView; 행의 수정 SqlDataAdapter myadapter=new SqlDataAdapter("select * from address",
"server=(local);Trusted_connection=yes;database=ado"); SqlCommandBuilder mycommandbuilder=new SqlCommandBuilder(myadapter); DataSet mydataset=new DataSet(); myadapter.Fill(mydataset, "address"); curRow=dataGrid1.CurrentRowIndex; mydataset.Tables["address"].Rows[curRow].BeginEdit(); mydataset.Tables["address"].Rows[curRow]["name"]=textBox1.Text; mydataset.Tables["address"].Rows[curRow]["phone"]=textBox2.Text; mydataset.Tables["address"].Rows[curRow]["email"]=textBox3.Text; mydataset.Tables["address"].Rows[curRow].EndEdit(); myadapter.Update(mydataset, "address"); dataGrid1.DataSource=mydataset.Tables["address"].DefaultView;
위를 보시면 대충 연결에 대해 이해가 가실꺼고..
대충 요런식으로 리스트 뷰에 데이타를 집어 넣으시면 되겠네요.ㅎㅎ
public void GetPatientList(ListView list)
  {
   
   list.Items.Clear();
   ListViewItem item;
   foreach(DataRow r in dSet.Tables["patient"].Rows)
   {
    item=new ListViewItem(r["name"].ToString());
    item.SubItems.Add(r["jumin"].ToString());
    item.SubItems.Add(r["id"].ToString());
    list.Items.Add(item);
   }
  }
2007/08/31 10:10 2007/08/31 10:10

[MySQL] 한글 설정

Developer 2007/05/20 02:56

MySQL을 설치하면 기본적으로 UTF-8로 Charset이 설정되어 있다.

이를 EUC-KR로 변경을 하기 위해서는 MySQL 설정파일인 my.cnf 파일에

다음의 내용을 추가한다.

[client]
default-character-set = euckr

[mysqld]
......
init_connect='set names euckr'
character-set-server=euckr
default-character-set=euckr
default-collation=euckr_korean_ci
character-set-client-handshake=false

[mysqldump]
default-character-set=euckr
2007/05/20 02:56 2007/05/20 02:56
 boot.ini 파일 내용을 수정합니다.

/noexecute   ->   /execute  로 "no" 부분만 수정하면됩니다.

boot.ini 파일 수정방법

시작 -> "실행"에서 ../boot.ini  라고 치면 메모장이 나옵니다.
2007/04/26 02:57 2007/04/26 02:57

C#에서 현재 실행중인 프로그램을 다시 실행하는 경우가 발생할 때 중복실행 여부를

확인하여 그에 대한 처리를 할 수 있도록 하는 코드이다.

System.Threading.Mutex 클래스를 이용한다.

기본적인 사용법은 다음과 같다.

[STAThread]
static void Main() {
    bool createdNew;
    Mutex gM1 = new Mutex(true,"MyMutex", out createdNew);              
    if (createdNew) {
        Application.Run(new frmMain());
        gM1.ReleaseMutex();
    }else {
        MessageBox.Show("이미 실행되어 있습니다.");
    }
}

이를 응용하여 네이트온과 같이 실행중인 경우 트레이에 있을 때 중복 실행이 되면 기존에 실행중인

프로그램을 활성화 시키는 방법이다.

[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern void BringWindowToTop(IntPtr hWnd);

[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern void SetForegroundWindow(IntPtr hWnd);

[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

[STAThread]
static void Main() {
    bool createNow = true;
    using(System.Threading.Mutex mutex =
              new System.Threading.Mutex(true, "ServerControllerMutex", out createNow)) {
        if (createNow) {
           Application.EnableVisualStyles();
           Application.SetCompatibleTextRenderingDefault(false);
           Application.Run(new FormMain());
        }
        else {
            IntPtr wHandle = FindWindow(null, "PDA 수신 서버");
            if (wHandle != IntPtr.Zero) {
               ShowWindow(wHandle, 1);
               BringWindowToTop(wHandle);
               SetForegroundWindow(wHandle);
            }
            Application.Exit();
        }
    }
}

2007/04/25 23:19 2007/04/25 23:19

1. mysqladmin을 이용하여 root 암호 설정
     $ mysqladmin -u root -p password new-password

이러한 명령을 실행하면 됩니다. 실행하면 패스워드를 입력하라고 하는데 처음 root의 패스워드는 없으므로 그냥 엔터를 치시면 root 패스워드가 변경됩니다.


2. update문을 이용하여 root 암호 설정 
      $ mysql -u root mysql

       mysql> update user set password = password('new-password') where user = 'root';
       mysql> flush privileges;


3. set password를 이용하여 root 암호 설정

      mysql> set password for root = password('new-password');

2007/04/12 14:30 2007/04/12 14:30
TAG
원도우 서비스 사용시의 log4net을 사용할 때는 추가적인 설정이 필요하다.

log4net을 적용하는 클래스에서 설정파일을 등록할 때 절대경로를 이용해야 한다.

또한 설치된 폴더의 권한을 변경하여야 하는데 이는 서비스 생성 시 Account 설정에 따라

변경이 된다.

만일 Account를 Network Services로 한 경우 설치된 폴더의 보안설정에서 Network Services

계정을 추가하여 쓰기 권한을 주어야 로그를 남길 수 있게 된다.

자세한 사항은 http://logging.apache.org/log4net/release/faq.html (새 창으로 열기) 를 참조하면 된다.
2007/04/10 02:38 2007/04/10 02:38
응용 프로그램에서 프로그램의 실행 경로는 System.Environment.CurrentDirectory를 이용하여

프로그램이 실행중인 폴더경로를 얻어올 수 있으나. 원도우 서비스인 경우 위의 방법을 이용하면

"C:\Windows\System32" 폴더를 반환한다. 따라서 실행중인 폴더에서 파일을 읽는 경우 못읽는

경우가 발생한다. 이를 위해 다음과 같이 System.Reflection.Assembly 클래스를 이용하여 어셈블리

의 절대경로를 얻어옴으로써 원도우 서비스에서도 실행중인 폴더에서의 파일을 읽을 수 있다.


System.Reflection.Assembly Asm = System.Reflection.Assembly.GetExecutingAssembly();
string location = Asm.Location; // 어셈블리(EZChatServerLib) 절대경로가 반환된다.
location = location.Substring(0, location.LastIndexOf("\\"));

위 코드를 이용하면 어셈블리의 절대경로를 얻어올 수 있다.
2007/04/10 02:32 2007/04/10 02:32