C#基礎筆記(第十六天)

来源:http://www.cnblogs.com/VSMinos/archive/2017/11/21/7873461.html
-Advertisement-
Play Games

1.進程複習//通過進程去打開應用程式 Process.Start("calc"); Process.Start("mspaint"); Process.Start("notepad"); Process.Start("iexplore", "http://www.baidu.com"); //通過 ...


1.進程複習
//通過進程去打開應用程式
Process.Start("calc");
Process.Start("mspaint");
Process.Start("notepad");
Process.Start("iexplore", "http://www.baidu.com");

//通過進程去打開指定的文件
ProcessStartInfo psi = new ProcessStartInfo(@"C:\Users\SJD\Desktop\AE.txt");
Process p = new Process();
p.StartInfo = psi;
p.Start();

//進程和線程的關係?一個進程包含多個線程
單線程容易照成程式假死
//前臺 後臺
Thread
Thread th=new Thread(Test);創建線程
th.IsBcakground=true; 標記它為後臺線程
start()啟動線程(告訴CPU 我已經準備好了可以被執行,但是具體執行時間,由CPU決定)
abort()終止線程 (終止完成之後不能再用start())
thread.sleep(1)靜態方法 可以讓當前線程停止一段時間運行

//線程中如何訪問控制項
程式不允許跨線程訪問,會拋異常。
想要不拋異常,在程式載入的時候,取消跨線程的檢查
雖然還是不允許這麼做,但不讓它去檢查,它就不知道這個事
control.checkforillegalcrossthreadcalls=false;

//線程里的方法傳參
如果線程執行的方法需要參數,那麼要求這個參數必須是object類型。
並且參數是傳到調用的start()裡面

2.socket
電腦,程式之間的電話機 收發數據
協議 兩個不同地方的人用普通話通訊
電腦和電腦之間通訊預設的語言
常用協議 UDP和TCP
socket 孔,插座 作為進程通信機制,也稱為“套接字” 用來描述IP地址和埠
是一個通信鏈的句柄(其實就是兩個程式通信用的)
IP是連接伺服器,埠號是連接想連接的應用程式
在服務端必須要有一個負責監聽的socket,看有沒有一個客服端連接到我們的伺服器
負責監聽的socket 創建一個負責通信的socket

3.tcp和udp協議
客服端要連接伺服器,首先要發送一個請求過去
要知道伺服器的ip地址,知道伺服器的應用程式的埠號
就可以準確的連接到伺服器的應用程式

TCP比UDP安全穩定,一般不會發生數據丟失
TCP 3次握手 伺服器(必須有) 請求(一定是客服端發給伺服器)
請求 客戶端--->伺服器 你有空嗎?
伺服器--->客戶端 我有空
客戶端--->服務端 我知道你有空了
三次握手 三次握手成功了,客服端才和伺服器相互的收發數據,否則不會進行數據的溝通
安全,穩定,效率相對低一些

UDP 快速 效率高,但不穩定,容易放生數據丟失
客服端給伺服器發消息,不管伺服器有空沒空就發,消息全發過去,具體伺服器有沒有精力接受這些消息,它不管,反正發過去了。

視頻傳輸用UDP(視頻聊天)聊天不清晰但流暢,不要畫面清晰卻一卡一卡的

3.創建和客戶端通信的socket

private void btnStart_Click(object sender, EventArgs e)
{
//當點擊開始監聽的時候 在伺服器端創建一個負責監IP地址跟埠號的Socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Any;//IPAddress.Parse(txtServer.Text);
//創建埠號對象
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
//監聽
socketWatch.Bind(point);
ShowMsg("監聽成功");
**設置監聽隊列
設置伺服器的最大監聽量
//一個時間點10個人,來11個人就1個人排隊
socketWatch.Listen(10);
Thread th = new Thread(Listen);
th.IsBackground = true;
th.Start(socketWatch);
}
/// <summary>
/// 等待客戶端的連接 並且創建與之通信的socket
/// </summary>
void Listen(object o)
{
Socket socketWatch = o as Socket;
//等待客戶端的連接 並且創建一個負責通信的socket
while (true)
{
Socket socketSend = socketWatch.Accept();
//192.168.1.50:連接成功
ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + "連接成功");
}
}

void ShowMsg(string str)
{
txtLog.AppendText(str + "\r\n");
}

private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegal
CrossThreadCalls = false;
}

4.設計協議
實現傳送文件
如何判斷接收數據是文件還是文字
設計“協議”:
把要傳遞的位元組數組前面都加上一個位元組做為標示。0:標示文字。1:標示文件。
即:文字:0+文字(位元組數組標示)
文件:1+文件的二進位信息

將泛型集合轉換為數組
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(str);
List<byte> list = new List<byte>();
list.Add(0);
list.AddRange(buffer);
byte[] newBuffer= list.ToArray();


5.創建服務端和客戶端通信的流程筆記
客戶端 服務端
Socket() Socket()
Bind() 綁定監聽埠
Listen() 設置監聽隊列
while(true)
{
Connect() 連接建立 Accept() 迴圈等待客戶端連接
}
Send() 發送數據 Receive() 迴圈接收客戶端信息
Receive() 接收數據 Send()
Close() 發送數據 捕捉異常 Close()

1.創建服務端的大概界面
第一排 txtServer(輸入IP) txtPort(輸入埠) btnStart(開始監聽) cboUsers(存儲連接到的IP和埠,combobox控制項)
第二排 txtLog(顯示通信結果)
第三排 txtMsg(輸入通信信息)
第四排 txtPath(存儲和顯示傳輸的文件及路徑) btnSelect(選擇) btnSendFile(發送文件)
第五排 btnSend(發送消息) btnZD(震動)

2.進入btnStart 入口(點擊開始監聽執行)
當點擊開始監聽時 在服務端創建一個負責監聽IP和埠號的socket
Socket socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Any;//IPAddress.Parse(txtServer.Text);
創建埠對象 把IP和埠號拼接起來
IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
監聽
socketWatch.Bind(point);

3.創建一個方法,提示監聽成功,並賦值給txtLog.Text.
方法要傳入一個string類型的參數,表示監聽成功
並且text要使用追加模式,才不會每次傳輸都覆蓋掉。
文本後面+\r\n 換行
void ShowMsg(string str)
{
txtLog.AppendText(str + "\r\n");
}
4.使用ShowMsg方法,傳輸"監聽成功"
ShowMsg("監聽成功");

5.繼續在btnStart
*ShowMsg("監聽成功");
*設置監聽隊列 只能連進來10個
socketWatch.Listen(10);
*等待客戶端連接 並且創建一個負責通信的socket
Socket socketSend= socketWatch.Accept(); socketWatch.Accept就是連接到的客戶端通信
*RemoteEndPoint能夠拿到遠程連過來的IP和埠 輸出到txtLog
ShowMsg(socketSend.RemoteEndPoint.ToString()+":"+"連接成功");

6.出現兩個問題
1.程式出現假死問題,因為只有一個主線程運行
開線程解決
2.因為接收通信只接收了一次,所以只有一個客戶端可以連過來
寫在一個迴圈中解決

7.創建一個方法 等待客戶端的連接,並創建與之通信用的socket
void Listen()
{
把第5步的這兩行剪切過來
**socketWatch只乾一件事情,監聽完後接受
Socket socketSend= socketWatch.Accept();
ShowMsg(socketSend.RemoteEndPoint.ToString()+":"+"連接成功");
}
外面加上while(true)
{
}
出現問題 負責監聽的socketWatch訪問不到了
方法有2 1.第2步的socketWatch聲明在外面
2.把socketWatch傳進來
跨線程傳參只能傳object類型
採用第二種
傳入一個聲明的object類型的參數 o
void Listen(object o)
把object類型的o轉為Socket socketWatch
Socket socketWatch = o as Socket;

8. Listen這個函數要被新線程執行,才不會假死
在btnStart方法中創建新線程 把Listen方法放進去
Thread th = new Thread(Listen);
設置為後臺線程
th.IsBackground = true;
運行並傳入socketWatch給Listen函數
th.Start(socketWatch);
9.程式會報錯,在程式載入時,取消跨線程的報錯
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
}
用telnet測試一下連接情況
10.在7步中的while迴圈繼續寫
客戶端連接成功後,伺服器應該接收客戶端發來的消息
通過負責通信的socket來處理
**跟客戶端收發數據都用負責通信的socket socketSend
receive這個方法接受客戶端發來的消息,接受位元組數組
數據拿過來後先放到一個位元組數組裡面
byte[] buffer = new byte[1024 * 1024 * 2];
r是實際接受到的有效位元組數
int r=socketSend.Receive(buffer);
把傳過來的byte[]轉換成能讀懂的字元串
string str= Encoding.UTF8.GetString(buffer, 0, r);
輸出到txtLog文本框裡面 調用之前的方法ShowMsg
ShowMsg用來作為輸出文本框的方法(自動換行)
socketSend.RemoteEndPoint表示與客戶端的IP和埠號
.tostring表示轉換為string類型了。和後面的一起作為一個整體的string類型傳參給ShowMsg();
在txtLog上顯示客戶端發送的數據
ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + str);
11.測試後,發現只能傳輸一次數字。所以需要把傳輸寫入迴圈並封裝起來。
封裝成一個接收客戶端信息的方法
void Recive()
{
while (true)
{
byte[] buffer = new byte[1024 * 1024 * 2];
//實際接受到的有效位元組數
int r = socketSend.Receive(buffer);
//把buffer轉換成能讀懂的字元串
string str = Encoding.UTF8.GetString(buffer, 0, r);
ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + str);
}
}

socketSend讀取有問題,也需要傳參 同object類型
12.返回Listen的while迴圈中
開啟一個新線程 不停的接收客戶端發送過來的消息
Thread th = new Thread(Recive);
th.IsBackground = true;
th.Start(socketSend);
問題1.現在是發一個字元換一行 但要一行顯示(這個只要用自己寫的客戶端做就是正常的了,跳過)
問題2.關了客戶端,服務端還是一直在發送。
因為客戶端關閉了,r的實際信息是空(也就是0),但還是一直在發送,所以要做一個判斷
if(r==0)
{ break; }
把容易發生異常的地方都try-catch起來。catch裡面什麼都不寫

13.創建客戶端模塊
txtServer(192.168.1.42) txtPort(50000) btnStart(連接)
txtLog
txtMsg

14.點擊連接進入btnSatrt_Click
創建負責通信的socket interNetwork表示IPV4 sockettype(類型)流式的 protocoltype(服務)Tcp
Socket socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
客戶端要去連接伺服器
首先要用靜態方法創建ipAddress 的IP地址
IPAddress ip = IPAddress.Parse(txtServer.Text);
再把IP和埠號拼接一起
IPEndPoint point = new IPEndPoint( ip, Convert.ToInt32(txtPort.Text));
獲得要遠程連接的伺服器的IP和埠號
socketSend.Connect(point);

15.創建一個方法 ShowMsg()
void ShowMsg(string str)
{
要使用追加文本的AppendText才不會被覆蓋掉
txtLog.AppendText(str + "\r\n");
}
在14步中傳入個"連接成功",表示客戶端與服務端連接上了
ShowMsg("連接成功");

16.連接上服務端 客戶端就給服務端發送消息
需要再txtMsg寫內容 發送給伺服器
寫在發送消息事件里,進入btnSend_Click
用負責通信的socketSend來通信。但是它寫在另一個事件里拿不到,所以把它聲明到外面去
socketSend.send()發信息到服務端,需要放入一個位元組數組
我們要發送的txtMsg.text裡面的信息,接收到string str裡面,trim是移除空格
string str = txtMsg.Text.Trim();
再把str轉換為位元組數組
byte[] buffer = Encoding.UTF8.GetBytes(str);
發送信息到服務端
socketSend.Send(buffer);

17.服務端向客戶端發送消息
寫在發送消息事件內 btnSend_Click
先將第7步 socket socketSend聲明到外面
如同第16步 把txtMsg的數據傳到客戶端
string str = txtMsg.Text();
byte[] buffer = Encoding.UTF8.GetBytes(str);
socketSend.Send(buffer);
18.客戶端 發消息不只一次,要不停的發,所以還要一直接收
寫一個和服務端的Recive方法一樣。使用wile(true)讓他迴圈使用
void Recive()
{
while(true)
{

}
}
用socketSend.Receive接收位元組數組buffer,返回一個實際接受的有效位元組數r
byte[] buffer = new byte[1024 * 1024 * 3];
int r= socketSend.Receive(buffer);
如12步,再加上判斷位元組數為空的時候跳出迴圈 if(r==0)
if(r==0)
{
break;
}
再將信息的數組解碼為字元串s來接收
string str=Encoding.UTF8.GetString(buffer, 0, r);
調用ShowMsg方法 把IP和埠號用:和接收的信息連接起來並換行輸出,顯示在txtMsg上
RemoteEndPoint 獲取IP地址和埠號
ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + s);
19.返回btnStart_Click事件
防止運行單線程時候卡死,需要開啟一個新線程,把Recive的方法傳進去,不停的接受服務端發來的消息
Thread th = new Thread(Recive);
設置為後臺線程
th.IsBackground = true;
th.Start();
20.為了防止跨線程報錯出異常
在form1_load載入時關閉跨線程的檢查
Control.CheckForIllegalCrossThreadCalls = false;
凡是涉及網路連接的都try-catch一下
21.現在只能和最後一個連上的客戶端通信,因為新的客戶端連過來,原來的就沒有了。
所以服務端需要一個來存儲遠程IP和埠的下拉框,給指定的客戶端發送消息 cboUsers
用一個鍵值對來存儲 Directory 根據string類型的IP地址去找socketSend 鍵值對
Dictionary<string, Socket> dicSocket = new Dictionary<string, Socket>();

22.在Listen的socketSend下麵添加集合
將遠程連接的客戶端的IP地址和Socket存入集合中
所以發消息的時候不能再直接用socketSend了,根據選中的IP地址來發送
dicSocket.d(socketSend.RemoteEndPoint.ToString(), socketSend);
將遠程連接的IP地址和埠號存儲到cboUsers下拉框中
cboUsers.Items.Add(socketSend.RemoteEndPoint.ToString());
轉到 btnSend_Click IP和埠
獲得用戶在下拉框中選中的IP地址指定給string類型的ip
string ip = cboUsers.SelectedItem.ToString();
dicSocket[ip].Send(buffer);
測試

23.現在已經實現了服務端和客戶端互相收發數據,但僅限文本類型數據
服務端還有文件和震動 客戶端怎麼區分發過來的是什麼。因為發來的是位元組數組
告訴客戶端 發的是什麼東西
製作一個偽協議
協議是約定 互相都要遵守
在位元組數組上做手腳
標記一下 根據類型把位元組數據前面的加上一位,[0]為標記 0,文本 1,文件 3,震動
24.對服務端的接收做判斷
服務端的接收內做判斷
如果是0,按照文本處理,1,按照文件處理,2,按照震動處理
服務端給客戶端發信息 btnSend_Click
在buffer中安插一個byte[0]=0;
數組長度不可變,需要新建一個數組來接受,併發送過去
數組長度 buffer.length+1 buffer[0]=0;
賦值給一個新的buffer 使用一個List的泛型集合添加,再轉換為位元組數組
List<byte> list = new List<byte>();
list.Add(0);
list.AddRange(list);
byte[]newByte= list.ToArray();
最後把傳過去的數組改為 dicSocket[ip].Send(newBuffer);
不能直接賦值給buffer,因為長度不一樣。
25.返回客戶端接收伺服器發來的消息 Recive
在接收字元串後得到實際數據大小下麵添加判斷首數字為(0,1,2)
if(buffer[0]==0)
{

}
把得到文本的處理代碼放入這個判斷中
然後擴展其他的
else if(buffer==1)
{
}
else if(buffer==2)
{
}
if(r==0)的判斷可以放到外面,不用3個都寫
if (r == 0)
{
break;
}
處理文本的代碼直接套入會有問題,因為位元組多了一個首數字,需要算進來
解碼的時候要從第二個元素(下標為1)開始處理,因為第一個元素是標記類,沒有用
解碼多少個,r-1。因為第一個沒有用。
string s = Encoding.UTF8.GetString(buffer,1 , r+1);
測試 不會丟失文本
26.服務端選擇文件
點擊 選擇 的時候應該彈出對話框 選擇文件 btnSelect事件中 選擇發送的文件
OpenFileDialog ofd = new OpenFileDialog();
ofd.Title = "請選擇要發送的文件";
ofd.InitialDirectory = @"C:\Users\SJD\Desktop";
ofd.Filter = "所有文件|*.*";
ofd.ShowDialog();
txtPath.Text= ofd.FileName;
27.服務端發送文件
點擊 發送文件 btnSend
獲得要發送的文件的路徑
string path = txtPath.Text;
讀取數據流
using (FileStream fsRead = new FileStream(path, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[1024 * 1024 * 5];
int r= fsRead.Read(buffer,0,buffer.Length);
拿到負責通信的socket把位元組數組buffer發過去
設置buffer的大小,讓他以實際參數大小發過去。
buffer數組,從0到r,無值枚舉參數
dicSocket[cboUsers.SelectedItem.ToString()].Send(buffer, 0,r, SocketFlags.None);
}
需要把數值1添加在首位位元組,所以
using (FileStream fsRead = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Read))
{
byte[] buffer = new byte[1024 * 1024 * 5];
int r= fsRead.Read(buffer,0,buffer.Length);
//設置buffer的大小,讓他以實際參數大小發過去。
List<byte> list = new List<byte>();
list.Add(1);
list.AddRange(buffer);
byte[]newBuffer= list.ToArray();
dicSocket[cboUsers.SelectedItem.ToString()].Send(newBuffer, 0,r+1, SocketFlags.None);

}
28.找到客戶端開始接收
在else if(buffer[0]==1)中創建 saveFileDialog的對象
SaveFileDialog sfd = new SaveFileDialog();
sfd.Title = "請選擇要保存的文件";
sfd.InitialDirectory = @"C:\Users\SJD\Desktop";
sfd.Filter = "所有文件|*.*";
WIN7,WIN8要加this。否則保存目錄彈不出來
sfd.ShowDialog(this);
string path=sfd.FileName;
using (FileStream fsWrite = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
{
fsWrite.Write(buffer, 1, r - 1);
MessageBox.Show("保存成功");
}
會出問題的地方都try-catch一下
29. 發送震動 進入 btnZD_Click事件
創建一位的位元組數組,放入2,根據它的鍵值對發送給指定IP客戶端
byte[] buffer = new byte[1];
buffer[0] = 2;
dicSocket[cboUsers.SelectedIte()m.ToString()].Send(buffer);
30.客戶端設置震動
客戶端創建一個震動的方法
void ZD()
{
迴圈500次 這個form(客戶端)一直不停賦值,位置一直移
for (int i = 0; i < 500; i++)
{
this.Location = new Point(200, 200);
this.Location = new Point(230, 230);
}
進入else if(buffer[0]==2) 把方法 ZD()放進來


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • static bool CheckPowerOfTwo(ulong num) { return num > 0 && (num & (num - 1)) == 0; } ...
  • 引自https://www.cnblogs.com/lsgsanxiao/p/5523282.html invoke和begininvoke 區別 一直對invoke和begininvoke的使用和概念比較混亂,這兩天看了些資料,對這兩個的用法和原理有了些新的認識和理解。 首先說下,invoke和b ...
  • 如何:對 Windows 窗體控制項進行線程安全調用 訪問 Windows 窗體控制項本質上不是線程安全的。 如果有兩個或多個線程操作某一控制項的狀態,則可能會迫使該控制項進入一種不一致的狀態。 還可能會出現其他與線程相關的 Bug,例如爭用情況和死鎖。 確保以線程安全方式訪問控制項非常重要。 在未使用 In ...
  • 一 前言 對於正則表達式,相信很多人都知道,但是很多人的第一感覺就是難學,因為看第一眼時,覺得完全沒有規律可尋,而且全是一堆各種各樣的特殊符號,完全不知所云。 其實只是對正則不瞭解而以,瞭解了你就會發現,原來就這樣啊正則所用的相關字元其實不多,也不難記,更不難懂,唯一難的就是組合起來之後,可讀性比較 ...
  • 一. 概念理解 你可能有留意到當你瀏覽網頁時,會有一些推送消息,大多數是你最近留意過的同類東西,比如你想買桌子,上淘寶搜了一下,結果連著幾天會有各種各樣的桌子的鏈接。這是因為 你瀏覽某個網頁的時候,WEB 伺服器會先送一些資料放在你的電腦上,類似於你打的文字,選的一些東西什麼的,Cookie 會幫 ...
  • 效果圖: 下載鏈接:創建wpf項目引用 如下:鏈接:http://pan.baidu.com/s/1chj1nS 密碼:u7y2 第一步:創建項目引用CefSharp 第二步:第二步將DLL拷貝到運行項目的Debug下 第三步:項目平臺設置32位 第四步:創建視頻文件與html腳本 第五步:Xaml ...
  • 本文為原創文章、源代碼為原創代碼,如轉載/複製,請在網頁/代碼處明顯位置標明原文名稱、作者及網址,謝謝! 本文使用的工具下載地址為: 或 dnSpy官方下載地址: 軟體界面如下: 該軟體分別64位版本及32位版本,分別為dnSpy.exe 及 dnSpy-x86.exe,調試時請註意調試所對應軟體版 ...
  • using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; namespace C... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...