채팅 프로그램 만들기

2) 채팅 프로그램 만들기 - 클라이언트 기능

잡동사니123 2023. 6. 16. 02:11

TCP 통신을 위한 구성

 

 

Form1 전체 코드

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace client
{
    public partial class Form1 : Form
    {
        TcpClient client;
        NetworkStream stream;
        public Form1()
        {
            InitializeComponent();
        }


        private void Form1_Load(object sender, EventArgs e)
        {
            //소켓 만들기
            client = new TcpClient();

            //서버에 연결 시도
            try
            {
                client.Connect("192.168.0.17", 8000);
                //stream 얻기
                stream = client.GetStream();
                Thread handler = new Thread(message_Receive);
                handler.IsBackground = true;
                handler.Start();
            }
            catch (SocketException se)
            {
                receiveTextBox.Text = se.Message;
            }


        }

        private void sendButton_Click(object sender, EventArgs e)
        {
            //stream에 메시지 보내기
            byte[] buffer = Encoding.Unicode.GetBytes(sendTextBox.Text);

            try
            {
                stream.Write(buffer, 0, buffer.Length);
            }
            catch (IOException ie)
            { 
                receiveTextBox.Text = ie.Message;
            }
        }

        private void message_Receive()
        {
            while(true) 
            {
                //메시지 받기
                byte[] recv = new byte[80];
                try
                {
                    int bytes = stream.Read(recv, 0, recv.Length);
                    string output = Encoding.Unicode.GetString(recv, 0, bytes);

                    if (receiveTextBox.InvokeRequired)
                        receiveTextBox.Invoke(new MethodInvoker(delegate { receiveTextBox.AppendText(output + Environment.NewLine); }));
                    else
                        receiveTextBox.AppendText(output + Environment.NewLine);
                }
                catch (IOException ie)
                {
                    if (receiveTextBox.InvokeRequired)
                        receiveTextBox.Invoke(new MethodInvoker(delegate { receiveTextBox.AppendText(ie.Message + Environment.NewLine); }));
                    else
                        receiveTextBox.AppendText(ie.Message + Environment.NewLine);
                    return;

                }
            }

        }
    }
}

 

Form1_Load

 private void Form1_Load(object sender, EventArgs e)
{
    //소켓 만들기
    client = new TcpClient();

    //서버에 연결 시도
    try
    {
        client.Connect("192.168.0.17", 8000);
        //stream 얻기
        stream = client.GetStream();
    }
    catch (SocketException se)
    {
        receiveTextBox.Text = se.Message;
    }

        Thread handler = new Thread(message_Receive);
        handler.IsBackground= true;
        handler.Start();
 }
  • Form1_Load : 폼이 생성될때 자동으로 실행되는 이벤트 함수
  • client : TcpClient를 생성
  • client.Connect : (ip,port번호) 에 해당하는 곳으로 연결을 시도함, ip와 port는 사용자 환경에 따라 수정 필자는 테스트 용이라 본인 컴퓨터 ip에 아무 포트번호 설정
  • 스트림 얻기 : client의 스트림을 얻음
  • 스레드 만들기 : 위 프로그램은 항상 메시지를 받도록 할 예정이므로 가만히 있든 메시지를 보내든 이상없이 메시지를 받을 수 있게 스레드를 만들어서 메시지르 받는 함수가 계속 돌아가게 함

 

sendButton_Click 이벤트

private void sendButton_Click(object sender, EventArgs e)
{
    //stream에 메시지 보내기
    byte[] buffer = Encoding.Unicode.GetBytes(sendTextBox.Text);

    try
    {
        stream.Write(buffer, 0, buffer.Length);
    }
    catch (IOException ie)
    { 
        receiveTextBox.Text = ie.Message;
    }

}
  • sendButton_Click : send 버튼 누를때마다 실행되는 이벤트 함수
  • Encoding.Unicode.GetBytes :  send박스에 입력했던 string을 byte로 변환해서 byte에 저장
  • stream.Write : buffer의 내용을 서버로 전송함

 

message_Receive 함수

private void message_Receive()
{
    while(true) 
    {
        //메시지 받기
        byte[] recv = new byte[80];
        try
        {
            int bytes = stream.Read(recv, 0, recv.Length);
            string output = Encoding.Unicode.GetString(recv, 0, bytes);

            if (receiveTextBox.InvokeRequired)
                receiveTextBox.Invoke(new MethodInvoker(delegate { receiveTextBox.AppendText(output + Environment.NewLine); }));
            else
                receiveTextBox.AppendText(output + Environment.NewLine);
        }
        catch (IOException ie)
        {
            if (receiveTextBox.InvokeRequired)
                receiveTextBox.Invoke(new MethodInvoker(delegate { receiveTextBox.AppendText(ie.Message + Environment.NewLine); }));
            else
                receiveTextBox.AppendText(ie.Message + Environment.NewLine);
            return;
        }
    }

}
  • message_Receive : 쓰레드를 이용해 프로그램 종료까지 항상 실행되는 사용자가 만든 함수
  • stream.Read : 서버에서 보낸 메시지를 읽어서 recv 배열에 저장
  • Encoding.Uincode.GetString : 서버에서 받은 byte 메시지를 string으로 바꿔 output에 저장
  • if문 : receive박스에 output을 출력하는 함수, 번거롭게 if문을 거치는 이유는 윈폼도 보이지 않는 스레드로 돌아가는데 그 스레드가 아닌 다른 스레드에서 값이 변경되면 오류가 나기 때문