close

不得不承認,寫的又臭又長的,又不好理解。

====ServerSocket.cs====

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;//for Thread
using System.Threading.Tasks;
using System.Net;//for IPEndPoint
using System.Net.Sockets;//for Socket
using System.Windows.Forms;//for MessageBox


namespace HelloServerSocket
{

    public class TServerSocket
    {
        //----宣告委派----
        public delegate void SynchronizeMethod();//萬用委派函式
        public delegate void _OnRead(object sender, byte[] buf, int len);//收到訊息的委派函式
        public delegate void _OnError(object sender, Socket socket, int ErrorCode);//收到訊息的委派函式
        public delegate void _OnConnect(object sender, Socket socket);//收到訊息的委派函式
        public delegate void _OnDisconnect(object sender, Socket socket);//收到訊息的委派函式

        //使用Invoke 呼叫萬用委派函式
        public void Synchronize(SynchronizeMethod Method)
        {
            while (!Owner.InvokeRequired) ;
            Owner.Invoke(Method);
        }

        //其他地方不會用到,因此用巢式class
        public class TConnection
        {
            public Socket Socket;

            //聽訊息用
            public Thread thread;
            //離開執行序用
            private bool bStop = false;
            //跟著釋放
            private Form Owner;


            
            //我的收到訊息的事件
            /// <summary>
            /// 實做public void OnRead(object sender, byte[] buf, int len)函式,並帶入TClientSocket.OnRead。
            /// </summary>
            public _OnRead OnRead = null;

            /// <summary>
            /// 實做public void OnError(object sender, Socket socket, int ErrorCode)函式,並帶入TClientSocket.OnError。
            /// </summary>            
            public _OnError OnError = null;

            public _OnDisconnect OnDisconnect = null;

            //建構子
            public TConnection(Form Owner, Socket s)
            {
                Socket = s;
                
                //會跟著釋放
                this.Owner = Owner;
                if (Owner == null)
                {
                    MessageBox.Show("Owner 不可為空值");
                }
            }

            private byte[] tmp_buf = null;
            private int tmp_len = 0;

            //聽訊息(執行序內的程式)
            private void Listent()
            {
                
                while (true)
                {
                    //降CPU Load用
                    Thread.Sleep(1);                    
                    //如果有代入事件,就觸發
                    if (OnRead != null)
                    {

                        /*
                        int len = Socket.Available;//取得Receive Size
                        if(len>0)
                        {
                            byte[] buf=new byte[len];
                            Socket.Receive(buf);
                        }
                        //這個方法可行,但就沒辦法知道斷線,不然原本我想就直接丟Socket回去OnRead。
                        */

                        //值接帶buf去接
                        byte[] buf=new byte[1024];
                        int len = Socket.Receive(buf);//當沒有資料時,會一直停在這裡,但斷線時會回傳0。
                        tmp_buf = buf;
                        tmp_len = len;
                        if (len == 0) break;
                        Synchronize(Sync_Read);
                    }
                    if (bStop) break;
                    if (Owner.Disposing) break;
                }
                //不斷線就關閉程式,BCB伺服端會出現ErrorCode:10053
                if (OnDisconnect != null) Synchronize(Sync_Disconnect);
                if (!Socket.Connected)
                {                    
                    Socket.Shutdown(SocketShutdown.Both);
                    Socket.Disconnect(true);
                    Socket.Close();
                }
                Socket = null;
                
            }

            //避免代入程式有使用到可視元件,使用Invoke呼叫委派函式
            void Sync_Disconnect()
            {
                OnDisconnect(this, Socket);
            }

            //避免代入程式有使用到可視元件,使用Invoke呼叫委派函式
            void Sync_Read()
            {
                OnRead(this, tmp_buf, tmp_len);
            }

            //使用Invoke 呼叫萬用委派函式
            public void Synchronize(SynchronizeMethod Method)
            {
                while (!Owner.InvokeRequired);
                Owner.Invoke(Method);
            }

            public void Connect()
            {
                thread = new Thread(Listent);
                thread.Start();
            }

            public void Disconnect()
            {
                bStop = true;
            }
        }//end class TConnect

        public List<TConnection> Connections=new List<TConnection>();
        
        public int Port=8888;
        private Form Owner;
        private Socket FSocket = null;

        //----宣告委派----
        public _OnRead OnRead = null;
        public _OnError OnError = null;        
        public _OnConnect OnConnect = null;
        public _OnDisconnect OnDisconnect = null;

        private Socket tmp_socket;
        private int tmp_error;

        //執行序,等待連線用
        private Thread thread = null;
        //離開執行序用
        private bool bStop = false;

        
       
        //建構子
        public TServerSocket(Form Owner)
        {
            //會跟著釋放
            this.Owner = Owner;
            if (Owner == null)
            {
                MessageBox.Show("Owner 不可為空值");
            }
            FSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            FSocket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), Port));
            FSocket.Listen(100);//最大連線數
        }

        //Server On
        public void Active()
        {
            //建立執行序
            thread = new Thread(WaitAccept);//帶入等待連線函式
            thread.Start();//開始執行序
        }

        //Server On(多載)
        public void Active(int port)
        {
            Port = port;
            Active();
        }

        //Server Off
        public void Deactive()
        {   
            FSocket.Close();
            bStop = true;
        }

        //等待連線
        private void WaitAccept()
        {
            while (true)
            {
                //Client
                Socket ClientSocket = null;
                try
                {
                    ClientSocket = FSocket.Accept();
                    if (OnConnect != null)
                    {
                        if (ClientSocket.Connected)
                        {
                            tmp_socket = ClientSocket;
                            Synchronize(Sync_Connect);
                        }
                    }
                    TConnection conn = new TConnection(Owner, ClientSocket);
                    conn.OnError = this.OnError;
                    conn.OnRead = this.OnRead;
                    conn.OnDisconnect = this.OnDisconnect;
                    Connections.Add(conn);
                    conn.Connect();
                }
                catch (SocketException e)
                {
                    //FSocket.Accept()中。
                    //FSocket.Close()時,所造成的錯誤。
                    if (e.ErrorCode == 10004) break;

                    if (OnError != null)
                    {
                        tmp_socket = ClientSocket;
                        tmp_error = e.ErrorCode;
                        Synchronize(Sync_Error);
                    }
                }
                if (bStop) break;
            }
            foreach (TConnection conn in Connections)
            {
                conn.Disconnect();
            }
        }

        public void Sync_Connect()
        {
            OnConnect(this, tmp_socket);
        }

        public void Sync_Error()
        {
            OnError(this, tmp_socket, tmp_error);
        }

        //傳送訊息
        public void SendText(String Text)
        {
            foreach (TConnection conn in Connections)
            {
                if (conn == null) continue;
                Byte[] bytesSend = Encoding.ASCII.GetBytes(Text);
                conn.Socket.Send(bytesSend, bytesSend.Length, 0);
            }
        }

    }//end class
}//end namespace
 

 

====Form1.cs====

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;

namespace HelloServerSocket
{
    public partial class Form1 : Form
    {
        public TServerSocket ServerSocket;
        
        public Form1()
        {
            InitializeComponent();
            ServerSocket = new TServerSocket(this);
            ServerSocket.OnConnect = ClientConnect;
            ServerSocket.OnError = ClientError;
            ServerSocket.OnRead = ClientRead;
            ServerSocket.OnDisconnect = ClientDisconnect;
            ServerSocket.Active();
        }

        public void ClientDisconnect(object sender, Socket socket)
        {
            textBox1.AppendText("Client Disconnect.\r\n");
        }
        public void ClientConnect(object sender, Socket socket)
        {
            textBox1.AppendText("Client Connect.\r\n");
        }
        public void ClientError(object sender, Socket socket, int ErrorCode)
        {
            textBox1.AppendText("Client Error:"+ErrorCode.ToString()+"\r\n");
        }
        public void ClientRead(object sender, byte[] buf, int len)
        {            
            String msg = Encoding.ASCII.GetString(buf,0,len);
            {
                textBox1.AppendText(msg + "\r\n");
            }
            for (int i = 0; i < ServerSocket.Connections.Count; i++)
            {
                ServerSocket.Connections[i].Socket.Send(buf,len,0);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            ServerSocket.Deactive();
        }
    }
}
 

arrow
arrow
    文章標籤
    程式語言
    全站熱搜

    史克威爾凱特 發表在 痞客邦 留言(1) 人氣()