2022年4月20日 星期三

c# socket server, client, delegate, thread






using System;

using System.Collections.Generic;

using System.Net;

using System.Net.Sockets;

using System.Text;

using System.Threading;

using System.Windows.Forms;


namespace SocketTestApp

{

    public partial class SocketTest : Form

    {

        //建立一個和客戶端通訊的套接字

        Socket SocketWatch = null;

        //定義一個集合,儲存客戶端資訊

        Dictionary<string, Socket> ClientConnectionItems = new Dictionary<string, Socket> { };


        public SocketTest()

        {

            InitializeComponent();

        }


        private void button1_Click(object sender, EventArgs e)

        {

            //埠號(用來監聽的)

            int port = 6000;


            //string host = "127.0.0.1";

            //IPAddress ip = IPAddress.Parse(host);

            IPAddress ip = IPAddress.Any;


            //將IP地址和埠號繫結到網路節點point上 

            IPEndPoint ipe = new IPEndPoint(ip, port);


            //定義一個套接字用於監聽客戶端發來的訊息,包含三個引數(IP4定址協議,流式連線,Tcp協議) 

            SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //監聽繫結的網路節點 

            SocketWatch.Bind(ipe);

            //將套接字的監聽佇列長度限制為20 

            SocketWatch.Listen(20);



            //負責監聽客戶端的執行緒:建立一個監聽執行緒 

            Thread threadwatch = new Thread(ServerWatchConnecting);

            //將窗體執行緒設定為與後臺同步,隨著主執行緒結束而結束 

            threadwatch.IsBackground = true;

            //啟動執行緒   

            threadwatch.Start();

            


            Console.WriteLine("開啟監聽......");

            Console.WriteLine("點選輸入任意資料回車退出程式......");

            richTextBox1.AppendText("開啟監聽......");

            /*

            Console.ReadKey();


            SocketWatch.Close();

            */

        }



        //監聽客戶端發來的請求 

        void ServerWatchConnecting()

        {

            Socket connection = null;


            //持續不斷監聽客戶端發來的請求   

            while (true)

            {

                try

                {

                    connection = SocketWatch.Accept();

                }

                catch (Exception ex)

                {

                    //提示套接字監聽異常   

                    Console.WriteLine(ex.Message);

                    break;

                }


                //客戶端網路結點號 

                string remoteEndPoint = connection.RemoteEndPoint.ToString();

                //新增客戶端資訊 

                ClientConnectionItems.Add(remoteEndPoint, connection);


                string strTotalMsg = "\r\n[客戶端\"" + remoteEndPoint + "\"建立連線成功! 客戶端數量:" + ClientConnectionItems.Count + "]";

                

                this.Invoke((MethodInvoker)delegate

                {

                    lock (this.listBox1)

                        listBox1.Items.Add(remoteEndPoint);

                });


                //顯示與客戶端連線情況

                Console.WriteLine(strTotalMsg);


                //獲取客戶端的IP和埠號 

                IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address;

                int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port;


                //讓客戶顯示"連線成功的"的資訊 

                string sendmsg = "[" + "本地IP:" + clientIP + " 本地埠:" + clientPort.ToString() + " 連線服務端成功!]";

                byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendmsg);

                connection.Send(arrSendMsg);


                this.Invoke((MethodInvoker)delegate

                {

                    lock (this.richTextBox1)

                        this.richTextBox1.AppendText(strTotalMsg);

                });


                //建立一個通訊執行緒   

                Thread thread = new Thread(ServerRecv);

                //啟動執行緒   

                thread.Start(connection);

            }

        }



        void ServerRecv(object socket_obj)

        {

            Socket socketServer = socket_obj as Socket;


            while (true)

            {

                //建立一個記憶體緩衝區,其大小為1024*1024位元組 即1M   

                byte[] arrServerRecMsg = new byte[1024 * 1024];

                //將接收到的資訊存入到記憶體緩衝區,並返回其位元組陣列的長度  

                try

                {

                    int length = socketServer.Receive(arrServerRecMsg);

                    if (length == 0)

                        continue;

                    //將機器接受到的位元組陣列轉換為人可以讀懂的字串   

                    string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);


                    string strTotalMsg = "\r\n[客戶端:" + socketServer.RemoteEndPoint + " 時間:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "]\r\n" + strSRecMsg;


                    this.Invoke((MethodInvoker)delegate

                    {

                        lock (this.richTextBox1)

                            this.richTextBox1.AppendText(strTotalMsg);

                    });


                    //將傳送的字串資訊附加到文字框txtMsg上   

                    Console.WriteLine(strTotalMsg);


                    //Thread.Sleep(3000);

                    //socketServer.Send(Encoding.UTF8.GetBytes("[" + socketServer.RemoteEndPoint + "]:"+strSRecMsg));

                    //傳送客戶端資料

                    if (ClientConnectionItems.Count > 0)

                    {

                        foreach (var socketTemp in ClientConnectionItems)

                        {

                            socketTemp.Value.Send(Encoding.UTF8.GetBytes("[" + socketServer.RemoteEndPoint + "]:" + strSRecMsg));

                        }

                    }

                }

                catch (Exception)

                {

                    listBox1.Items.Remove(socketServer.RemoteEndPoint.ToString());

                    ClientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());

                    //提示套接字監聽異常 

                    Console.WriteLine("\r\n[客戶端\"" + socketServer.RemoteEndPoint + "\"已經中斷連線! 客戶端數量:" + ClientConnectionItems.Count + "]");

                    //關閉之前accept出來的和客戶端進行通訊的套接字 

                    socketServer.Close();

                    break;

                }

            }

        }

        private void button4_Click(object sender, EventArgs e)

        {

            if (ClientConnectionItems.Count > 0)

            {

                foreach (var socketTemp in ClientConnectionItems)

                {

                    for(int cnt =0; cnt < listBox1.SelectedItems.Count; cnt++)

                    {

                        foreach (var item in listBox1.SelectedItems)

                        {

                            if (item.ToString() == socketTemp.Key)

                            {

                                socketTemp.Value.Send(Encoding.UTF8.GetBytes("[Msg from server]:" + textBox2.Text));

                            }

                        }

                    }

                   

                }

            }


        }







        //建立1個客戶端套接字和1個負責監聽服務端請求的執行緒 

        Thread ThreadClient = null;

        Socket SocketClient = null;


        private void button2_Click(object sender, EventArgs e)

        {


            try

            {

                int port = 6000;

                //string host = "127.0.0.1";//伺服器端ip地址

                string host = textBox_target_ip.Text;


                IPAddress ip = IPAddress.Parse(host);

                IPEndPoint ipe = new IPEndPoint(ip, port);


                //定義一個套接字監聽 

                SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


                try

                {

                    //客戶端套接字連線到網路節點上,用的是Connect 

                    SocketClient.Connect(ipe);

                }

                catch (Exception)

                {

                    Console.WriteLine("連線失敗!\r\n");

                    Console.ReadLine();

                    return;

                }


                ThreadClient = new Thread(ClientRecv);

                ThreadClient.IsBackground = true;

                ThreadClient.Start();


                Thread.Sleep(1000);

                Console.WriteLine("請輸入內容<按Enter鍵傳送>:\r\n");

                while (true)

                {

                    string sendStr = Console.ReadLine();

                    ClientSendMsg(sendStr);

                }


                //int i = 1;

                //while (true)

                //{

                //  Console.Write("請輸入內容:");

                //  string sendStr = Console.ReadLine();


                //  Socket clientSocket = new Socket(AddressFamily.InterNetwork,ProtocolType.Tcp);

                //  clientSocket.Connect(ipe);

                //  //send message

                //  //byte[] sendBytes = Encoding.ASCII.GetBytes(sendStr);

                //  byte[] sendBytes = Encoding.GetEncoding("utf-8").GetBytes(sendStr);


                //  //Thread.Sleep(4000);


                //  clientSocket.Send(sendBytes);


                //  //receive message

                //  string recStr = ""; 

                //  byte[] recBytes = new byte[4096];

                //  int bytes = clientSocket.Receive(recBytes,recBytes.Length,0);

                //  //recStr += Encoding.ASCII.GetString(recBytes,bytes);

                //  recStr += Encoding.GetEncoding("utf-8").GetString(recBytes,bytes);

                //  Console.WriteLine(recStr);


                //  clientSocket.Close();

                //  if (i >= 100)

                //  {

                //    break;

                //  }

                //  i++;

                //}


                //Console.ReadLine();

                //return;


                //string result = String.Empty;


            }

            catch (Exception ex)

            {

                Console.WriteLine(ex.Message);

                Console.ReadLine();

            }

        }


        //接收服務端發來資訊的方法  

        public void ClientRecv()

        {

            int x = 0;

            //持續監聽服務端發來的訊息 

            while (true)

            {

                try

                {

                    //定義一個1M的記憶體緩衝區,用於臨時性儲存接收到的訊息 

                    byte[] arrRecvmsg = new byte[1024 * 1024];


                    //將客戶端套接字接收到的資料存入記憶體緩衝區,並獲取長度 

                    int length = SocketClient.Receive(arrRecvmsg);


                    //將套接字獲取到的字元陣列轉換為人可以看懂的字串 

                    string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg, 0, length);

                    if (x == 1)

                    {

                        string strTotalMsg = "\r\n伺服器:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "\r\n" + strRevMsg + "\r\n";

                        Console.WriteLine(strTotalMsg);

                        this.Invoke((MethodInvoker)delegate

                        {

                            lock (this.richTextBox2)

                                this.richTextBox2.AppendText(strTotalMsg);

                        });

                    }

                    else

                    {

                        string strTotalMsg = strRevMsg + "\r\n";


                        Console.WriteLine(strTotalMsg);

                        this.Invoke((MethodInvoker)delegate

                        {

                            lock (this.richTextBox2)

                                this.richTextBox2.AppendText(strTotalMsg);

                        });

                        x = 1;

                    }

                }

                catch (Exception ex)

                {

                    Console.WriteLine("遠端伺服器已經中斷連線!" + ex.Message + "\r\n");

                    break;

                }

            }

        }


        //傳送字元資訊到服務端的方法 

        public void ClientSendMsg(string sendMsg)

        {

            //將輸入的內容字串轉換為機器可以識別的位元組陣列   

            byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(sendMsg);

            //呼叫客戶端套接字傳送位元組陣列   

            SocketClient.Send(arrClientSendMsg);

        }


        private void button3_Click(object sender, EventArgs e)

        {

            ClientSendMsg(textBox1.Text);

        }

    }

}


沒有留言: