场景
Winform中使用Websocket4Net实现Websocket客户端并定时存储接收数据到SQLite中:
Winform中使用Websocket4Net实现Websocket客户端并定时存储接收数据到SQLite中-CSDN博客
Winform中操作Sqlite数据增删改查、程序启动时执行创建表初始化操作:
Winform中操作Sqlite数据增删改查、程序启动时执行创建表初始化操作_winform sqllite-CSDN博客
在上面实现Websocket客户端的基础上,如何实现Websocket服务端,并实现定时给所有的客户端群发消息。
群发的消息从SQLite中读取,循环进行群发。
注:
博客:
霸道流氓气质_C#,架构之路,SpringBoot-CSDN博客
实现
1、Fleck
GitHub - statianzo/Fleck: C# Websocket Implementation
新建Winform项目,并使用Nuget引入依赖
搜索Fleck
按照官网说明,快速实现Websocket服务端只需要
var server = new WebSocketServer("ws://0.0.0.0:8181");
server.Start(socket =>
{
socket.OnOpen = () => Console.WriteLine("Open!");
socket.OnClose = () => Console.WriteLine("Close!");
socket.OnMessage = message => socket.Send(message);
});
并且官方提供了一些示例demo,比如群发消息的实现,这里是在控制台项目中的示例
var allSockets = new List<IWebSocketConnection>();
var server = new WebSocketServer("ws://0.0.0.0:8181");
server.Start(socket =>
{
socket.OnOpen = () =>
{
Console.WriteLine("Open!");
allSockets.Add(socket);
};
socket.OnClose = () =>
{
Console.WriteLine("Close!");
allSockets.Remove(socket);
};
socket.OnMessage = message =>
{
Console.WriteLine(message);
allSockets.ToList().ForEach(s => s.Send("Echo: " + message));
};
});
demo位置
2、这里基于Winform设计窗体布局如下
3、启动服务端/开始监听按钮点击事件
新建WebSocketServer服务端对象,便于停止监听
public WebSocketServer wsServer= null;
新建一个list用来存储所有的客户端连接信息
private List<IWebSocketConnection> allSockets = new List<IWebSocketConnection>();
然后在开始监听按钮的点击事件中
private void button_start_listen_Click(object sender, EventArgs e)
{
try
{
allSockets.Clear();
string wsAddress = textBox_server_address.Text.Trim();
wsServer = new WebSocketServer(wsAddress); //创建webscoket服务端实例
wsServer.Start(socket => {
socket.OnOpen = () =>
{
//Console.WriteLine("Open");
allSockets.Add(socket);
};
socket.OnClose = () =>
{
//Console.WriteLine("Close");
allSockets.Remove(socket);
};
socket.OnMessage = message => {
//Console.WriteLine(message);
};
socket.OnError = message =>
{
//Console.WriteLine(message);
};
});
textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":监听成功");
textBox_log.AppendText("\r\n");
}
catch (Exception exception)
{
textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":监听异常:" + exception.Message);
textBox_log.AppendText("\r\n");
}
}
在建立连接和关闭事件中分别对客户端的list进行添加和删除。
4、停止监听的按钮点击事件中
遍历所有客户端的list,循环进行关闭,并销毁服务端对象
private void button_stop_listen_Click(object sender, EventArgs e)
{
allSockets.ToList().ForEach(s => s.Close());
wsServer.Dispose();
textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":监听停止");
textBox_log.AppendText("\r\n");
}
5、单次群发按钮点击事件
private void button_single_mass_Click(object sender, EventArgs e)
{
if (null != wsServer)
{
string message = textBox_message.Text.Trim();
allSockets.ToList().ForEach(s => {
if (s.IsAvailable)
{
s.Send(message);
}
});
}
else {
textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":wsServer未启动");
textBox_log.AppendText("\r\n");
}
}
判断服务端对象不为空,遍历所有客户端list,判断如果可用则调用send方法,发送string类型的消息。
6、加载数据按钮实现
用来从SQLite中读取需要循环群发的消息内容
首先声明string的list用来存储加载的数据
private List<string> loadDataList = new List<string>();
然后按钮的点击事件中
private void button_load_data_Click(object sender, EventArgs e)
{
try
{
if (null == wsServer)
{
textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":wsServer未启动");
textBox_log.AppendText("\r\n");
}
else
{
loadDataList.Clear();
SQLiteDataReader reader = Global.Instance.sqlLiteHelper.ExecuteQuery("SELECT* FROM positions;");
if (reader.HasRows)
{
while (reader.Read())
{
string data = reader.GetString(reader.GetOrdinal("data"));
loadDataList.Add(data);
}
}
textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":加载数据完成,共("+ loadDataList.Count+")条。");
textBox_log.AppendText("\r\n");
}
}
catch (Exception exception)
{
textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":加载数据异常:" + exception.Message);
textBox_log.AppendText("\r\n");
}
}
7、定时群发实现
首先新建定时器以及加载的数据的索引
Timer _timerMass = new Timer();
private int index = 0;
定时群发按钮点击事件实现
private void button_start_mass_Click(object sender, EventArgs e)
{
if (null == wsServer) {
textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":wsServer未启动");
textBox_log.AppendText("\r\n");
} else {
_timerMass.Interval = (int)numericUpDown_mass.Value;
_timerMass.Tick += _timer_Tick_Mass;
_timerMass.Start();
textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":定时群发已经启动!!");
textBox_log.AppendText("\r\n");
}
}
定时器执行方法具体实现
private void _timer_Tick_Mass(object sender, EventArgs e)
{
if (loadDataList.Count>0) {
if (index > loadDataList.Count - 1)
{
index = 0;
}
string data = loadDataList[index];
allSockets.ToList().ForEach(s => {
if (s.IsAvailable) {
s.Send(data);
}
});
index++;
}
}
8、停止定时群发按钮点击事件实现
private void button_stop_mass_Click(object sender, EventArgs e)
{
//停止定时器
_timerMass.Tick -= _timer_Tick_Mass;
_timerMass.Stop();
textBox_log.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":定时群发已经停止!!!");
textBox_log.AppendText("\r\n");
index = 0;
}