web端代碼就是js代碼,C#有兩種方式:使用第三方庫,如Fleck,使用C#原生socket編程實現(xiàn)
1、web端代碼:
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>下發(fā)網(wǎng)站上文件到學(xué)生機</title>
<script type="text/javascript">
function callDesktopReceiveFile(button) {
var ws = null;
if (button.innerHTML == '下發(fā)') {
button.innerHTML = '取消';
try {
if (ws) ws.close();
} catch(e) {
console.log(e)
}
ws = new WebSocket('ws://127.0.0.1:14567');
//監(jiān)聽是否連接成功
ws.onopen = function () {
console.log('ws連接狀態(tài)[成功]:' + ws.readyState);
ws.send("content:receiveFile;url:http://127.0.0.1:5500/2023CQGKMNT.dat;");
// ws.close();
console.log('發(fā)送消息');
};
// 接聽服務(wù)器發(fā)回的信息并處理展示
ws.onmessage = function (e) {
console.log('接收到來自服務(wù)器的消息:' + e.data);
// 如果服務(wù)器在業(yè)務(wù)上主動關(guān)閉連接,則此處無需再關(guān)閉
// if (e.data === 'roger') {
// ws.close();
// }
};
// 監(jiān)聽連接關(guān)閉事件
ws.onclose = function () {
// 監(jiān)聽整個過程中websocket的狀態(tài)
console.log('ws連接狀態(tài)[關(guān)閉]:' + ws.readyState);
};
// 監(jiān)聽并處理error事件
ws.onerror = function (error) {
console.log(error);
};
} else if (button.innerHTML == '取消') {
try {
if (ws) ws.close();
} catch(e) {
console.log(e)
}
button.innerHTML = '下發(fā)';
}
}
</script>
</head>
<body>
<div>
<table border="1" cellspacing="0">
<tr>
<th>試卷號</th>
<th>試卷名稱</th>
<th>描述</th>
<th>操作</th>
</tr>
<tr>
<td>JCLX01</td>
<td>基礎(chǔ)練習(xí)一</td>
<td>建賬、會計期間設(shè)置、部門職員設(shè)置、銀行賬戶設(shè)置、科目設(shè)置等</td>
<td><button id="btnDownload" onclick="callDesktopReceiveFile(this)">下發(fā)</button></td>
</tr>
<tr>
<td>JCLX02</td>
<td>基礎(chǔ)練習(xí)二</td>
<td>建賬、會計期間設(shè)置、部門職員設(shè)置、銀行賬戶設(shè)置、科目設(shè)置等</td>
<td><button id="btnDownload" onclick="callDesktopReceiveFile(this)">下發(fā)</button></td>
</tr>
</table>
</div>
</body>
</html>
2、C#端代碼
方式一:使用第三方庫Fleck
參考:chanpinxue.cn/archives/979.html
方式二:使用C#原生socket編程自行實現(xiàn)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using U8FileTransfer.TcpHelper;
using System.Net.Sockets;
using System.Net;
using System.Security.Cryptography;
namespace CodeExperiment
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Thread thread = new Thread(websocketListen);
thread.IsBackground = true;
thread.Start();
}
/// <summary>
/// 解析客戶端數(shù)據(jù)包,防止亂碼
/// </summary>
/// <param name="recBytes">服務(wù)器接收的數(shù)據(jù)包</param>
/// <param name="recByteLength">有效數(shù)據(jù)長度</param>
/// <returns></returns>
private static string AnalyticData(byte[] recBytes, int recByteLength)
{
if (recByteLength < 2) { return string.Empty; }
bool fin = (recBytes[0] & 0x80) == 0x80; // 1bit,1表示最后一幀
if (!fin)
{
return string.Empty;// 超過一幀暫不處理
}
bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩碼
if (!mask_flag)
{
return string.Empty;// 不包含掩碼的暫不處理
}
int payload_len = recBytes[1] & 0x7F; // 數(shù)據(jù)長度
byte[] masks = new byte[4];
byte[] payload_data;
if (payload_len == 126)
{
Array.Copy(recBytes, 4, masks, 0, 4);
payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]);
payload_data = new byte[payload_len];
Array.Copy(recBytes, 8, payload_data, 0, payload_len);
}
else if (payload_len == 127)
{
Array.Copy(recBytes, 10, masks, 0, 4);
byte[] uInt64Bytes = new byte[8];
for (int i = 0; i < 8; i++)
{
uInt64Bytes[i] = recBytes[9 - i];
}
UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0);
payload_data = new byte[len];
for (UInt64 i = 0; i < len; i++)
{
payload_data[i] = recBytes[i + 14];
}
}
else
{
Array.Copy(recBytes, 2, masks, 0, 4);
payload_data = new byte[payload_len];
Array.Copy(recBytes, 6, payload_data, 0, payload_len);
}
for (var i = 0; i < payload_len; i++)
{
payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]);
}
return Encoding.UTF8.GetString(payload_data);
}
/// <summary>
/// 打包服務(wù)器數(shù)據(jù),防止亂碼
/// </summary>
/// <param name="message">數(shù)據(jù)</param>
/// <returns>數(shù)據(jù)包</returns>
private static byte[] PackData(string message)
{
byte[] contentBytes = null;
byte[] temp = Encoding.UTF8.GetBytes(message);
if (temp.Length < 126)
{
contentBytes = new byte[temp.Length + 2];
contentBytes[0] = 0x81;
contentBytes[1] = (byte)temp.Length;
Array.Copy(temp, 0, contentBytes, 2, temp.Length);
}
else if (temp.Length < 0xFFFF)
{
contentBytes = new byte[temp.Length + 4];
contentBytes[0] = 0x81;
contentBytes[1] = 126;
contentBytes[2] = (byte)(temp.Length & 0xFF);
contentBytes[3] = (byte)(temp.Length >> 8 & 0xFF);
Array.Copy(temp, 0, contentBytes, 4, temp.Length);
}
else
{
// 暫不處理超長內(nèi)容
}
return contentBytes;
}
/// <summary>
/// 客戶端消息結(jié)構(gòu)化
/// message參數(shù)格式為多個key:value鍵值對通過分號拼接組成,示例:
/// content:download_and_send;file-url:https://www.a.com/a.zip;
///
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
private Dictionary<string, string> ProcessRemoteMessage(string message)
{
Dictionary<string, string> dic = new Dictionary<string, string>();
if (message.Substring(message.Length - 1, 1) == ";")
{
message = message.Substring(0, message.Length - 1);
}
string[] strs = message.Split(';');
if (strs.Length > 0)
{
Console.WriteLine("- - - - - - - - - - - - - - - - - - -");
foreach (string s in strs)
{
Console.WriteLine(s);
string[] split = s.Split(new char[] { ':' }, 2);
Console.WriteLine("[" + split[0] + "][" + split[1] + "]");
dic.Add(split[0], split[1]);
}
Console.WriteLine("- - - - - - - - - - - - - - - - - - -");
}
return dic;
}
private void websocketListen()
{
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
EndPoint endPoint = new IPEndPoint(IPAddress.Any, 14567);//監(jiān)聽端口
server.Bind(endPoint);
server.Listen(10); // 排隊等待連接最大數(shù)量10
// 監(jiān)聽多個客戶端連接
while (true)
{
Socket client = server.Accept();
Console.WriteLine("有客戶端連上來了");
//接收客戶端發(fā)來的HTTP-Header消息
byte[] bytes = new byte[1024];
int len = client.Receive(bytes);
string strMessage = Encoding.UTF8.GetString(bytes, 0, len);
Console.WriteLine(strMessage);
//獲取Sec-WebSocket-Key,為握手做準(zhǔn)備
string[] strings = strMessage.Split('\n');
string strSecWebSocketKey = "";
foreach (var item in strings)
{
string[] strings1 = item.Split(':');
if (strings1[0] == "Sec-WebSocket-Key")
{
strSecWebSocketKey = strings1[1].Trim();
}
}
//生成服務(wù)端Sec-WebSocket-Accept,迎合客戶端的握手請求
byte[] secKeyBytes = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(strSecWebSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
string secKey = Convert.ToBase64String(secKeyBytes);
// 發(fā)送給客戶端完成握手(會觸發(fā)Websocket的open()回調(diào)函數(shù)),針對websocket必須使用以下header
string strHeader = "";
strHeader += "HTTP/1.1 101 Switching Protocols" + Environment.NewLine;
strHeader += "Upgrade: websocket" + Environment.NewLine;
strHeader += "Connection: Upgrade" + Environment.NewLine;
strHeader += "Sec-WebSocket-Accept: " + secKey + Environment.NewLine + Environment.NewLine;
client.Send(Encoding.UTF8.GetBytes(strHeader));
string remoteFileUrl = null;
bool clientClose = false;
// 循環(huán)接收websocket發(fā)來的消息實現(xiàn)雙方交流
while (!clientClose)
{
//接收客戶端發(fā)來的消息
byte[] bytes2 = new byte[1024];
int len2 = client.Receive(bytes2);
string strMessage2 = AnalyticData(bytes2, len2);
if (strMessage2.Length > 0)
{
Console.WriteLine("客戶端發(fā)來消息:{0}", strMessage2);
Dictionary<string, string> messageDic = ProcessRemoteMessage(strMessage2);
string content = null;
messageDic.TryGetValue("content", out content);
Console.WriteLine("message content:" + content);
if (content == "receiveFile")
{
messageDic.TryGetValue("url", out remoteFileUrl);
client.Send(PackData("roger"));
Console.WriteLine("remoteFileUrl: " + remoteFileUrl);
Console.WriteLine("to do invoke download.");
// 關(guān)閉連接
client.Shutdown(SocketShutdown.Both);
client.Close();
clientClose = true;
}
}
else
{
Console.WriteLine("客戶端關(guān)閉了連接");
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}
}
}
}
}
通信雙方都可以主動關(guān)閉連接,不管誰關(guān)閉連接,對方都能收到消息。client端關(guān)閉連接,server端能收到內(nèi)容長度為0的消息。server端關(guān)閉連接,client端會觸發(fā)onclose事件。
該文章在 2024/3/30 0:18:44 編輯過