C#Winform实时更新数据库信息Demo(使用Scoket)

最近在贴吧上看到有个提问就是关于怎么在Winform上实时的更新数据数据库

提问者提到的是利用Timer去轮询,但最后通过网上查了下资料,感受Socket也是可行的,json

因而就写了这个Demowindows

这个Demo的思路很简单:服务器

有一个Socket服务端,只负责接收多个客户端传过来的讯息,根据讯息内容去判断是否广播app

这里每个winform窗体程序就是一个Socket客户端,若是窗体上对数据库作了更新(例如增,删,改)操做socket

就会调用一个方法,该方法主要是向Socket服务端发送一个字符串"1"this

当Socket服务端接收到了字符串为"1"时,则广播给全部客户端一个字符串"1"spa

而当客户端接收到服务端传过来一个"1"时,则当即执行数据绑定的方法(从新将界面的DataGridVeiw数据绑定)线程

这样就实现了一有数据改变就实时刷新的效果code

下面贴出各部分代码

 

================服务端====================================================

服务端的界面,比较简单

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

 

我的拙做,敬请谅解.

相关文章
相关标签/搜索