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[]; /// <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(); 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, , receiveLength);
//服务端负责将客户端的消息分发给各个客户端
//判断客户端发来的消息是否是预定的标志
if (clientMessage=="")
{
//通知各客户端
this.SendMessage("");
} //向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 <= ) 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[];
//获取返回数据的长度
int length = clinet.Receive(recBuf);
//获取监听到的数据
string reslut = Encoding.UTF8.GetString(recBuf, , length); if (reslut == "")
{
//刷新表格数据
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(""));
}
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": ,
"phone": ""
},
{
"name": "张三",
"age": ,
"phone": ""
},
{
"name": "张三",
"age": ,
"phone": ""
},
{
"name": "张三",
"age": ,
"phone": ""
},
{
"name": "张三",
"age": ,
"phone": ""
},
{
"name": "张三",
"age": ,
"phone": ""
},
{
"name": "张三",
"age": ,
"phone": ""
}
]
====================================运行效果图==============================

=========================================分割线==================================
其实个人觉得可以把服务端做成一个Windows服务更好
代码打包地址(内含windows服务代码)
关于如何将windows服务如何安装到服务中,网上教程很多,请自行百度
https://pan.baidu.com/s/1J6SIGxwzzvG-B1ACyDWPKw
个人拙作,敬请谅解.
C#Winform实时更新数据库信息Demo(使用Scoket)的更多相关文章
- 自己主动化測试使用mybatis更新数据库信息实例
代码例如以下: mybatis配置文件: <? xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ...
- C# winform自动更新 (附 demo下载)
随着需求的变化,如果Server每次更新出新的内容,Client都要重新安装的话. 太过于复杂化. 所以自动更新是很有必要的. 一..NET自带的更新方式 以服务器端为主 (自动更新,微软爸 ...
- 第十二章——SQLServer统计信息(1)——创建和更新统计信息
原文:第十二章--SQLServer统计信息(1)--创建和更新统计信息 简介: 查询的统计信息: 目前为止,已经介绍了选择索引.维护索引.如果有合适的索引并实时更新统计信息,那么优化器会选择有用的索 ...
- 与find不同,locate并不是实时查找。你需要更新数据库,以获得最新的文件索引信息。updatedb
find是实时查找,如果需要更快的查询,可试试locate:locate会为文件系统建立索引数据库,如果有文件更新,需要定期执行更新命令来更新索引库: $locate string 寻找包含有stri ...
- SharePoint 2013 数据库中手动更新用户信息
在SharePoint的使用过程中,尤其是Windows认证的情况下,而且没有配置用户配置文件服务,经常会出现如果更新AD中的用户信息(包括名字.显示名.邮件等),SharePoint这边站点并不会更 ...
- HTML5 WebSocket 实时推送信息测试demo
测试一下HTML5的websocket功能,实现了客户端→服务器实时推送信息到客户端,包括推送图片: websocket实现MessageInbound类 onTextMessage()/onBina ...
- 使用hibernate更新数据库记录的信息的相关学习记录
截选代码(可能遗漏标点符号): package name.sql; import java.util.List; import name.session.HibernateSessionFactory ...
- JDBC连接(MySql)数据库步骤,以及查询、插入、删除、更新等十一个处理数据库信息的功能
主要内容: JDBC连接数据库步骤. 一个简单详细的查询数据的例子. 封装连接数据库,释放数据库连接方法. 实现查询,插入,删除,更新等十一个处理数据库信息的功能.(包括事务处理,批量更新等) 把十 ...
- python---django中form组件(2)自定制属性以及表单的各种验证,以及数据源的实时更新,以及和数据库关联使用ModelForm和元类
自定义属性以及各种验证 分析widget: class TestForm(forms.Form): user = fields.CharField( required = True, widget = ...
随机推荐
- python网络编程--粘包解决方案 和 subprocess模块
1.缓冲区:作用:将程序和网络解耦分为输入缓冲区, 输出缓冲区 每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区.write()/send() 并不立即向网络中传输数据,而是先 ...
- C# Winform下一个热插拔的MIS/MRP/ERP框架16(窗体基类场景2)
如果没有特别需求,和场景1一样只变更表名,主键字段,检测字段等名称,不需要写其它代码了. * 清单列表+单笔编辑/保存,适用于大多数基础资料管理以及简单的单据资料录入(当然,排版是要改一改的): * ...
- python基础目录
一.博客链接 1.基础操作 python基础,变量,if语句 while循环/格式化输出/ 逻辑运算/ 编码 /单位转换 列表的操作,元组,range; enumerate dict字典;dict的操 ...
- SpringMvc HttpMessageConverter之@ResponseBody
我们先看HttpMessageConverter的示意图,从图片可以看出它是多么的重要.在一条必经之路截道了的感觉. 先上我的测试例子: jsp页面: <%@ page language=&qu ...
- HTML5基础实例(三)
不知道从哪说起那就一段一段代码的说吧 实例一:iframe框架显示 写一个这样的网页: 分析: 1.需要三个链接,一个是默认的百度链接,默认显示在那个框里,另外:两个是点击跳转的超链接. 2.需要if ...
- Oracle中ROWNUM的使用技巧
ROWNUM是一种伪列,它会根据返回记录生成一个序列化的数字.利用ROWNUM,我们可以生产一些原先难以实现的结果输出,但因为它是伪列的这个特殊性,我们在使用时也需要注意一些事项,不要掉入“陷阱”.下 ...
- 2016级算法期末模拟练习赛-B.AlvinZH的青春记忆I
1083 AlvinZH的青春记忆I 思路 中等题,动态规划. 简化题意,一个环上取数,数不可相邻,取取得数之和最大值. 环不好表示,可以解开变成一列数,那么答案应为下列两种情况较大者. ①:取第一个 ...
- vim中常用的命令
1.光标的命令 gg 移到第一行位置 G 移到最后一行 o 行首 $ 行末 nk 向上移动n行 nj 向下移动n行 nh 向左移动n列 nl 向右移动n列 ctrl+f ...
- mariadb配置主从同步遇到的问题
一:ERROR: No query specified 解决方案: \G后面不能再加分号;,因为\G在功能上等同于;,如果加了分号,那么就是;;(2个分号),SQL语法错误 二:主从同步不成功 Sla ...
- C# 委托的一些使用上的小技巧
1.委托是一种数据类型,我们可以在任何定义类的地方定义委托,在任何声明类的地方声明委托 2.初始化委托有两种方式,代码如下: (1).像类一样初始化委托 public delegate void Sa ...