본문 바로가기
공부,일/C# 네트워크

20210818 네트워크 프로그래밍 채팅 프로그램 만들기 (M:M)

by fromnothing1 2021. 8. 18.

1. select

: 리스트 안에 있는 소켓의 상태를 확인한다. ( 데이타가 들어왔는지 , 데이타를 쓰는지 등등)

데이타가 들어온 소켓만 따로 리스트를 만든다. 

원본 리스트는 회손된다. 

 

https://docs.microsoft.com/ko-kr/dotnet/api/system.net.sockets.socket.select?view=net-5.0 

 

Socket.Select(IList, IList, IList, Int32) 메서드 (System.Net.Sockets)

하나 이상의 소켓 상태를 확인합니다.Determines the status of one or more sockets.

docs.microsoft.com

서버

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

namespace NetSocket_Server_002
{
    class SmartServer
    {
        private Thread aThread;
        private Socket aSocket;
        private ArrayList aSocketList;
        private string IP;
        private int Port;

        public SmartServer() : this("192.168.0.110", 5000)
        {
        }
        public SmartServer(string IP) : this(IP, 5000)
        {
        }
        public SmartServer(int Port) : this("192.168.0.110", Port)
        {
        }
        public SmartServer(string IP, int Port)
        {
            this.IP = IP;
            this.Port = Port;

            this.aSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this.aSocket.Bind(new IPEndPoint(IPAddress.Parse(this.IP), this.Port));
            this.aSocket.Listen(5);

            this.aSocketList = new ArrayList();
            this.aSocketList.Add(aSocket);

            aThread = new Thread(Receiver);
        }

        private void SendTOClient(byte[] aData,int iSize)
        {
            foreach (Socket User in aSocketList)
            {
                if (User == aSocket)
                {
                    continue;
                }
                User.Send(aData, 0, iSize, SocketFlags.None);
            }
        }

        private void SendTOClient(Socket RSoket,byte[] aData, int iSize)
        {
            foreach (Socket User in aSocketList)
            {
                if (User == RSoket)
                {
                    continue;
                }
                if (User == aSocket)
                {
                    continue;
                }
                User.Send(aData, 0, iSize, SocketFlags.None);
            }
        }


        private void Receiver()
        {
            ArrayList aSocketList_Temp;
            byte[] aData = new byte[1024];
            string aString;
            int iSize;

            while (true)
            {
                aSocketList_Temp = (ArrayList)(aSocketList.Clone());
                Socket.Select(aSocketList_Temp, null, null, -1);

                foreach (Socket Temp in aSocketList_Temp)
                {
                    if (Temp != aSocket)
                    {
                        iSize = Temp.Receive(aData);
                        aString = Temp.RemoteEndPoint +" : "+Encoding.Default.GetString(aData, 0, iSize);
                        if ("quit" != aString)
                        {
                            SendTOClient(Temp,aData, iSize);
                            Console.WriteLine("대화:" + aString);
                        }
                        else
                        {
                            string TempMessage = "채팅종료 : "+" : "+Temp.RemoteEndPoint;
                            Temp.Close();
                            aSocketList.Remove(Temp);

                            byte[] aData_Temp = Encoding.Default.GetBytes(TempMessage);

                            SendTOClient(aData_Temp, aData_Temp.Length);

                            Console.WriteLine(TempMessage);
                            Console.WriteLine("현재 접속자 수 : " + (aSocketList.Count - 1));
                        }
                    }
                    else
                    {
                        aSocketList.Add(Temp.Accept());
                        Console.WriteLine("새로운 접속자 : " + ((Socket)aSocketList[aSocketList.Count - 1]).RemoteEndPoint);
                        Console.WriteLine("현재 접속자 수 : " + (aSocketList.Count - 1));
                    }
                }
            }
        }
        public void Run()
        {
            byte[] aData;
            string aString;

            Console.WriteLine("Server Start...");

            aThread.Start();

            while (true)
            {
                Console.Write("서버 입력 : ");
                aString = Console.ReadLine();
                aData = Encoding.Default.GetBytes("[공지사항]" + aString);
                //aData = Encoding.UTF8.GetBytes("[공지사항]" + aString);   // 뿌띠 테스트용

                SendTOClient(aData, aData.Length);

                if ("quit" == aString)
                {
                    break;
                }
            }

            aThread.Abort();

            foreach (Socket User in aSocketList)
            {
                User.Close();
            }

            aThread = null;
            aSocket = null;
            aSocketList = null;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            SmartServer aSmartServer = new SmartServer();
            aSmartServer.Run();
        }
    }
}

클라이언트

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

namespace NetSocket_client
{
    class SmartClient
    {

        private Socket aSocket;
        private string IP;
        private int Port;
        private Thread aThread;
        private string NickName;

        public SmartClient() : this("192.168.0.110",5000,"someone")
        {
        }
        public SmartClient(string IP) : this(IP, 5000, "someone")
        {
        }
        public SmartClient(int Port) : this("192.168.0.110", Port, "someone")
        {
        }
        public SmartClient(string IP, int Port) : this(IP, Port, "someone")
        {
        }
        public SmartClient(string IP, int Port, string NickName)
        {
            this.aSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this.IP   = IP;
            this.Port = Port;
            this.NickName = NickName;

            aThread = new Thread(Receiver);
            Console.WriteLine("서버 접속정보 : " + this.IP +" , "+ this.Port);
        }

        private void Receiver()
        {
            byte[] aData = new byte[1024];
            string aString;
            int iSize;

            while (true)
            {
                iSize = aSocket.Receive(aData);
                aString = Encoding.Default.GetString(aData, 0, iSize);
                if (aString == "[공지사항]quit")
                {
                    Console.WriteLine("서버의 종료 요청으로 채팅프로그램을 닫습니다.");
                    Environment.Exit(1); // .. 0은 시스템이 정상 종료를 알려준다. 
                }
                Console.WriteLine("수신: " + aString);
            }
        }
        public void run()
        {
            byte[] aData;
            String aStirng;

            Console.WriteLine("서버 접속 시도 중...");
            aSocket.Connect("192.168.0.110", 5000);
            Console.WriteLine("서버 온라인...");

            aThread.Start();

            while (true)
            {
                Console.Write("클라이언트 입력 : ");
                aStirng = Console.ReadLine();
                aData = Encoding.Default.GetBytes(aStirng);
                aSocket.Send(aData,0, aData.Length, SocketFlags.None);

                if ("quit" == aStirng)
                {
                    aData = Encoding.Default.GetBytes("1명 나가유");
                    break;
                }

            }
            aThread.Abort(); // Thread 가 무한 while 문이라서 join 은 쓸수 없다.
            aSocket.Close();
        }

    }
    class Program
    {

        static void Main(string[] args)
        {
            SmartClient client = new SmartClient();
            client.run();
        }
        
    }
}

 

에러 처리 완료 코드

 

서버

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

namespace NetSocket_210819_010
{
    class SmartServer
    {
        private Thread aThread;
        private Socket aSocket;
        private ArrayList aSocketList;
        private string IP;
        private int Port;
        private Dictionary<Socket, string> NicName;

        public SmartServer() : this("192.168.0.110", 5000)
        {
        }
        public SmartServer(string IP) : this(IP, 5000)
        {
        }
        public SmartServer(int Port) : this("192.168.0.110", Port)
        {
        }
        public SmartServer(string IP, int Port)
        {
            this.IP = IP;
            this.Port = Port;

            this.aSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                this.aSocket.Bind(new IPEndPoint(IPAddress.Parse(this.IP), this.Port));
            }
            catch (SocketException)
            {
                Console.WriteLine("Bind에 문제가 있어 서버 초기화가 불가능 합니다.");
                aThread = null;
                aSocket = null;
                aSocketList = null;
                IP = null;
                Port = 0;
                NicName = null;
                return;
            }

            this.aSocket.Listen(5);

            this.aSocketList = new ArrayList();
            this.aSocketList.Add(aSocket);

            aThread = new Thread(Receiver);
            NicName = new Dictionary<Socket, string>();
            NicName.Add(aSocket, "서버");
        }

        private void SendToClient(byte[] aData, int iSize)
        {
            foreach (Socket User in aSocketList)
            {
                if (User == aSocket)
                {
                    continue;
                }
                User.Send(aData, 0, iSize, SocketFlags.None);
            }
        }

        private void Receiver()
        {
            ArrayList aSocketList_Temp;
            string aString;
            byte[] aData = new byte[1024];
            byte[] aData_Temp;
            int iSize;

            while (true)
            {
                aSocketList_Temp = (ArrayList)(aSocketList.Clone());
                Socket.Select(aSocketList_Temp, null, null, -1);

                foreach (Socket Temp in aSocketList_Temp)
                {
                    if (Temp != aSocket)
                    {
                        try
                        {
                            iSize = Temp.Receive(aData);
                            aString = Encoding.Default.GetString(aData, 0, iSize);
                        }
                        catch (SocketException)
                        {
                            Console.WriteLine(NicName[Temp] + " 사용자와의 연결에 문제가 발생하였습니다.");
                            aString = "quit";
                        }

                        if ("quit" != aString)
                        {
                            aString = NicName[Temp] + " : " + aString;
                            aData_Temp = Encoding.Default.GetBytes(aString);

                            SendToClient(aData_Temp, aData_Temp.Length);
                            Console.WriteLine(aString);
                        }
                        else
                        {
                            aString = "\n" + NicName[Temp] + ": 채팅 종료\n";
                            Temp.Close();
                            aSocketList.Remove(Temp);
                            NicName.Remove(Temp);

                            aData_Temp = Encoding.Default.GetBytes(aString);

                            SendToClient(aData_Temp, aData_Temp.Length);

                            Console.WriteLine(aString);
                            Console.WriteLine("현재 접속자 수 : " + (aSocketList.Count - 1));
                        }
                    }
                    else
                    {
                        Socket aSocket = Temp.Accept();

                        iSize = aSocket.Receive(aData);
                        aString = Encoding.Default.GetString(aData, 0, iSize);
                        NicName.Add(aSocket, aString);

                        aSocketList.Add(aSocket);

                        Console.WriteLine("새로운 접속자(" + aSocket.RemoteEndPoint + ") : " + aString);
                        Console.WriteLine("현재 접속자 수 : " + (aSocketList.Count - 1));
                    }
                }
            }
        }
        public void Run()
        {
            byte[] aData;
            string aString;

            if (aSocket == null)
            {
                Console.WriteLine("서버가 초기화 되지 않아 실행이 불가합니다...");
                return;
            }

            Console.WriteLine("Server Start...");

            aThread.Start();

            while (true)
            {
                Console.Write("서버 입력 : ");
                aString = Console.ReadLine();
                aData = Encoding.Default.GetBytes("[공지사항]" + aString);
                //aData = Encoding.UTF8.GetBytes("[공지사항]" + aString);   // 뿌띠 테스트용

                SendToClient(aData, aData.Length);

                if ("quit" == aString)
                {
                    break;
                }
            }

            aThread.Abort();

            foreach (Socket User in aSocketList)
            {
                User.Close();
            }

            aThread = null;
            aSocket = null;
            NicName = null;
            aSocketList = null;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            SmartServer aSmartServer = new SmartServer();
            aSmartServer.Run();
        }
    }
}

클라이언트

using System;
using System.Linq.Expressions;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace NetSocket_Client_010
{
    class SmartClient
    {
        private Socket aSocket;
        private string IP;
        private int Port;
        private Thread aThread;
        private Thread aThread2;
        private bool bExit;

        public SmartClient() : this("192.168.0.110", 5000)
        {
        }
        public SmartClient(string IP) : this(IP, 5000)
        {
        }
        public SmartClient(int Port) : this("192.168.0.110", Port)
        {
        }
        public SmartClient(string IP, int Port)
        {
            aSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this.IP = IP;
            this.Port = Port;
            this.bExit = false;

            this.aThread = new Thread(Receiver);
            this.aThread2 = new Thread(Sender);

            Console.WriteLine("서버 접속 정보 : " + this.IP + ":" + this.Port);
        }

        private void Receiver()
        {
            byte[] aData = new byte[1024];
            string aString;
            int iSize;

            while (true)
            {
                try
                {
                    iSize = aSocket.Receive(aData);
                    aString = Encoding.Default.GetString(aData, 0, iSize);
                }
                catch (SocketException)
                {
                    aString = "[공지사항]quit";
                }

                if (aString == "[공지사항]quit")
                {
                    Console.WriteLine("서버의 종료 요청으로 채팅 프로그램을 닫습니다.");
                    bExit = true;
                    return;
                }

                Console.WriteLine("\n" + aString);
            }
        }

        private void Sender()
        {
            byte[] aData;
            string aString;

            while (true)
            {
                Console.Write("> ");
                aString = Console.ReadLine();
                aData = Encoding.Default.GetBytes(aString);
                aSocket.Send(aData, aData.Length, SocketFlags.None);

                if ("quit" == aString)
                {
                    bExit = true;
                    break;
                }
            }
        }
        public void Run()
        {
            byte[] aData;
            string aString;

            while (true)
            {
                Console.Write("닉네임을 입력하세요 : ");
                aString = Console.ReadLine();
                if (aString.Length == 0)
                {
                    Console.WriteLine("잘 못된 닉네임입니다.");
                    continue;
                }
                break;
            }

            aString = "[" + aString + "]";

            Console.WriteLine("서버 접속 시도 중...");

            try
            {
                aSocket.Connect("192.168.0.110", 5000);
            }
            catch (SocketException)
            {
                Console.WriteLine("서버 오프라인...");
                return;
            }

            aData = Encoding.Default.GetBytes(aString);
            aSocket.Send(aData, aData.Length, SocketFlags.None);

            Console.WriteLine("서버 온라인...");

            aThread.Start();
            aThread2.Start();

            while (!bExit)
            {
                Thread.Sleep(10);
            }

            aThread.Abort();
            aThread2.Abort();
            aSocket.Close();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            SmartClient aSmartClient = new SmartClient();
            aSmartClient.Run();
        }
    }
}

'공부,일 > C# 네트워크' 카테고리의 다른 글

packet 분석기 만들기 (3)  (0) 2021.09.15
packet 분석기 만들기 (2) HexaViewer , NIC 선택  (0) 2021.09.10
packet 분석기 만들기 (1)  (0) 2021.09.10
1:1 채팅 만들기 socket  (0) 2021.08.17
210817 쓰레드  (0) 2021.08.17

댓글