• 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}已成功连接到服务器
    ", 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}
    ", 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

    个人拙作,敬请谅解.

  • 相关阅读:
    leetcode — simplify-path
    leetcode — climbing-stairs
    leetcode — sqrtx
    leetcode — text-justification
    leetcode — add-binary
    leetcode — plus-one
    leetcode — valid-number
    leetcode — minimum-path-sum
    leetcode — unique-paths-ii
    四维偏序 CDQ套CDQ
  • 原文地址:https://www.cnblogs.com/rbzz/p/9152941.html
Copyright © 2020-2023  润新知