첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ 1:1 채팅하기

----------------------------------------------------------------------------------------------------


TestChatting.zip


MainForm.cs

 

 

using Microsoft.Win32;

using System;

using System.IO;

using System.Net;

using System.Net.Sockets;

using System.Runtime.InteropServices;

using System.Threading;

using System.Windows.Forms;

 

namespace TestChatting

{

    /// <summary>

    /// 메인 폼

    /// </summary>

    public partial class MainForm : Form

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Import

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region 윈도우 깜박이기 - FlashWindow(windowHandle, inverted)

 

        /// <summary>

        /// 윈도우 깜박이기

        /// </summary>

        /// <param name="windowHandle">윈도우 핸들</param>

        /// <param name="inverted">반전 여부</param>

        /// <returns>처리 결과</returns>

        [DllImport("User32.dll")]

        private static extern bool FlashWindow(IntPtr windowHandle, bool inverted);

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Delegate

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region 메시지 추가하기 대리자 - AddMessageDelegate(message)

 

        /// <summary>

        /// 메시지 추가하기 대리자

        /// </summary>

        /// <param name="message">메시지</param>

        private delegate void AddMessageDelegate(string message);

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 메시지명

        /// </summary>

        private const string MESSAGE_NAME = "TestChattingeName";

 

        /// <summary>

        /// 메시지 포트

        /// </summary>

        private const string MESSAGE_PORT = "TestChattingPort";

 

        /// <summary>

        /// 레지스트리 키

        /// </summary>

        private RegistryKey registryKey = null;

 

        /// <summary>

        /// 메시지 추가 대리자

        /// </summary>

        private AddMessageDelegate addMessageDelegate = null;

 

        /// <summary>

        /// TCP 리스너

        /// </summary>

        private TcpListener tcpListener;

 

        /// <summary>

        /// 서버 TCP 클라이언트

        /// </summary>

        private TcpClient serverTcpClient;

        

        /// <summary>

        /// 클라이언트 TCP 클라이언트

        /// </summary>

        private TcpClient clientTcpClient;

 

        /// <summary>

        /// 네트워크 스트림

        /// </summary>

        private NetworkStream networkStream;

 

        /// <summary>

        /// 스트림 리더

        /// </summary>

        private StreamReader streamReader;

 

        /// <summary>

        /// 스트림 라이터

        /// </summary>

        private StreamWriter streamWriter;

 

        /// <summary>

        /// 서버 실행 여부

        /// </summary>

        private bool isServerRunning = false;

 

        /// <summary>

        /// 클라이언트 실행 여부

        /// </summary>

        private bool isClientRunning = false;

 

        /// <summary>

        /// 서버 포트

        /// </summary>

        private int serverPort;

 

        /// <summary>

        /// 별칭

        /// </summary>

        private string aliasName;

 

        /// <summary>

        /// 서버 스레드

        /// </summary>

        private Thread serverThread;

 

        /// <summary>

        /// 수신 스레드

        /// </summary>

        private Thread receiveThread;

        

        /// <summary>

        /// 텍스트 변경 여부

        /// </summary>

        private bool isTextChanged = false;

 

        /// <summary>

        /// 텍스트 송신 여부

        /// </summary>

        private bool isTextSent = false;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - MainForm()

 

        /// <summary>

        /// 생성자

        /// </summary>

        public MainForm()

        {

            InitializeComponent();

 

            this.addMessageDelegate = new AddMessageDelegate(AddMessage);

 

            RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("SOFTWARE", true);

 

            registryKey.CreateSubKey("TestChatting", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryOptions.None);

 

            this.registryKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\TestChatting", true);

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        //////////////////////////////////////////////////////////////////////////////// Event

 

        #region 폼 로드시 처리하기 - Form_Load(sender, e)

 

        /// <summary>

        /// 폼 로드시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void Form_Load(object sender, EventArgs e)

        {

            string messageName = null;

            

            try

            {

                messageName = this.registryKey.GetValue(MESSAGE_NAME) as string;

            }

            catch

            {

            }

 

            string messagePort = null;

            

            try

            {

                messagePort = this.registryKey.GetValue(MESSAGE_PORT) as string;

            }

            catch

            {

            }

 

            if(string.IsNullOrEmpty(messageName))

            {

                this.aliasName  = this.idTextBox.Text;

            }

            else

            {

                this.aliasName  = messageName;

            }

 

            if(string.IsNullOrEmpty(messagePort))

            {

                this.serverPort = 62000;

            }

            else

            {

                try

                {

                    this.serverPort = Convert.ToInt32(messagePort);

                }

                catch

                {

                    this.serverPort = 62000;

                }

            }

 

            this.idTextBox.Text   = this.aliasName;

            this.portTextBox.Text = this.serverPort.ToString();

        }

 

        #endregion

        #region 폼을 닫을 경우 처리하기 - Form_FormClosing(sender, e)

 

        /// <summary>

        /// 폼을 닫을 경우 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void Form_FormClosing(object sender, FormClosingEventArgs e)

        {

            if(this.runServerCheckBox.Checked)

            {

                StopServer();

            }

            else

            {

                DisconnectServer();

            }

        }

 

        #endregion

        #region 설정 도구 스트립 메뉴 항목 클릭시 처리하기 - settingToolStripMenuItem_Click(sender, e)

 

        /// <summary>

        /// 설정 도구 스트립 메뉴 항목 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void settingToolStripMenuItem_Click(object sender, EventArgs e)

        {

            this.settingToolStripMenuItem.Enabled = false;

 

            this.optionPanel.Visible = true;

 

            this.idTextBox.Focus();

        }

 

        #endregion

        #region 닫기 도구 스트립 메뉴 항목 클릭시 처리하기 - closeToolStripMenuItem_Click(sender, e)

 

        /// <summary>

        /// 닫기 도구 스트립 메뉴 항목 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)

        {

            Close();

        }

 

        #endregion

        #region Connect 도구 스트립 버튼 클릭시 처리하기 - connectToolStripButton_Click(sender, e)

 

        /// <summary>

        /// Connect 도구 스트립 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void connectToolStripButton_Click(object sender, EventArgs e)

        {

            if(this.runServerCheckBox.Checked == true)

            {

                #region 서버 실행 체크시 처리한다.

 

                IPAddress ipAddress = new IPAddress(0);

 

                try

                {

                    this.aliasName = this.registryKey.GetValue(MESSAGE_NAME) as string;

                }

                catch

                {

                    this.aliasName  = this.idTextBox.Text;

                    this.serverPort = Convert.ToInt32(this.portTextBox.Text);

                }

 

                if(this.isServerRunning)

                {

                    #region 서버 실행시 처리한다.

 

                    StopServer();

 

                    #endregion

                }

                else

                {

                    #region 서버 중단시 처리한다.

 

                    try

                    {

                        this.tcpListener = new TcpListener(ipAddress, this.serverPort);

 

                        this.tcpListener.Start();

 

                        this.isServerRunning = true;

 

                        this.inputMessageTextBox.Enabled = true;

 

                        this.sendButton.Enabled = true;

 

                        this.inputMessageTextBox.Focus();

 

                        this.disconnectToolStripButton.Enabled = true;

 

                        this.connectToolStripButton.Enabled = false;

 

                        this.runServerCheckBox.Enabled = false;

 

                        this.serverThread = new Thread(StartServer);

 

                        this.serverThread.Start();

 

                        this.settingToolStripMenuItem.Enabled = false;

                    }

                    catch

                    {

                        Invoke(this.addMessageDelegate, "서버를 실행할 수 없습니다.");

                    }

 

                    #endregion

                }

 

                #endregion

            }

            else

            {

                if(this.isClientRunning)

                {

                    #region 클라이언트 실행시 처리한다.

 

                    this.inputMessageTextBox.Enabled = false;

 

                    this.sendButton.Enabled = false;

 

                    DisconnectServer();

 

                    #endregion

                }

                else

                {

                    #region 클라이언트 중단시 처리한다.

 

                    this.aliasName  = this.registryKey.GetValue(MESSAGE_NAME) as string;

                    this.serverPort = Convert.ToInt32(this.registryKey.GetValue(MESSAGE_PORT));

 

                    ConnectServer();

 

                    #endregion

                }

            }

        }

 

        #endregion

        #region Disconnect 도구 스트립 버튼 클릭시 처리하기 - disconnectToolStripButton_Click(sender, e)

 

        /// <summary>

        /// Disconnect 도구 스트립 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void disconnectToolStripButton_Click(object sender, EventArgs e)

        {

            try

            {

                if(this.runServerCheckBox.Checked)

                {

                    if(this.serverTcpClient.Connected)

                    {

                        string currentTimeString = Convert.ToString(DateTime.Now);

 

                        this.streamWriter.WriteLine(this.aliasName + "&" + "채팅 어플리케이션이 종료되었습니다." + "&" + currentTimeString);

 

                        this.streamWriter.Flush();

                    }

                }

                else

                {

                    if(this.clientTcpClient.Connected)

                    {

                        string currentTimeString = Convert.ToString(DateTime.Now);

 

                        this.streamWriter.WriteLine(this.aliasName + "&" + "채팅 어플리케이션이 종료되었습니다." + "&" + currentTimeString);

 

                        this.streamWriter.Flush();

                    }

                }

            }

            catch

            {

            }

 

            StopServer();

 

            this.settingToolStripMenuItem.Enabled = true;

        }

 

        #endregion

        #region 서버 실행 체크 박스 체크 변경시 처리하기 - runServerCheckBox_CheckedChanged(sender, e)

 

        /// <summary>

        /// 서버 실행 체크 박스 체크 변경시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void runServerCheckBox_CheckedChanged(object sender, EventArgs e)

        {

            if(this.runServerCheckBox.Checked)

            {

                this.ipTextBox.Enabled = false;

            }

            else

            {

                this.ipTextBox.Enabled = true;

            }

        }

 

        #endregion

        #region 설정 버튼 클릭시 처리하기 - settingButton_Click(sender, e)

 

        /// <summary>

        /// 설정 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void settingButton_Click(object sender, EventArgs e)

        {

            if(this.runServerCheckBox.Checked == true)

            {

                SetControl();

            }

            else

            {

                if(this.ipTextBox.Text == string.Empty)

                {

                    this.ipTextBox.Focus();

                }

                else

                {

                    SetControl();

                }

            }

        }

 

        #endregion

        #region 닫기 버튼 클릭시 처리하기 - closeButton_Click(sender, e)

 

        /// <summary>

        /// 닫기 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void closeButton_Click(object sender, EventArgs e)

        {

            this.settingToolStripMenuItem.Enabled = true;

 

            this.optionPanel.Visible = false;

 

            this.inputMessageTextBox.Focus();

        }

 

        #endregion

        #region 입력 메시지 텍스트 박스 키 PRESS 처리하기 - inputMessageTextBox_KeyPress(sender, e)

 

        /// <summary>

        /// 입력 메시지 텍스트 박스 키 PRESS 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void inputMessageTextBox_KeyPress(object sender, KeyPressEventArgs e)

        {

            if(e.KeyChar == (char)13)

            {

                e.Handled = true;

 

                this.sendButton.PerformClick();

            }

        }

 

        #endregion

        #region 입력 메시지 텍스트 박스 텍스트 변경시 처리하기 - inputMessageTextBox_TextChanged(sender, e)

 

        /// <summary>

        /// 입력 메시지 텍스트 박스 텍스트 변경시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void inputMessageTextBox_TextChanged(object sender, EventArgs e)

        {

            if(this.isTextChanged == false && this.isTextSent != false)

            {

                this.isTextChanged = true;

 

                this.streamWriter.WriteLine("S001" + "&" + "상대방이 메시지 입력중입니다." + "&" + " ");

 

                this.streamWriter.Flush();

            }

            else if(this.inputMessageTextBox.Text == "" && this.isTextChanged == true && this.isTextSent == true)

            {

                this.isTextChanged = false;

            }

        }

 

        #endregion

        #region 전송 버튼 클릭시 처리하기 - sendButton_Click(sender, e)

 

        /// <summary>

        /// 전송 버튼 클릭시 처리하기

        /// </summary>

        /// <param name="sender">이벤트 발생자</param>

        /// <param name="e">이벤트 인자</param>

        private void sendButton_Click(object sender, EventArgs e)

        {

            if(this.inputMessageTextBox.Text == string.Empty)

            {

                this.inputMessageTextBox.Focus();

            }

            else

            {

                SendMessage();

            }

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Function

 

        #region 메시지 추가하기 - AddMessage(message)

 

        /// <summary>

        /// 메시지 추가하기

        /// </summary>

        /// <param name="message">메시지</param>

        private void AddMessage(string message)

        {

            this.messageRichTextBox.AppendText(message + "\r\n");

 

            this.messageRichTextBox.Focus();

 

            this.messageRichTextBox.ScrollToCaret();

 

            this.inputMessageTextBox.Focus();

 

            FlashWindow(Handle, true);

        }

 

        #endregion

        #region 수신하기 - Receive()

 

        /// <summary>

        /// 수신하기

        /// </summary>

        private void Receive()

        {

            try

            {

                while(this.isClientRunning)

                {

                    Thread.Sleep(1);

 

                    if(this.networkStream.CanRead)

                    {

                        string message = this.streamReader.ReadLine();

 

                        string[] messageElementArray = message.Split('&');

 

                        if(messageElementArray[0] == "S001")

                        {

                            this.timeToolStripStatusLabel.Text = messageElementArray[1];

                        }

                        else

                        {

                            if(message.Length > 0)

                            {

                                Invoke(this.addMessageDelegate, messageElementArray[0] + " : " + messageElementArray[1]);

                            }

 

                            this.timeToolStripStatusLabel.Text = "마지막으로 받은 시각 :" + messageElementArray[2];

                        }

                    }

                }

            }

            catch

            {

            }

        }

 

        #endregion

        #region 서버 시작하기 - StartServer()

 

        /// <summary>

        /// 서버 시작하기

        /// </summary>

        private void StartServer()

        {

            Invoke(this.addMessageDelegate, "서버 실행 : 챗 상대의 접속을 기다립니다...");

 

            while(this.isServerRunning)

            {

                try

                {

                    this.serverTcpClient = this.tcpListener.AcceptTcpClient();

 

                    Invoke(this.addMessageDelegate, "챗 상대 접속..");

 

                    this.networkStream = this.serverTcpClient.GetStream();

 

                    this.streamReader = new StreamReader(this.networkStream);

                    this.streamWriter = new StreamWriter(this.networkStream);

 

                    this.isClientRunning = true;

 

                    this.isTextSent = true;

 

                    this.receiveThread = new Thread(Receive);

 

                    this.receiveThread.Start();

                }

                catch

                {

                }

            }

        }

 

        #endregion

        #region 서버 중단하기 - StopServer()

 

        /// <summary>

        /// 서버 중단하기

        /// </summary>

        private void StopServer()

        {

            this.isServerRunning = false;

 

            this.inputMessageTextBox.Enabled = false;

 

            this.inputMessageTextBox.Clear();

 

            this.sendButton.Enabled = false;

 

            this.connectToolStripButton.Enabled = true;

 

            this.disconnectToolStripButton.Enabled = false;

 

            this.runServerCheckBox.Enabled = true;

 

            this.isClientRunning = false;

 

            if(this.streamReader != null)

            {

                this.streamReader.Close();

            }

 

            if(this.streamWriter != null)

            {

                this.streamWriter.Close();

            }

 

            if(this.networkStream != null)

            {

                this.networkStream.Close();

            }

 

            if(this.serverTcpClient != null)

            {

                this.serverTcpClient.Close();

            }

 

            if(this.tcpListener != null)

            {

                this.tcpListener.Stop();

            }

 

            if(this.receiveThread != null)

            {

                this.receiveThread.Abort();

            }

 

            if(this.serverThread != null)

            {

                this.serverThread.Abort();

            }

 

            Invoke(this.addMessageDelegate, "연결이 끊어졌습니다.");

        }

 

        #endregion

        #region 서버 접속하기 - ConnectServer()

 

        /// <summary>

        /// 서버 접속하기

        /// </summary>

        private void ConnectServer()

        {

            try

            {

                this.clientTcpClient = new TcpClient(this.ipTextBox.Text, this.serverPort);

 

                Invoke(this.addMessageDelegate, "서버에 접속했습니다.");

 

                this.networkStream = this.clientTcpClient.GetStream();

 

                this.streamReader = new StreamReader(this.networkStream);

                this.streamWriter = new StreamWriter(this.networkStream);

 

                this.isClientRunning = true;

 

                this.connectToolStripButton.Enabled = false;

 

                this.disconnectToolStripButton.Enabled = true;

 

                this.inputMessageTextBox.Enabled = true;

 

                this.sendButton.Enabled = true;

 

                this.inputMessageTextBox.Focus();

 

                this.receiveThread = new Thread(Receive);

 

                this.receiveThread.Start();

            }

            catch

            {

                this.isClientRunning = false;

 

                Invoke(this.addMessageDelegate, "서버에 접속하지 못했습니다.");

            }

        }

 

        #endregion

        #region 서버 접속 끊기 - DisconnectServer()

 

        /// <summary>

        /// 서버 접속 끊기

        /// </summary>

        private void DisconnectServer()

        {

            this.isClientRunning = false;

 

            try

            {

                if(this.streamReader != null)

                {

                    this.streamReader.Close();

                }

 

                if(this.streamWriter != null)

                {

                    this.streamWriter.Close();

                }

 

                if(this.networkStream != null)

                {

                    this.networkStream.Close();

                }

 

                if(this.clientTcpClient != null)

                {

                    this.clientTcpClient.Close();

                }

 

                if(this.receiveThread != null)

                {

                    this.receiveThread.Abort();

                }

            }

            catch

            {

                return;

            }

        }

 

        #endregion

        #region 컨트롤 설정하기 - SetControl()

 

        /// <summary>

        /// 컨트롤 설정하기

        /// </summary>

        private void SetControl()

        {

            if(this.idTextBox.Text == "")

            {

                this.idTextBox.Focus();

            }

            else if(this.portTextBox.Text == "")

            {

                this.portTextBox.Focus();

            }

            else

            {

                try

                {

                    string id   = this.idTextBox.Text;

                    string port = this.portTextBox.Text;

 

                    this.registryKey.SetValue(MESSAGE_NAME, id  );

                    this.registryKey.SetValue(MESSAGE_PORT, port);

 

                    this.optionPanel.Visible = false;

 

                    this.settingToolStripMenuItem.Enabled = true;

                    this.connectToolStripButton.Enabled   = true;

                }

                catch

                {

                    MessageBox.Show("설정이 저장되지 않았습니다.", "에러", MessageBoxButtons.OK, MessageBoxIcon.Error);

                }

            }

        }

 

        #endregion

        #region 메시지 보내기 - SendMessage()

 

        /// <summary>

        /// 메시지 보내기

        /// </summary>

        private void SendMessage()

        {

            try

            {

                string currentTimeString = Convert.ToString(DateTime.Now);

 

                this.streamWriter.WriteLine(this.aliasName + "&" + this.inputMessageTextBox.Text + "&" + currentTimeString);

 

                this.streamWriter.Flush();

 

                AddMessage(this.aliasName + " : " + this.inputMessageTextBox.Text);

 

                this.inputMessageTextBox.Clear();

            }

            catch

            {

                Invoke(this.addMessageDelegate, "메지시 전송시 오류가 발생하였습니다.");

 

                this.inputMessageTextBox.Clear();

            }

        }

 

        #endregion

    }

}

 

----------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker

댓글을 달아 주세요