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

namespace SocketServer
{
    internal class Program
    {
        private static List<Socket> clients = new List<Socket>();
        private static List<String> userNames = new List<string>();
        private static Socket Server;
        static void Main(string[] args)
        {
            Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            Server.Bind(new IPEndPoint(IPAddress.Any, 12345));
            Server.Listen(10);
            Console.WriteLine("服务端开启，等待用户连接");

            while(true)
            {
                Socket client = Server.Accept();
                clients.Add(client);
                Console.WriteLine($"用户连接{client.RemoteEndPoint}");// 输出用户ip，端口
                // 多线程实现用户之间通信
                Thread th = new Thread(() => HandleClient(client));
                th.Start();

            }

            static void HandleClient(Socket client)
            {
                byte[] buffer = new byte[1024];//缓冲区、数据丢了就可以重发
                string name = "";
                try
                {
                    int num = client.Receive(buffer);//字节放进缓冲区
                                                     //字节-》String
                    name = Encoding.UTF8.GetString(buffer, 0, num);//从第0个字节开始，转换num个为字符
                    Console.WriteLine($"{client.RemoteEndPoint}注册为{name}");
                    //告诉其他客户，广播
                    BoardCasts($"{client.RemoteEndPoint}注册为{name}", client);
                    userNames.Add(name);
                    while(true)
                    {
                        num = client.Receive(buffer);
                        if(num == 0) break;// 客户端退出，不再聊天
                        string message = Encoding.UTF8.GetString(buffer, 0, num);
                        BoardCasts(name + ":" + message, client);// 告诉其他客户端
                        Console.WriteLine(name + ":" + message);// 告诉服务端

                    }
                }
                catch(Exception ex)
                {
                    // 防止各种原因退出导致的服务端崩溃，如内存溢出、网络错误，可以放在日志、输出
                }
                finally
                {
                    client.Close();
                    clients.Remove(client);
                    userNames.Remove(name);
                    BoardCasts(name + "下线", client);// 告诉其他客户端
                    Console.WriteLine(name + "下线");// 告诉服务端
                }
                
                
            }

            static void BoardCasts(string msg , Socket client)
            {
                foreach(var i in clients)
                {
                    if(i != client)// 除去发送者本人（注册的人）
                    {
                        i.Send(Encoding.UTF8.GetBytes(msg));//Socket是字节传输信息
                    }
                }
            }
        }
    }
}
