一、委託:把一個方法看成參數傳到另外一個方法中javascript
擴展方法:一、靜態類 二、靜態方法 三、this關鍵字html
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 委託 { //擴展方法的三大步 //一、靜態類 二、靜態方法 三、this 關鍵字 public static class MyListExit { //this List<string> list 表示須要擴展方法的類型,即:給list<string>類型擴展一個MyWhere方法 //Func<string,bool> funcWhere 傳入的參數是一個泛型方法 public static List<string> MyWhere(this List<string> list, Func<string, bool> funcWhere) { List<string> result = new List<string>(); //遍歷集合list,返回的也是一個集合 foreach (var item in list) { if (funcWhere(item)) { result.Add(item); } } return result; } } }
二、父窗體與子窗體間傳值前端
1)、(委託方式)java
i、在父窗體內定義一個無返回值且有一個字符串類型參數的委託程序員
//定義發佈消息委託
public Action<string> AfterMsgSend { get;set;}
ii、在子窗體內寫一個傳入參數爲字符串類型的方法SetText做用是設置子窗體文本框的Text屬性sql
public void SetText(string str) { tbMsg.Text = str; }
iii、在父窗體的Load事件中,建立子窗體對象,而後將子窗體的SetText方法追加到委託AfterMsgSend裏面,而後調用子窗體Show方法,打開子窗體數據庫
private void ParentFrm_Load(object sender, EventArgs e) { ChildFrm frm = new ChildFrm(); AfterMsgSend += frm.SetText; frm.Show(); }
iiii、在父窗體的按鈕單擊事件中,先判斷委託AfterMsgSend是否爲空,若是爲空則直接return,不然就調用委託函數編程
private void btSendMsg_Click(object sender, EventArgs e) { //委託傳值 if (AfterMsgSend == null) { return; } AfterMsgSend(this.tbMsg.Text); }
2)、(事件方式)小程序
i、在父窗體內定義一個發佈消息的事件AfterMsgChangedEvent瀏覽器
//定義一個發佈消息事件 public event EventHandler AfterMsgChangedEvent;
ii、在父窗體的按鈕點擊事件中觸發事件
//觸發事件
AfterMsgChangedEvent(this,new EventArgs());
iii、EventArgs不能傳遞參數,而咱們須要給子窗體傳遞參數,因此咱們須要本身寫一個繼承自EventArgs的子類TextBoxMsgChangeEventArg
public class TextBoxMsgChangeEventArg:EventArgs { public string Text { get; set; } }
iiii、父窗體的觸發事件就應該變成
//觸發事件 AfterMsgChangedEvent(this, new TextBoxMsgChangeEventArg() { Text = this.tbMsg.Text });
iiiii、在子窗體建立一個知足AfterMsgChangedEvent事件類型的方法
public void AfterFrmMsgChange(object sender, EventArgs e) { TextBoxMsgChangeEventArg arg = e as TextBoxMsgChangeEventArg; SetText(arg.Text); }
iiiiii、在父窗體中建立子窗體的對象,在打開以前將子窗體的AfterFrmMsgChange方法綁定到父窗體的AfterMsgChangedEvent事件上
private void ParentFrm_Load(object sender, EventArgs e) { ChildFrm frm = new ChildFrm(); AfterMsgChangedEvent += frm.AfterFrmMsgChange; frm.Show(); }
三、發佈訂閱模式和觀察者模式
i、寫一個用來傳遞參數的接口Ifrmable
public interface Ifrmable { void SetText(string str); }
ii、父窗體中建立一個Ifrmable類型的集合
public List<Ifrmable> list { get; set; }
iii、父窗體按鈕單擊事件中給子窗體的接口方法傳值
private void btSend_Click(object sender, EventArgs e) { if (list == null) { return; } foreach (var item in list) { item.SetText(this.tbSend.Text); } }
iiii、子窗體中實現接口方法
public partial class FrmChild : Form,Ifrmable { public FrmChild() { InitializeComponent(); } public void SetText(string str) { this.tbSend.Text = str; } }
iiiii、父窗體load事件中初始化子窗體對象
private void FrmFather_Load(object sender, EventArgs e) { FrmFather ff = new FrmFather(); FrmChild fc = new FrmChild(); ff.list = new List<Ifrmable>(); ff.list.Add(fc); ff.Show(); fc.Show(); }
五、多線程
進程:操做系統分配資源的最小單位,能夠理解爲一個小模塊小程序
線程:一個線程就是一個進程裏面的代碼的執行流。每一個線程都要指向一個方法體,方法執行完以後,線程就釋放
線程默認是前臺線程,一個進程結束的標誌是全部前臺線程都結束以後。
static void Main(string[] args) { //建立一個線程 Thread th = new Thread(delegate() { while (true) { Console.WriteLine(DateTime.Now); Thread.Sleep(1000); } }); th.IsBackground = true;//線程默認是前臺線程,一個進程結束的標誌是全部前臺線程都結束以後。 th.Priority = ThreadPriority.Normal;//後臺線程不會組塞 進程的退出 th.Start();//告訴操做系統線程準備就緒 th.Join(100000);//等待th執行完成 th.Abort();//不得已才能使用,直接終止線程 }
避免非子線程調用主線程建立的控件的時候報錯的辦法就是不檢查是否存在跨線程調用
public Form1() { InitializeComponent(); Control.CheckForIllegalCrossThreadCalls = false; //這種方式不用在正式的項目中 }
在正式的項目中解決跨線程報錯的問題應該像下面這樣寫
Thread th = new Thread(delegate() { if (btSendMsg.InvokeRequired)//InvokeRequired:若是是別的線程建立的此控件 { btSendMsg.Invoke(new Action<string>(s => { this.tbMsg.Text = s; }), DateTime.Now.ToString()); } else { tbMsg.Text = DateTime.Now.ToString(); } });
雙色球案例
public partial class WinFrmDoubleColorBall : Form { private List<Label> lbList = new List<Label>(); private bool isRunning = false; public WinFrmDoubleColorBall() { InitializeComponent(); //Control.CheckForIllegalCrossThreadCalls = false; } private void WinFrmDoubleColorBall_Load(object sender, EventArgs e) { for (int i = 0; i < 6; i++) { Label lb = new Label(); lb.Text = "0"; lb.AutoSize = true; lb.Location = new Point(50 * i + 50, 100); this.Controls.Add(lb); lbList.Add(lb); } } private void btStart_Click(object sender, EventArgs e) { isRunning = true; Thread th = new Thread(delegate() { Random r = new Random(); while (isRunning) { foreach (var item in lbList) { string str=r.Next(0, 10).ToString(); if (item.InvokeRequired) { item.Invoke(new Action<string>(delegate(string s) { item.Text = s; }), str); //item.Invoke(new Action<string>(s => { item.Text = s; } // ),str); } else { item.Text = str; } } Thread.Sleep(200); } }); th.IsBackground = true; th.Start(); } private void btStop_Click(object sender, EventArgs e) { isRunning = false; } }
六、對象池技術
爲何有連接池?1)、連接對象建立很是消耗資源 2)、考慮到對象的重用
避免死鎖:1)、sql操做表的順序儘可能一致 2)把查詢sql中加with(nolock) 3)、由於連接很是多引發的死鎖,能夠用臨時表來解決 4)、分庫:水平分庫,垂直分庫 5)、數據庫集羣,讀寫分離
class Program { static void Main(string[] args) { //建立一個池子 MyConnection[] connectArry=new MyConnection[100]; //索引 int index = -1; //建立10個消費者 for (int i = 0; i < 10; i++) { Thread th = new Thread(() => { while (true) { lock(connectArry) //lock後面要跟一個引用類型的實例,鎖住同一個對象(引用的地址)就互斥 { if (index > 0) { connectArry[index+1] = null; Console.WriteLine("消費了一個產品:"+index); index--; } } Thread.Sleep(500); } }); th.IsBackground = true; th.Start(); } //建立5個生產者 for (int i = 0; i <5; i++) { Thread th = new Thread(() => { while (true) { lock(connectArry) { if (index < 99) { connectArry[index+1] = new MyConnection(); Console.WriteLine("生產了一個產品:" + (index+1)); index++; } } Thread.Sleep(1000); } }); th.IsBackground = true; th.Start(); } Console.ReadKey(); } } public class MyConnection { }
線程池的線程自己都是後臺線程,優點在於線程能夠進行重用,缺點在於不靈活(不能手動中止)
ThreadPool.QueueUserWorkItem((s) =>
{
Console.WriteLine(s);
});
上面的線程池過程和下面的隊列操做是同樣的原理,區別就是下面這個是先進先出的
Queue<WaitCallback> queue = new Queue<WaitCallback>(); //建立一個隊列 queue.Enqueue((s) => //進隊列 { Console.WriteLine(s); });
何時用線程池?何時用手動建立線程?
1)、能用線程池就用線程池,處理的順序不肯定。
2)、想手動關閉線程就必須手動建立線程(Abort(),Join())
3)、須要對線程的優先級作設置必須手動建立線程
4)、若是執行的線程時間特別長,線程池適合用於作大量的小運算。
獲取系統最大可設置線程數與實際設置最大線程數
//獲取線程池最大線程數據 int numMax = 0; int runNumMax = 0; ThreadPool.GetMaxThreads(out numMax, out runNumMax); Console.WriteLine(numMax + " " + runNumMax);
七、異步調用委託:與手動建立線程比較的優點在於能夠拿到線程執行的結果1)、無回調函數的異步委託
static void Main(string[] args) { //建立一個委託 Func<int, int, string> func = delegate(int a, int b) { return (a + b).ToString(); }; //異步調用委託 IAsyncResult result = func.BeginInvoke(3, 4, null, null); //異步獲取委託返回的結果,EndInvoke方法會阻塞當前線程,直到異步委託指向的方法執行完畢纔會繼續往下執行 string str = func.EndInvoke(result); Console.WriteLine(str); Console.ReadKey(); }
2)、有回調函數的異步委託
static void Main(string[] args) { //建立一個委託 Func<int, int, string> func = delegate(int a, int b) { return (a + b).ToString(); }; //異步調用委託 func.BeginInvoke(3, 4, MyAsyncCallback, "123"); Console.ReadKey(); } public static void MyAsyncCallback(IAsyncResult ar) { //一、拿到異步委託執行的結果 AsyncResult result = (AsyncResult)ar; //強轉成AsyncResult類型 var del = (Func<int, int, string>)result.AsyncDelegate; //強轉成Func<int, int, string>類型 string str = del.EndInvoke(result); Console.WriteLine("異步回調函數的返回結果是:"+str); //7 //二、拿到回掉函數參數 Console.WriteLine("回調函數拿到的參數是:" + result.AsyncState); //123 }
static void Main(string[] args) { //建立一個委託 Func<int, int, string> func = delegate(int a, int b) { return (a + b).ToString(); }; //異步調用委託 func.BeginInvoke(3, 4, MyAsyncCallback, func); //最後直接把委託func當成參數傳給回調函數 Console.ReadKey(); } public static void MyAsyncCallback(IAsyncResult ar) { var del = (Func<int, int, string>)ar.AsyncState; //直接將傳進來的參數強轉成Func<int, int, string>類型, string str = del.EndInvoke(ar); Console.WriteLine("異步回調函數的返回結果是:"+str); //7 }
static void Main(string[] args) { //建立一個委託 Func<string, string, bool> func = delegate(string stra, string strb) { return stra == strb; }; func.BeginInvoke("0123", "123", MyCallback, func); Console.ReadKey(); } private static void MyCallback(IAsyncResult ar) { Func<string, string, bool> del = (Func<string, string, bool>)ar.AsyncState; bool b = del.EndInvoke(ar); if (b) { Console.WriteLine("相等"); } else { Console.WriteLine("不等"); } }
七、Socket編程
服務端:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.IO; 7 using System.Linq; 8 using System.Net; 9 using System.Net.Sockets; 10 using System.Text; 11 using System.Text.RegularExpressions; 12 using System.Threading; 13 using System.Threading.Tasks; 14 using System.Windows.Forms; 15 16 namespace Socket編程窗體服務端與客戶端 17 { 18 public partial class ServerFrm : Form 19 { 20 List<Socket> proxSocketList = new List<Socket>(); 21 public ServerFrm() 22 { 23 InitializeComponent(); 24 } 25 26 private void btStart_Click(object sender, EventArgs e) 27 { 28 btStart.Enabled=false; 29 //一、獲取本機IP 30 //IPAddress[] ipAddress = Dns.GetHostAddresses(Dns.GetHostName()); 31 IPAddress iP = IPAddress.Parse(tbIp.Text); 32 //二、建立一個用於監聽的Socket 33 Socket serverSocket = new Socket( 34 AddressFamily.InterNetwork, 35 SocketType.Stream, 36 ProtocolType.Tcp 37 ); 38 //三、綁定IP 39 IPEndPoint ipEndPoint=new IPEndPoint(iP,Convert.ToInt32(tbPort.Text)); 40 serverSocket.Bind(ipEndPoint); 41 42 ReceiveText("服務端開始監聽"); 43 //四、創建監聽隊列,默認爲10 44 serverSocket.Listen(10); 45 46 //五、主線程一直負責監聽,線程池的線程來接受客戶端鏈接請求 47 ThreadPool.QueueUserWorkItem((s) => 48 { 49 while (true) 50 { 51 Socket proxSocket = serverSocket.Accept(); 52 ReceiveText("客戶端:" + proxSocket.RemoteEndPoint + "連接成功"); 53 proxSocketList.Add(proxSocket); 54 if (cbClientSocket.InvokeRequired) 55 { 56 cbClientSocket.Invoke(new Action<IPEndPoint>((a) => { cbClientSocket.Items.Add(a); }), proxSocket.RemoteEndPoint); 57 } 58 else 59 { 60 cbClientSocket.Items.Add(proxSocket.RemoteEndPoint); 61 } 62 ThreadPool.QueueUserWorkItem(new WaitCallback( ReceiveCallback), proxSocket); 63 } 64 },serverSocket); 65 } 66 67 private void ReceiveCallback(object ar) 68 { 69 Socket proxSocket = (Socket)ar; 70 byte[] buffer = new byte[1024 * 1024]; 71 while (true) 72 { 73 int iReceive=0; 74 try 75 { 76 iReceive = proxSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None); 77 } 78 catch 79 { 80 81 } 82 if (iReceive <= 0) 83 { 84 ReceiveText("客戶端:" + proxSocket.RemoteEndPoint + "斷開連接"); 85 proxSocketList.Remove(proxSocket); 86 if (cbClientSocket.InvokeRequired) 87 { 88 cbClientSocket.Invoke(new Action<Socket>((s) => { cbClientSocket.Items.Remove(s.RemoteEndPoint); }), proxSocket); 89 } 90 else 91 { 92 cbClientSocket.Items.Remove(proxSocket.RemoteEndPoint); 93 } 94 return; 95 } 96 if (buffer[0] == 1) 97 { 98 ReceiveText("收到來自:" + proxSocket.RemoteEndPoint + "的消息:" + Encoding.Default.GetString(buffer, 1, iReceive-1)); 99 } 100 else if (buffer[0] == 2) 101 { 102 Thread th = new Thread(new ThreadStart(() => 103 { 104 using (SaveFileDialog sfd = new SaveFileDialog()) 105 { 106 if (sfd.ShowDialog() != DialogResult.OK) 107 { 108 return; 109 } 110 byte[] fileData = new byte[buffer.Length - 1]; 111 Buffer.BlockCopy(buffer, 1, fileData, 0, buffer.Length - 1); 112 using (FileStream fs = new FileStream(sfd.FileName, FileMode.Create, FileAccess.Write)) 113 { 114 using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)) 115 { 116 sw.Write(Encoding.Default.GetString(fileData, 0, fileData.Length)); 117 } 118 } 119 } 120 })); 121 th.SetApartmentState(ApartmentState.STA); 122 th.Start(); 123 } 124 } 125 } 126 private void ReceiveText(string str) 127 { 128 if (rtbReceive.InvokeRequired) 129 { 130 rtbReceive.Invoke(new Action<string>((s) => 131 { 132 rtbReceive.Text = string.Format("{0}\r\n{1}", str, rtbReceive.Text); 133 }),str); 134 } 135 else 136 { 137 rtbReceive.Text = string.Format("{0}\r\n{1}", str, rtbReceive.Text); 138 } 139 } 140 141 private void btSend_Click(object sender, EventArgs e) 142 { 143 foreach (var item in proxSocketList) 144 { 145 if (cbClientSocket.SelectedItem == null) 146 { 147 byte[] data = Encoding.Default.GetBytes(tbSend.Text); 148 byte[] buffer = new byte[data.Length + 1]; 149 buffer[0] = 1; 150 Buffer.BlockCopy(data, 0, buffer, 1, data.Length); 151 item.Send(buffer, 0, buffer.Length, SocketFlags.None); 152 } 153 else 154 { 155 if (item.RemoteEndPoint == cbClientSocket.SelectedItem) 156 { 157 byte[] data = Encoding.Default.GetBytes(tbSend.Text); 158 byte[] buffer = new byte[data.Length + 1]; 159 buffer[0] = 1; 160 Buffer.BlockCopy(data, 0, buffer, 1, data.Length); 161 item.Send(buffer, 0, buffer.Length, SocketFlags.None); 162 } 163 } 164 } 165 } 166 167 private void btSendFile_Click(object sender, EventArgs e) 168 { 169 string str = ""; 170 Thread th = new Thread(new ThreadStart(() => 171 { 172 using (OpenFileDialog ofd = new OpenFileDialog()) 173 { 174 if (ofd.ShowDialog() != DialogResult.OK) 175 { 176 return; 177 } 178 if (tbFileName.InvokeRequired) 179 { 180 tbFileName.Invoke(new Action<string>(delegate(string s) { this.tbFileName.Text = s; }), ofd.FileName); 181 } 182 else 183 { 184 this.tbFileName.Text = ofd.FileName; 185 } 186 187 using (FileStream fs = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read)) 188 { 189 using (StreamReader sr = new StreamReader(fs, Encoding.Default)) 190 { 191 if (!sr.EndOfStream) 192 { 193 str = str + sr.ReadToEnd(); 194 } 195 } 196 } 197 } 198 foreach (var item in proxSocketList) 199 { 200 if (cbClientSocket.InvokeRequired) 201 { 202 cbClientSocket.Invoke(new Action<Socket>((s) => 203 { 204 if (s.RemoteEndPoint == cbClientSocket.SelectedItem) 205 { 206 byte[] data = Encoding.Default.GetBytes(str); 207 byte[] buffer = new byte[data.Length + 1]; 208 buffer[0] = 2; 209 Buffer.BlockCopy(data, 0, buffer, 1, data.Length); 210 s.Send(buffer, 0, buffer.Length, SocketFlags.None); 211 ReceiveText("發送文件到:" + s.RemoteEndPoint + "成功"); 212 } 213 else if (cbClientSocket.SelectedItem == null) 214 { 215 byte[] data = Encoding.Default.GetBytes(str); 216 byte[] buffer = new byte[data.Length + 1]; 217 buffer[0] = 2; 218 Buffer.BlockCopy(data, 0, buffer, 1, data.Length); 219 s.Send(buffer, 0, buffer.Length, SocketFlags.None); 220 ReceiveText("發送文件到:" + s.RemoteEndPoint + "成功"); 221 } 222 }),item); 223 } 224 else 225 { 226 if (item.RemoteEndPoint == cbClientSocket.SelectedItem) 227 { 228 byte[] data = Encoding.Default.GetBytes(str); 229 byte[] buffer = new byte[data.Length + 1]; 230 buffer[0] = 2; 231 Buffer.BlockCopy(data, 0, buffer, 1, data.Length); 232 item.Send(buffer, 0, buffer.Length, SocketFlags.None); 233 ReceiveText("發送文件到:" + item.RemoteEndPoint + "成功"); 234 } 235 else if (cbClientSocket.SelectedItem == null) 236 { 237 byte[] data = Encoding.Default.GetBytes(str); 238 byte[] buffer = new byte[data.Length + 1]; 239 buffer[0] = 2; 240 Buffer.BlockCopy(data, 0, buffer, 1, data.Length); 241 item.Send(buffer, 0, buffer.Length, SocketFlags.None); 242 ReceiveText("發送文件到:" + item.RemoteEndPoint + "成功"); 243 } 244 } 245 } 246 247 })); 248 th.SetApartmentState(ApartmentState.STA); 249 th.Start(); 250 } 251 252 private void tbClear_Click(object sender, EventArgs e) 253 { 254 cbClientSocket.SelectedItem =null; 255 } 256 } 257 }
客戶端:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.IO; 7 using System.Linq; 8 using System.Net; 9 using System.Net.Sockets; 10 using System.Text; 11 using System.Text.RegularExpressions; 12 using System.Threading; 13 using System.Threading.Tasks; 14 using System.Windows.Forms; 15 16 namespace Socket編程窗體服務端與客戶端 17 { 18 public partial class ClientFrm : Form 19 { 20 private Socket ClientSocket { get; set; } 21 public ClientFrm() 22 { 23 InitializeComponent(); 24 } 25 26 private void btConnect_Click(object sender, EventArgs e) 27 { 28 btConnect.Enabled = false; 29 //一、獲取本機IP 30 //IPAddress[] ipAddress = Dns.GetHostAddresses(Dns.GetHostName()); 31 IPAddress iP = IPAddress.Parse(tbIp.Text); 32 //二、建立一個用於連接的Socket 33 Socket clientSocket = new Socket( 34 AddressFamily.InterNetwork, 35 SocketType.Stream, 36 ProtocolType.Tcp 37 ); 38 //三、綁定IP 39 IPEndPoint ipEndPoint = new IPEndPoint(iP, Convert.ToInt32(tbPort.Text)); 40 41 //四、開始連接 42 clientSocket.Connect(ipEndPoint); 43 ClientSocket = clientSocket; 44 ReceiveText("到服務端:" + clientSocket.RemoteEndPoint + "連接成功"); 45 ThreadPool.QueueUserWorkItem((s) => 46 { 47 byte[] buffer = new byte[1024 * 1024]; 48 while (true) 49 { 50 int iReceive = 0; 51 try 52 { 53 iReceive = clientSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None); 54 } 55 catch 56 { 57 58 } 59 if (iReceive <= 0) 60 { 61 ReceiveText("斷開與服務端:" + clientSocket.RemoteEndPoint + "連接"); 62 return; 63 } 64 if (buffer[0] == 1) 65 { 66 ReceiveText("收到服務端" + clientSocket.RemoteEndPoint + "發來的消息:" + Encoding.Default.GetString(buffer, 1, iReceive-1)); 67 } 68 else if (buffer[0] == 2) 69 { 70 Thread th = new Thread(new ThreadStart(() => 71 { 72 using (SaveFileDialog sfd = new SaveFileDialog()) 73 { 74 if (sfd.ShowDialog() != DialogResult.OK) 75 { 76 return; 77 } 78 byte[] fileData = new byte[buffer.Length - 1]; 79 Buffer.BlockCopy(buffer, 1, fileData, 0, buffer.Length - 1); 80 using (FileStream fs = new FileStream(sfd.FileName, FileMode.Create, FileAccess.Write)) 81 { 82 using (StreamWriter sw = new StreamWriter(fs, Encoding.Default)) 83 { 84 sw.Write(Encoding.Default.GetString(fileData, 0, fileData.Length)); 85 } 86 } 87 } 88 })); 89 th.SetApartmentState(ApartmentState.STA); 90 th.Start(); 91 } 92 } 93 },clientSocket); 94 } 95 private void ReceiveText(string str) 96 { 97 if (rtbReceive.InvokeRequired) 98 { 99 rtbReceive.Invoke(new Action<string>((s) => 100 { 101 rtbReceive.Text = string.Format("{0}\r\n{1}", str, rtbReceive.Text); 102 }), str); 103 } 104 else 105 { 106 rtbReceive.Text = string.Format("{0}\r\n{1}", str, rtbReceive.Text); 107 } 108 } 109 110 private void btSend_Click(object sender, EventArgs e) 111 { 112 byte[] data = Encoding.Default.GetBytes(tbSend.Text); 113 byte[] buffer = new byte[data.Length+1]; 114 buffer[0] = 1; 115 Buffer.BlockCopy(data, 0, buffer, 1, data.Length); 116 ClientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None); 117 } 118 119 private void btSendFile_Click(object sender, EventArgs e) 120 { 121 string str = ""; 122 Thread th = new Thread(new ThreadStart(() => 123 { 124 using (OpenFileDialog ofd = new OpenFileDialog()) 125 { 126 if (ofd.ShowDialog() != DialogResult.OK) 127 { 128 return; 129 } 130 if (tbSendFileName.InvokeRequired) 131 { 132 tbSendFileName.Invoke(new Action<string>(delegate(string s) { this.tbSendFileName.Text = s; }), ofd.FileName); 133 } 134 else 135 { 136 this.tbSendFileName.Text = ofd.FileName; 137 } 138 139 using (FileStream fs = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read)) 140 { 141 using (StreamReader sr = new StreamReader(fs,Encoding.Default)) 142 { 143 if (!sr.EndOfStream) 144 { 145 str = str + sr.ReadToEnd(); 146 } 147 } 148 } 149 } 150 byte[] data = Encoding.Default.GetBytes(str); 151 152 byte[] buffer = new byte[data.Length + 1]; 153 buffer[0] = 2; 154 Buffer.BlockCopy(data, 0, buffer, 1, data.Length); 155 ClientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None); 156 ReceiveText("發送文件到:" + ClientSocket.RemoteEndPoint + "成功"); 157 })); 158 th.SetApartmentState(ApartmentState.STA); 159 th.Start(); 160 } 161 162 private void ClientFrm_FormClosed(object sender, FormClosedEventArgs e) 163 { 164 ClientSocket.Shutdown(SocketShutdown.Both); 165 } 166 } 167 }
八、Response.Redirect原理
請求頭(消息頭)包含(客戶機請求的服務器主機名,客戶機的環境信息等):
一、Accept:用於告訴服務器,客戶機支持的數據類型 (例如:Accept:text/html,image/*)
二、Accept-Charset:用於告訴服務器,客戶機採用的編碼格式
三、Accept-Encoding:用於告訴服務器,客戶機支持的數據壓縮格式
四、Accept-Language:客戶機語言環境
五、Host:客戶機經過這個服務器,想訪問的主機名
六、If-Modified-Since:客戶機經過這個頭告訴服務器,資源的緩存時間
七、Referer:客戶機經過這個頭告訴服務器,它(客戶端)是從哪一個資源來訪問服務器的(防盜鏈)
八、User-Agent:客戶機經過這個頭告訴服務器,客戶機的軟件環境(操做系統,瀏覽器版本等)
九、Cookie:客戶機經過這個頭,將Coockie信息帶給服務器
十、Connection:告訴服務器,請求完成後,是否保持鏈接
十一、Date:告訴服務器,當前請求的時間
一個http響應表明服務器端向客戶端回送的數據,它包括:
一個狀態行,若干個響應消息頭,以及實體內容
狀態行: 例如: HTTP/1.1 200 OK (協議的版本號是1.1 響應狀態碼爲200 響應結果爲 OK)
響應頭(消息頭)包含:
一、Location:這個頭配合302狀態嗎,用於告訴客戶端找誰
二、Server:服務器經過這個頭,告訴瀏覽器服務器的類型
三、Content-Encoding:告訴瀏覽器,服務器的數據壓縮格式
四、Content-Length:告訴瀏覽器,回送數據的長度
五、Content-Type:告訴瀏覽器,回送數據的類型
六、Last-Modified:告訴瀏覽器當前資源緩存時間
七、Refresh:告訴瀏覽器,隔多長時間刷新
八、Content- Disposition:告訴瀏覽器如下載的方式打開數據。例如:
context.Response.AddHeader("Content-Disposition","attachment:filename=icon.jpg");
context.Response.WriteFile("icon.jpg");
九、Transfer-Encoding:告訴瀏覽器,傳送數據的編碼格式
十、ETag:緩存相關的頭(能夠作到實時更新)
十一、Expries:告訴瀏覽器回送的資源緩存多長時間。若是是-1或者0,表示不緩存
十二、Cache-Control:控制瀏覽器不要緩存數據 no-cache
1三、Pragma:控制瀏覽器不要緩存數據 no-cache
1四、Connection:響應完成後,是否斷開鏈接。 close/Keep-Alive
1五、Date:告訴瀏覽器,服務器響應時間
九、POST和GET請求處理方式的不一樣點:
POST經過http請求的請求體日後臺服務器傳數據,數據傳遞量較大GET經過queryString的方式來傳遞數據,會自動封裝到請求行的url地址後面
十、表單要想提交數據必須具有如下條件:1)、表單標籤必需要有name屬性 2)、表單標籤不能設置爲disabled
十一、ASP.NET中三層架構:
BLL:業務邏輯層
DAL:數據訪問層
Model:實體層
Common:經常使用處理組件層
DBUtility:數據庫應用層
十二、上傳圖片文件
from的enctype屬性必定得是multipart/form-data才能傳文件
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> </head> <body> <form method="post" enctype="multipart/form-data" action="ImageUpload.ashx"> // <input type="file" name="imgFile" /> <input type="submit" value="上傳" /> </form> </body> </html>
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/html"; //拿到上傳上來的文件 HttpPostedFile file= context.Request.Files["imgFile"]; string path = "/Upload/"+Guid.NewGuid().ToString()+file.FileName; file.SaveAs(context.Request.MapPath(path)); string str = string.Format(@"<html><head></head><body><img src='{0}'/></body></html>" ,path); context.Response.Write(str); }
像上面程序這樣上傳文件有一個問題,若是上傳的是一個可執行的代碼文件會直接運行,對網站安全形成影響,因此在前端上傳的時候加一個判斷
<script src="../Scripts/jQuery-3.2.1.js"></script> <script type="text/javascript"> $(function () { $(":file").change(function () { var fileName = $(this).val(); var ext = fileName.substr(fileName.lastIndexOf(".")) if (ext == ".jpeg" || ext == ".jpg" || ext == ".png" || ext == ".gif"||ext==".bmp") { return true; } else { $(this).val(""); return false; } }); }); </script>
可是光前端判斷還不夠,這樣只能防止普通用戶誤傳文件,若是有人繞過前端直接訪問後臺,問題依然存在,因此後臺也得加判斷
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/html"; //拿到上傳上來的文件 HttpPostedFile file = context.Request.Files["imgFile"]; string ext = Path.GetExtension(file.FileName); if(!(ext == ".jpeg" || ext == ".jpg" || ext == ".png" || ext == ".gif" || ext == ".bmp")) { context.Response.Write("你是猴子請來的逗b嗎"); context.Response.End(); } else { string path = "/Upload/" + Guid.NewGuid().ToString() + file.FileName; file.SaveAs(context.Request.MapPath(path)); string str = string.Format(@"<html><head></head><body><img src='{0}'/></body></html>" , path); context.Response.Write(str); } }
1三、網站的防盜鏈
要是不作防盜鏈檢查的話,頗有可能本網站的資源會被別的網站盜鏈,至關於本網站免費給別的網站存儲數據。
下面要作的就是防盜鏈:資源通常不直接顯示在html裏面,用通常處理程序能夠在顯示前進行防盜鏈判斷,這裏要判斷當前請求是否來自本網站的域名和端口,是的話放行,不是就剁掉。
<body> <h1>這是主網站</h1> <!--<img src="a.bmp" />--> <img src="ShowImage.ashx" /> </body>
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "image/jpeg"; //判斷是不是本網站的請求,是的話放心,不是的話結束 Uri refererUrl = context.Request.UrlReferrer; //判斷:UrlRefrence的域名和端口是不是本網站的域名和端口 Uri requestUrl = context.Request.Url; if (Uri.Compare(requestUrl, refererUrl, UriComponents.HostAndPort, UriFormat.SafeUnescaped, StringComparison.CurrentCulture) == 0) { context.Response.WriteFile("a.bmp"); } else { context.Response.WriteFile("9.bmp"); } }
<body> <h1>這是子網站</h1> <img src="http://localhost:9299/FileUpload/ShowImage.ashx" /> </body>
1四、給上傳的圖片加水印文字
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script src="../Scripts/jQuery-3.2.1.js"></script> <script type="text/javascript"> $(function () { $(":file").change(function () { var fileName = $(this).val(); var ext = fileName.substr(fileName.lastIndexOf(".")) if (ext == ".jpeg" || ext == ".jpg" || ext == ".png" || ext == ".gif" || ext == ".bmp") { return true; } else { $(this).val(""); return false; } }); }); </script> </head> <body> <form method="post" enctype="multipart/form-data" action="ImageProcess.ashx"> <input type="file" name="imgFile" /> <input type="submit" value="上傳" /> </form> </body> </html>
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/html"; HttpPostedFile file = context.Request.Files["imgFile"]; if (file == null) { context.Response.End(); } //把上傳的文件作成了一個image對象 Image image = Image.FromStream(file.InputStream); Graphics graphics = Graphics.FromImage(image); string str="唐唐"; //要加的水印文字 graphics.DrawString(str, new Font("宋體", 48), new SolidBrush(Color.Blue), new PointF(image.Width - (48 * str.Length), image.Height - 96));//繪製文字到上傳的圖片 string strPath = "/Upload/" + Guid.NewGuid().ToString() + file.FileName; //申明一個保存圖片的路徑 image.Save(context.Request.MapPath(strPath), ImageFormat.Jpeg); //保存圖片到指定的路徑 string strHtml = string.Format(@"<html><head></head><body><img src='{0}'/></body></html>",strPath);//將指定路徑下的圖片放到html字符串裏 context.Response.Write(strHtml);//顯示上面拼寫的html頁面 }
1五、縮略圖
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script src="../Scripts/jQuery-3.2.1.js"></script> <script type="text/javascript"> $(function () { $(":file").change(function () { var fileName = $(this).val(); var ext = fileName.substr(fileName.lastIndexOf(".")) if (ext == ".jpeg" || ext == ".jpg" || ext == ".png" || ext == ".gif" || ext == ".bmp") { return true; } else { $(this).val(""); return false; } }); }); </script> </head> <body> <!--<form method="post" enctype="multipart/form-data" action="ImageProcess.ashx">--> <form method="post" enctype="multipart/form-data" action="SmallImage.ashx"> <input type="file" name="imgFile" /> <input type="submit" value="上傳" /> </form> </body> </html>
public class SmallImage : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "image/jpeg"; HttpPostedFile file = context.Request.Files["imgFile"]; if (file == null) { context.Response.End(); } //把上傳的文件作成了一個image對象 Image image = Image.FromStream(file.InputStream); Bitmap smallImage = new Bitmap(100, 100); Graphics g = Graphics.FromImage(smallImage); g.DrawImage(image, new Rectangle(0, 0, 100, 100), new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel); string strPath = "/Upload/Small-" + Guid.NewGuid().ToString() + file.FileName; smallImage.Save(context.Request.MapPath(strPath)); MemoryStream ms=new MemoryStream(); smallImage.Save(ms,ImageFormat.Jpeg);//把縮略圖寫到內存流 context.Response.BinaryWrite(ms.ToArray()); }
1六、asp.net基礎工做原理圖
1七、HttpApplication的處理管道19個事件。(轉)
HttpApplication對象是由Asp.NET幫助咱們建立的,它是asp.net中處理請求的重要對象。爲了便於擴展,HttpApplication採用處理管道的方式進行處理,將處理的步驟分爲多個步驟,每一個步驟經過事件的形式暴露給程序員,這些事件按照固定的處理順序依次觸發,程序員經過編寫事件處理方法就能夠定義一個請求的擴展過程。
對於HttpApplication,到ASP.Net 4.0,提供了19個標準事件。
1.BeginRequest:asp.net開始處理請求的第一個事件,表示處理的開始。
2.AuthenticateRequest:驗證請求,通常用來取得請求的用戶信息。
3.PostAuthenticateRequest:已經獲取請求的用戶信息。
4.AuthorizeRequest:受權,通常用來檢查用戶的請求是否得到權限。
5.PostAuthorizeRequest:用戶請求已經得到受權。
6.ResolveRequestCache:獲取之前處理緩存的處理結果,若是之前緩存過,那麼,不用再進行請求的處理工做,直接返回緩存的結果。
7.PostResolveRequestCache:已經完成緩存的處理工做。
8.PostMapRequestHandler:已經根據用戶的請求,建立了請求的處理器對象。
9.AcquireRequestState:取得請求的狀態,通常用於session
10.PostAcquireRequestState:已經得到了session
11.PreRequestHandlerExecute:準備執行處理程序。
12.PostRequestHandlerExecute:已經執行了處理程序
13.ReleaseRequestState:釋放請求的狀態。
14.PostReleaseRequestState:已經釋放了請求的狀態。
15.UpdateRequestCache:更新緩存。
16.PostUpdateRequestCache:已經更新了緩存。
17.LogRequest:請求的日誌操做
18.PostLogRequest:已經完成請求的日誌操做。
19.EndRequest:本次請求處理完成。
下面是請求管道中的19個事件.(轉)
(1)BeginRequest: 開始處理請求
(2)AuthenticateRequest受權驗證請求,獲取用戶受權信息
(3):PostAuthenticateRequest獲取成功
(4): AunthorizeRequest 受權,通常來檢查用戶是否得到權限
(5):PostAuthorizeRequest:得到受權
(6):ResolveRequestCache:獲取頁面緩存結果
(7):PostResolveRequestCache 已獲取緩存 當前請求映射到MvcHandler(pr): 建立控制器工廠 ,建立控制器,調用action執行,view→response
//action Handler : PR()
(8):PostMapRequestHandler 建立頁面對象:建立 最終處理當前http請求的 Handler 實例: 第一從HttpContext中獲取當前的PR Handler ,Create
(9):PostAcquireRequestState 獲取Session
(10)PostAcquireRequestState 得到Session
(11)PreRequestHandlerExecute:準備執行頁面對象 執行頁面對象的ProcessRequest方法
(12)PostRequestHandlerExecute 執行完頁面對象了
(13)ReleaseRequestState 釋放請求狀態
(14)PostReleaseRequestState 已釋放請求狀態
(15)UpdateRequestCache 更新緩存
(16)PostUpdateRequestCache 已更新緩存
(17)LogRequest 日誌記錄
(18)PostLogRequest 已完成日誌
(19)EndRequest 完成、
1八、Server.Transfer()和Response.Redirect()的區別
1)、Server.Transfer是實現了一個內部接管的效果,當瀏覽器發送請求到服務器時,服務器執行Server.Transfer將請求直接交給另一個處理程序來處理,這個過程瀏覽器是感知不到的;
2)、Response.Redriect:當瀏覽器發送請求到服務器,服務器執行Response.Redirect返回一個302相應給瀏覽器,讓瀏覽器從新請求另一個地址,這個過程瀏覽器可以感知到;
3)、綜上所述,二者實現的效果同樣,可是Server.Transfer是用後臺接管的方式實現,瀏覽器只用發起一次請求(所以只能訪問內部網站),而Respnse.Redirect須要發起兩次請求(所以能夠訪問外部網站)。
1九、ViewState:幫助咱們記住當前頁面的狀態,文本框,下拉列表的改變事件都經過此實現,其本質至關於一個內容通過Base64加密的隱藏域。適合給本身傳值
20、cookie:一小段文本,明文,存儲在客戶端瀏覽器內存裏面或磁盤,cookie和網站相關,cookie會隨請求一塊兒發送到後臺,cookie有限制:4kb字節總數據,
使用場景:記住用戶名,適用於幫助網站記住使用當前瀏覽器的用戶相關信息。若是設置了過時時間就存在磁盤上,沒有設置過時時間就存在內存。若是給cookie設置path路徑就指定在該路勁下的網頁才能使用cookie。子域能夠訪問父域的cookie,父域想要訪問子域的cookie必需要將子域的cookie建立成父域的cookie。
2一、Session:會話,就是持續的一段時間,若是是通常處理程序實現session必需要實現IRequiresSessionState接口。
2二、Application:全局變量,也能夠用來存儲數據。