C# Socket之TCP服務器

需要引用using System.Net.Sockets; using System.Net;兩個命名空間;

namespace TcpServer  //服務器
{
    class Program
    {
        public static List<Client> clientList = new List<Client>();
       
        static void Main(string[] args)
        {
            Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//創建socket對象
            tcpServer.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.145"), 8090));//綁定IP和申請端口

            tcpServer.Listen(100);//設置客戶端最大連接數
            Console.WriteLine("服務器已啟動,等待連接.........");
            while (true)//循環等待新客戶端的連接
            {
                Socket clientSocket = tcpServer.Accept();
                Console.WriteLine((clientSocket.RemoteEndPoint as IPEndPoint).Address+"已連接");
                Client client = new Client(clientSocket);
                clientList.Add(client);
            }
        }
        public static void BroadcastMessage(string message, Client clientSocket)//這個函數用來廣播接收到的客戶端消息  參數1為消息,參數2為消息來源(客戶端)
        {
            var onConnectedList = new List<Client>();//用來存儲已斷開服務器連接的客戶端

            foreach (var client in clientList)//遍歷已經存儲的客戶端
            {
                if (clientSocket == client)//如果該客戶端是消息來源,則不重復發送消息給該客戶端
                {
                    continue;
                }
                if (client.Connected)//判斷該客戶端的狀態
                {
                    client.SendMessage(client.ip + ":" + message);//
                }
                else//把已斷開連接的客戶端放到數組中
                {
                    onConnectedList.Add(client);
                }
            }
            foreach (var temp in onConnectedList)//廣播完之后從存儲已連接客戶端集合中移除掉已斷開連接的客戶端
            {
                clientList.Remove(temp);
            }
        }
    }
}
namespace TcpServer  
{
    class Client
    {
        private Socket clientSocket;
        private Thread t;
        public string ip = "";
        private byte[] data = new byte[1024];
        public Client(Socket socket)
        {
            clientSocket = socket;
            ip = (clientSocket.RemoteEndPoint as IPEndPoint).Address.ToString();//獲取客戶端的ip
            t = new Thread(ReceiveMessage);//開啟線程執行循環接收消息
            t.Start();
        }
        private void ReceiveMessage()//接收消息
        {
            int length = 0;//初始化消息的長度
            while (true)//循環接收消息
            {
                length = clientSocket.Receive(data);//獲取存放消息數據數組的長度
                if (clientSocket.Poll(10, SelectMode.SelectRead))//????
                {
                    clientSocket.Close();
                    break;
                }
                if (length != 0)//判斷是否有數組內是否存放消息數據
                {
                    string message = Encoding.UTF8.GetString(data, 0, length);//Byte轉為string
                    Program.BroadcastMessage(message, this);//廣播給其他客戶端
                    Console.WriteLine("來自" + (clientSocket.RemoteEndPoint as IPEndPoint).Address + ":" + message);//輸出到服務器控制臺
                    length = 0;//歸0
                }
            }
        }
        public void SendMessage(string message)//發送消息
        {
            byte[] data = Encoding.UTF8.GetBytes(message);
            clientSocket.Send(data);
        }
        public bool Connected//獲取該客戶端的狀態
        {
            get { return clientSocket.Connected; }
        }
    }
}
image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 此文章將記錄我在C# Winform 開發過程中遇到的問題及相關知識技術點 ,方便自己以后查閱..... 博客原文...
    遇見_c256閱讀 3,411評論 1 21
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,869評論 18 139
  • 一、 為什么需要命名空間(問題提出) 命名空間是ANSIC++引入的可以由用戶命名的作用域,用來處理程序中 常見的...
    IvanRunning閱讀 2,385評論 0 2
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,075評論 25 708
  • 煮溫酒,論銀劍,醉后相歡。吞青梅,思白棋,歡后相念。記閑日,飲苦茶,念后相知。撲燭火,放簾幕,知后相守。
    星河沸點閱讀 238評論 0 1