개발/개인 프로젝트

C# 소켓, 스레드를 이용한 채팅 프로그램

안녕진 2020. 1. 7. 17:17

(C#을 처음 시작했기 때문에, 틀리거나 비효율적인 부분이 많이 있을 수 있습니다. 알려주시면 수정하겠습니다.)

 

 

C#이 Java와 너무 비슷해서, Java로 배운 네트워크/스레드 프로그래밍 기술(?)로 만든 엄청 간단한 채팅 프로그램이다.

Socket 통신에 관한 내용은 다른 블로그들에 너무너무 설명이 잘 돼있으니 참고하자!

 

 

작동 방식은 아래와 같다.

1. A, B, C 접속

2. A가 메시지를 보냄 => 서버에 전송 => 서버가 B, C에게 A의 메시지를 보냄

** 클라이언트끼리의 통신이 아니고, 클라이언트들과 서버의 통신이다.

 

 

테스트방법(사용방법)은

1. 서버프로그램과 클라이언트(2~3개)프로그램들을 차례대로 실행한다.(서버부터 실행)

**실행 == dotnet run

2. 모든 클라이언트 프로그램에 id/client1 처럼 아이디(client1)를 입력한다. (아이디는 서로 다르게)

3. 한 클라이언트 프로그램에 addMsg/입력할메시지 라고 입력하고, 다른 프로그램들의 변화를 관찰한다.

왼쪽부터 순서대로 서버 / 클라이언트1 / 클라이언트2

 

 

client와 server 모두 아래와 비슷하게 while문을 돌며 각각 server측 / client측의 입력을 계속 받도록 했고,

외부(server 혹은 client)로부터 입력을 받을 때, 다른 작업(server 혹은 client로의 전송)을 할 수 있도록 Thread를 생성하여 실행했다.

아래는 client의 source code 중 일부이다.

(new Thread(new ThreadStart(() =>
            {
                while(true)
                {
                    String line = "";
                    while(line.Equals(""))
                    {
                        line = reader.ReadLine();
                        if(line == null)
                        {
                            Console.WriteLine("서버와의 연결이 끊어졌습니다.");
                            return;
                        }
                    }
                    String[] command = line.Split("/");
                    if(command[0].Equals("addMsg"))
                    {
                        Console.WriteLine(command[1] + "/" + command[2]);
                    }
                }
            }))).Start();

 

 

아래는 전체 source code이다.

 

Server

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;

namespace server
{
    class Program
    {
        public const int port = 50000;

        public static ArrayList clientList = new ArrayList();
        static void Main(string[] args)
        {
            new Program();
        }

        public Program()
        {
            TcpListener tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), port);
            tcpListener.Start();
            while(true)
            {
                Socket client = tcpListener.AcceptSocket();
                IPEndPoint ip = (IPEndPoint) client.RemoteEndPoint;
                Console.WriteLine("주소 {0}에서 접속", ip);
                ClientListener clientThread = new ClientListener(client);
                clientList.Add(clientThread);
            }
        }
    }

    class ClientListener
    {
        String id;
        Socket client;
        System.IO.StreamReader reader;
        System.IO.StreamWriter writer;
        public ClientListener(Socket client)
        {
            this.client = client;
            NetworkStream networkStream = new NetworkStream(client);
            this.reader = new System.IO.StreamReader(networkStream);
            this.writer = new System.IO.StreamWriter(networkStream);
            (new Thread(new ThreadStart(Run))).Start();
        }
        
        private void Run()
        {
            while(true)
            {
                String line = "";
                while(line.Equals(""))
                {
                    line = reader.ReadLine();
                    if(line == null)
                    {
                        Program.clientList.Remove(this);
                        Console.WriteLine(this.id + "접속 종료");
                        return;
                    }
                }
                Console.WriteLine(client.RemoteEndPoint + "-send/" + line);
                
                String[] command = line.Split("/");
                if(command[0].Equals("addMsg"))
                {
                    foreach(object clientThread in Program.clientList)
                    {
                        ClientListener client = (ClientListener) clientThread;
                        Console.WriteLine(client.id);
                        if(!client.Equals(this))
                        {
                            NetworkStream networkStream = new NetworkStream(client.client);
                            System.IO.StreamWriter writer = new System.IO.StreamWriter(networkStream);
                            writer.WriteLine("addMsg/" + this.id + "/" + command[1]);
                            writer.Flush();
                        }
                    }
                }
                else if(command[0].Equals("id"))
                {
                    this.id = command[1];
                }
            }
        }
        public override bool Equals(Object obj)
        {
            //Check for null and compare run-time types.
            if ((obj == null) || ! this.GetType().Equals(obj.GetType())) 
            {
                return false;
            }
            else { 
                ClientListener other = (ClientListener) obj; 
                return (this.id == other.id);
            }   
        }
        public override int GetHashCode() { return 0; } // 나중에 알아보기
    }
}

 

Client

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

namespace client
{
    class Program
    {
        static void Main(string[] args)
        {
            TcpClient server;
            try
            {
                server = new TcpClient("127.0.0.1", 50000);
            }
            catch (Exception)
            {
                Console.WriteLine("서버와의 연결이 끊어졌습니다.");
                return;
            }

            NetworkStream networkStream = server.GetStream();
            System.IO.StreamReader reader = new System.IO.StreamReader(networkStream);
            System.IO.StreamWriter writer = new System.IO.StreamWriter(networkStream);

            (new Thread(new ThreadStart(() =>
            {
                while(true)
                {
                    String line = "";
                    while(line.Equals(""))
                    {
                        line = reader.ReadLine();
                        if(line == null)
                        {
                            Console.WriteLine("서버와의 연결이 끊어졌습니다.");
                            return;
                        }
                    }
                    String[] command = line.Split("/");
                    if(command[0].Equals("addMsg"))
                    {
                        Console.WriteLine(command[1] + "/" + command[2]);
                    }
                }
            }))).Start();

            String line = "";
            while(!line.Equals("quit"))
            {
                line = Console.ReadLine();
                writer.WriteLine(line);
                writer.Flush();
            }
        }
    }
}