C#Winform實時更新數據庫信息Demo(使用Scoket)


最近在貼吧上看到有個提問就是關於怎么在Winform上實時的更新數據

提問者提到的是利用Timer去輪詢,但最后經過網上查了下資料,感覺Socket也是可行的,

於是就寫了這個Demo

這個Demo的思路很簡單:

有一個Socket服務端,只負責接收多個客戶端傳過來的訊息,根據訊息內容去判斷是否廣播

這里每一個winform窗體程序就是一個Socket客戶端,如果窗體上對數據庫做了更新(例如增,刪,改)操作

就會調用一個方法,該方法主要是向Socket服務端發送一個字符串"1"

當Socket服務端接收到了字符串為"1"時,則廣播給所有客戶端一個字符串"1"

而當客戶端接收到服務端傳過來一個"1"時,則立即執行數據綁定的方法(重新將界面的DataGridVeiw數據綁定)

這樣就實現了一有數據改變就實時刷新的效果

下面貼出各部分代碼

 

================服務端====================================================

服務端的界面,比較簡單

public partial class Server : Form
    {
        public Server()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 已連接上的客戶端集合
        /// </summary>
        List<Socket> clinetSockets;
        /// <summary>
        /// 服務端主Socket
        /// </summary>
        Socket socket;

        /// <summary>
        /// 設置數據緩沖區
        /// </summary>
        private byte[] result = new byte[1024];

        /// <summary>
        /// 開啟偵聽按鈕點擊事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            //初始化
            clinetSockets = new List<Socket>();
            //創建socket對象
             socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //獲取ip地址和端口(其實應該把它放在配置文件中,客戶端的ip和port都放在配置文件中)
            IPAddress ip = IPAddress.Parse(txtIPAddress.Text.Trim());
            int port = Convert.ToInt32(txtPort.Text.Trim());
            IPEndPoint point = new IPEndPoint(ip, port);

            //綁定ip和端口
            socket.Bind(point);
            //設置最大連接數
            socket.Listen(10);

            listBox1.Items.Add("服務器已開啟,等待客戶端連接中.....");

            //開啟新線程監聽
            Thread serverThread = new Thread(ListenClientConnect);
            serverThread.IsBackground = true;
            serverThread.Start(socket);

        }

        
        /// <summary>
        /// 監聽傳入
        /// </summary>
        /// <param name="ar"></param>
        private void ListenClientConnect(object ar)
        {
            //設置標志
            bool flag = true;
            //獲得服務器的Socket
            Socket serverSocket = ar as Socket;
            //輪詢
            while (flag)
            {
                //獲得連入的客戶端socket
                Socket clientSocket = serverSocket.Accept();
                //將新加入的客戶端加入列表中
                clinetSockets.Add(clientSocket);

                //向listbox中寫入消息
                listBox1.Invoke(new Action(() => {
                    listBox1.Items.Add(string.Format("客戶端{0}已成功連接到服務器\r\n", clientSocket.RemoteEndPoint));
                }));
                //開啟新的線程,進行監聽客戶端消息
                var mReveiveThread = new Thread(ReceiveClient);
                mReveiveThread.IsBackground = true;
                mReveiveThread.Start(clientSocket);
            }

        }
       
        /// <summary>
        /// 接收客戶端傳過來的數據
        /// </summary>
        /// <param name="obj"></param>
        private void ReceiveClient(object obj)
        {
            //獲取當前客戶端
            //因為每次發送消息的可能並不是同一個客戶端,所以需要使用var來實例化一個新的對象
            //可是我感覺這里用局部變量更好一點
            var mClientSocket = (Socket)obj;
            // 循環標志位
            bool flag = true;
            while (flag)
            {
                try
                {
                    //獲取數據長度
                    int receiveLength = mClientSocket.Receive(result);
                    //獲取客戶端消息
                    string clientMessage = Encoding.UTF8.GetString(result, 0, receiveLength);
                    //服務端負責將客戶端的消息分發給各個客戶端
                    //判斷客戶端發來的消息是否是預定的標志
                    if (clientMessage=="1")
                    {
                        //通知各客戶端
                        this.SendMessage("1");
                    }

                    //向listbox中寫入消息
                    listBox1.Invoke(new Action(() => {
                        listBox1.Items.Add(string.Format("客戶端{0}發來消息{1}", mClientSocket.RemoteEndPoint, clientMessage));
                    }));

                }
                catch(Exception e)
                {
                    //從客戶端列表中移除該客戶端
                    clinetSockets.Remove(mClientSocket);
                    
                    //顯示客戶端下線消息
                    listBox1.Invoke(new Action(() =>
                    {
                        listBox1.Items.Add(string.Format("服務器發來消息:客戶端{0}從服務器斷開,斷開原因:{1}\r\n", mClientSocket.RemoteEndPoint, e.Message));
                    }));

                    //斷開連接
                    mClientSocket.Shutdown(SocketShutdown.Both);
                    mClientSocket.Close();
                    break;
                }
            }
        }

        /// <summary>
        /// 向所有的客戶端群發消息
        /// </summary>
        /// <param name="msg">message</param>
        public void SendMessage(string msg)
        {
            //確保消息非空以及客戶端列表非空
            if (msg == string.Empty || clinetSockets.Count <= 0) return;
            //向每一個客戶端發送消息
            foreach (Socket s in this.clinetSockets)
            {
                (s as Socket).Send(Encoding.UTF8.GetBytes(msg));
            }
        }

        /// <summary>
        /// 窗體關閉后釋放資源
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Server_FormClosing(object sender, FormClosingEventArgs e)
        {
            
        }
    }

 

======================================客戶端=================================

public partial class Clinet : Form
    {
        public Clinet()
        {
            InitializeComponent();
        }

        //創建數據對象
        Data get = new 客戶端.Data();

        /// <summary>
        /// 客戶端的Socket
        /// </summary>
        Socket clinet;

        private void Clinet_Load(object sender, EventArgs e)
        {
            RefTable();
            //創建socket
            CreateSocket();
        }

        /// <summary>
        /// 創建客戶端的Socket
        /// </summary>
        private void CreateSocket()
        {
            // 創建socket
            clinet = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //連接
            //獲得ip和端口(讀取配置文件)
            var app = System.Configuration.ConfigurationManager.AppSettings;
            IPEndPoint point = new IPEndPoint(IPAddress.Parse(app["ip"]), Convert.ToInt32(app["port"]));

            //連接服務器
            clinet.Connect(point);

            //開啟新線程獲取服務器端消息
            Thread thClinet = new Thread(new ThreadStart(CallRec));
            thClinet.IsBackground = true;
            thClinet.Start();
        }

        /// <summary>
        /// 接收消息
        /// </summary>
        private void CallRec()
        {
            bool flag = true;
            while (flag)
            {
                byte[] recBuf = new byte[1024];
                //獲取返回數據的長度
                int length = clinet.Receive(recBuf);
                //獲取監聽到的數據
                string reslut = Encoding.UTF8.GetString(recBuf, 0, length);

                if (reslut == "1")
                {
                    //刷新表格數據
                    RefTable();
                }
            }
        }

        /// <summary>
        /// 刷新表格
        /// </summary>
        private void RefTable()
        {
            dataGridView1.Invoke(new Action(() =>
            {
                dataGridView1.DataSource = get.GetPersonList();
            }));
            
        }

        /// <summary>
        /// 添加數據事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAdd_Click(object sender, EventArgs e)
        {
            //獲取用戶輸入
            string name = txtAddName.Text;
            int age = Convert.ToInt32(txtAgeAdd.Text);
            string phone = txtPhoneAdd.Text;

            //實例化一個數據對象
            Person p = new Person() { Name = name, Age = age, Phone = phone };
            //寫入數據
            AddList(p);
        }

        /// <summary>
        /// 寫入數據
        /// </summary>
        /// <param name="p"></param>
        private void AddList(Person p)
        {
            //獲取數據集合
            List<Person> list = dataGridView1.DataSource as List<Person>;
            //加入數據
            list.Add(p);
            //加入數據
            bool b = get.Add(list);
            if (b)
            {
                MessageBox.Show("增加成功");
                //增加成功后發送socket信息
                //向服務器發送消息
                clinet.Send(Encoding.UTF8.GetBytes("1"));
            }
            else
            {
                MessageBox.Show("增加失敗");
            }
        }
       

        private void Clinet_FormClosing(object sender, FormClosingEventArgs e)
        {
           
        }
    }

客戶端是讀取的本地Json數據創建的對象集合用以模擬數據庫

class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Phone { get; set; }
    }
 class Data
    {
        System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer();
        public List<Person> GetPersonList()
        {
            //讀取json數據
            string jsonStr = File.ReadAllText("Data.json");
            
            List<Person> list = js.Deserialize<List<Person>>(jsonStr);
            return list;
        }

        public bool Add(List<Person> list)
        {
            //向數據中覆蓋追加
            string strJson = js.Serialize(list);
            try
            {
                File.WriteAllText("Data.json", strJson);
                return true;
            }
            catch
            {

                return false;
            }
           
        }
    }

Data.json數據

[
  {
    "name": "張三",
    "age": 14,
    "phone": "13888888888"
  },
  {
    "name": "張三",
    "age": 14,
    "phone": "13888888888"
  },
  {
    "name": "張三",
    "age": 14,
    "phone": "13888888888"
  },
  {
    "name": "張三",
    "age": 14,
    "phone": "13888888888"
  },
  {
    "name": "張三",
    "age": 14,
    "phone": "13888888888"
  },
  {
    "name": "張三",
    "age": 14,
    "phone": "13888888888"
  },
  {
    "name": "張三",
    "age": 14,
    "phone": "13888888888"
  }
]

====================================運行效果圖==============================

 

=========================================分割線==================================

 

其實個人覺得可以把服務端做成一個Windows服務更好

 

代碼打包地址(內含windows服務代碼)

關於如何將windows服務如何安裝到服務中,網上教程很多,請自行百度

https://pan.baidu.com/s/1J6SIGxwzzvG-B1ACyDWPKw

 

個人拙作,敬請諒解.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM