1、委托:把一个方法当作参数传到另一个方法中

扩展方法:1、静态类 2、静态方法 3、this关键字

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace 委托
  8. {
  9. //扩展方法的三大步
  10. //1、静态类 2、静态方法 3、this 关键字
  11. public static class MyListExit
  12. {
  13. //this List<string> list 表示需要扩展方法的类型,即:给list<string>类型扩展一个MyWhere方法
  14. //Func<string,bool> funcWhere 传入的参数是一个泛型方法
  15. public static List<string> MyWhere(this List<string> list, Func<string, bool> funcWhere)
  16. {
  17. List<string> result = new List<string>();
  18. //遍历集合list,返回的也是一个集合
  19. foreach (var item in list)
  20. {
  21. if (funcWhere(item))
  22. {
  23. result.Add(item);
  24. }
  25. }
  26. return result;
  27. }
  28. }
  29. }

2、父窗体与子窗体间传值

1)、(委托方式)

i、在父窗体内定义一个无返回值且有一个字符串类型参数的委托

  1. //定义发布消息委托
    public Action<string> AfterMsgSend { get;set;}

ii、在子窗体内写一个传入参数为字符串类型的方法SetText作用是设置子窗体文本框的Text属性

  1. public void SetText(string str)
  2. {
  3. tbMsg.Text = str;
  4. }

iii、在父窗体的Load事件中,创建子窗体对象,然后将子窗体的SetText方法追加到委托AfterMsgSend里面,然后调用子窗体Show方法,打开子窗体

  1. private void ParentFrm_Load(object sender, EventArgs e)
  2. {
  3. ChildFrm frm = new ChildFrm();
  4. AfterMsgSend += frm.SetText;
  5. frm.Show();
  6. }

iiii、在父窗体的按钮单击事件中,先判断委托AfterMsgSend是否为空,如果为空则直接return,否则就调用委托函数

  1. private void btSendMsg_Click(object sender, EventArgs e)
  2. {
  3. //委托传值
  4. if (AfterMsgSend == null)
  5. {
  6. return;
  7. }
  8. AfterMsgSend(this.tbMsg.Text);
  9. }

2)、(事件方式)

i、在父窗体内定义一个发布消息的事件AfterMsgChangedEvent

  1. //定义一个发布消息事件
  2. public event EventHandler AfterMsgChangedEvent;

ii、在父窗体的按钮点击事件中触发事件

  1. //触发事件
    AfterMsgChangedEvent(this,new EventArgs());

iii、EventArgs不能传递参数,而我们需要给子窗体传递参数,所以我们需要自己写一个继承自EventArgs的子类TextBoxMsgChangeEventArg

  1. public class TextBoxMsgChangeEventArg:EventArgs
  2. {
  3. public string Text { get; set; }
  4. }

iiii、父窗体的触发事件就应该变成

  1. //触发事件
  2. AfterMsgChangedEvent(this, new TextBoxMsgChangeEventArg() { Text = this.tbMsg.Text });

iiiii、在子窗体创建一个满足AfterMsgChangedEvent事件类型的方法

  1. public void AfterFrmMsgChange(object sender, EventArgs e)
  2. {
  3. TextBoxMsgChangeEventArg arg = e as TextBoxMsgChangeEventArg;
  4. SetText(arg.Text);
  5. }

iiiiii、在父窗体中创建子窗体的对象,在打开之前将子窗体的AfterFrmMsgChange方法绑定到父窗体的AfterMsgChangedEvent事件上

  1. private void ParentFrm_Load(object sender, EventArgs e)
  2. {
  3. ChildFrm frm = new ChildFrm();
  4. AfterMsgChangedEvent += frm.AfterFrmMsgChange;
  5. frm.Show();
  6. }

3、发布订阅模式和观察者模式

i、写一个用来传递参数的接口Ifrmable

  1. public interface Ifrmable
  2. {
  3. void SetText(string str);
  4. }

ii、父窗体中创建一个Ifrmable类型的集合

  1. public List<Ifrmable> list { get; set; }

iii、父窗体按钮单击事件中给子窗体的接口方法传值

  1. private void btSend_Click(object sender, EventArgs e)
  2. {
  3. if (list == null)
  4. {
  5. return;
  6. }
  7. foreach (var item in list)
  8. {
  9. item.SetText(this.tbSend.Text);
  10.  
  11. }
  12. }

iiii、子窗体中实现接口方法

  1. public partial class FrmChild : Form,Ifrmable
  2. {
  3. public FrmChild()
  4. {
  5. InitializeComponent();
  6. }
  7. public void SetText(string str)
  8. {
  9. this.tbSend.Text = str;
  10. }
  11. }

iiiii、父窗体load事件中初始化子窗体对象

  1. private void FrmFather_Load(object sender, EventArgs e)
  2. {
  3. FrmFather ff = new FrmFather();
  4. FrmChild fc = new FrmChild();
  5. ff.list = new List<Ifrmable>();
  6. ff.list.Add(fc);
  7. ff.Show();
  8. fc.Show();
  9. }

5、多线程

进程:操作系统分配资源的最小单位,可以理解为一个小模块小程序

线程:一个线程就是一个进程里面的代码的执行流。每个线程都要指向一个方法体,方法执行完之后,线程就释放

线程默认是前台线程,一个进程结束的标志是所有前台线程都结束之后。

  1. static void Main(string[] args)
  2. {
  3. //创建一个线程
  4. Thread th = new Thread(delegate()
  5. {
  6. while (true)
  7. {
  8. Console.WriteLine(DateTime.Now);
  9. Thread.Sleep();
  10. }
  11. });
  12.  
  13. th.IsBackground = true;//线程默认是前台线程,一个进程结束的标志是所有前台线程都结束之后。
  14.  
  15. th.Priority = ThreadPriority.Normal;//后台线程不会组塞 进程的退出
  16.  
  17. th.Start();//告诉操作系统线程准备就绪
  18.  
  19. th.Join();//等待th执行完成
  20.  
  21. th.Abort();//不得已才能使用,直接终止线程
  22.  
  23. }

避免非子线程调用主线程创建的控件的时候报错的办法就是不检查是否存在跨线程调用

  1. public Form1()
  2. {
  3. InitializeComponent();
  4. Control.CheckForIllegalCrossThreadCalls = false; //这种方式不用在正式的项目中
  5. }

在正式的项目中解决跨线程报错的问题应该像下面这样写

  1. Thread th = new Thread(delegate() {
  2. if (btSendMsg.InvokeRequired)//InvokeRequired:如果是别的线程创建的此控件
  3. {
  4. btSendMsg.Invoke(new Action<string>(s =>
  5. {
  6. this.tbMsg.Text = s;
  7. }), DateTime.Now.ToString());
  8. }
  9. else
  10. {
  11. tbMsg.Text = DateTime.Now.ToString();
  12. }
  13. });

双色球案例

  1. public partial class WinFrmDoubleColorBall : Form
  2. {
  3. private List<Label> lbList = new List<Label>();
  4. private bool isRunning = false;
  5. public WinFrmDoubleColorBall()
  6. {
  7. InitializeComponent();
  8. //Control.CheckForIllegalCrossThreadCalls = false;
  9. }
  10.  
  11. private void WinFrmDoubleColorBall_Load(object sender, EventArgs e)
  12. {
  13. for (int i = ; i < ; i++)
  14. {
  15. Label lb = new Label();
  16. lb.Text = "";
  17. lb.AutoSize = true;
  18.  
  19. lb.Location = new Point( * i + , );
  20. this.Controls.Add(lb);
  21. lbList.Add(lb);
  22. }
  23. }
  24.  
  25. private void btStart_Click(object sender, EventArgs e)
  26. {
  27. isRunning = true;
  28. Thread th = new Thread(delegate()
  29. {
  30. Random r = new Random();
  31. while (isRunning)
  32. {
  33. foreach (var item in lbList)
  34. {
  35. string str=r.Next(, ).ToString();
  36. if (item.InvokeRequired)
  37. {
  38. item.Invoke(new Action<string>(delegate(string s) { item.Text = s; }), str);
  39. //item.Invoke(new Action<string>(s => { item.Text = s; }
  40.  
  41. // ),str);
  42. }
  43. else
  44. {
  45. item.Text = str;
  46. }
  47.  
  48. }
  49. Thread.Sleep();
  50. }
  51. });
  52. th.IsBackground = true;
  53. th.Start();
  54. }
  55.  
  56. private void btStop_Click(object sender, EventArgs e)
  57. {
  58. isRunning = false;
  59. }
  60. }

6、对象池技术

为什么有链接池?1)、链接对象创建非常消耗资源 2)、考虑到对象的重用

避免死锁:1)、sql操作表的顺序尽量一致 2)把查询sql中加with(nolock) 3)、因为链接非常多引起的死锁,可以用临时表来解决 4)、分库:水平分库,垂直分库 5)、数据库集群,读写分离

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. //创建一个池子
  6. MyConnection[] connectArry=new MyConnection[];
  7.  
  8. //索引
  9. int index = -;
  10.  
  11. //创建10个消费者
  12. for (int i = ; i < ; i++)
  13. {
  14. Thread th = new Thread(() => {
  15. while (true)
  16. {
  17. lock(connectArry) //lock后面要跟一个引用类型的实例,锁住同一个对象(引用的地址)就互斥
  18. {
  19. if (index > )
  20. {
  21. connectArry[index+] = null;
  22. Console.WriteLine("消费了一个产品:"+index);
  23. index--;
  24. }
  25. }
  26. Thread.Sleep();
  27. }
  28. });
  29. th.IsBackground = true;
  30. th.Start();
  31. }
  32.  
  33. //创建5个生产者
  34. for (int i = ; i <; i++)
  35. {
  36. Thread th = new Thread(() =>
  37. {
  38. while (true)
  39. {
  40. lock(connectArry)
  41. {
  42. if (index < )
  43. {
  44. connectArry[index+] = new MyConnection();
  45. Console.WriteLine("生产了一个产品:" + (index+));
  46. index++;
  47. }
  48. }
  49. Thread.Sleep();
  50. }
  51. });
  52. th.IsBackground = true;
  53. th.Start();
  54. }
  55. Console.ReadKey();
  56. }
  57. }
  58. public class MyConnection
  59. {
  60.  
  61. }

线程池的线程本身都是后台线程,优势在于线程可以进行重用,缺点在于不灵活(不能手动停止)

  1. ThreadPool.QueueUserWorkItem((s) =>
  2. {
  3. Console.WriteLine(s);
  4. });

上面的线程池过程和下面的队列操作是一样的原理,区别就是下面这个是先进先出的

  1. Queue<WaitCallback> queue = new Queue<WaitCallback>(); //创建一个队列
  2. queue.Enqueue((s) => //进队列
  3. {
  4. Console.WriteLine(s);
  5. });

什么时候用线程池?什么时候用手动创建线程?

1)、能用线程池就用线程池,处理的顺序不确定。

2)、想手动关闭线程就必须手动创建线程(Abort(),Join())

3)、需要对线程的优先级做设置必须手动创建线程

4)、如果执行的线程时间特别长,线程池适合用于做大量的小运算。

获取系统最大可设置线程数与实际设置最大线程数

  1. //获取线程池最大线程数据
  2. int numMax = ;
  3. int runNumMax = ;
  4. ThreadPool.GetMaxThreads(out numMax, out runNumMax);
  5. Console.WriteLine(numMax + " " + runNumMax);

7、异步调用委托:与手动创建线程比较的优势在于可以拿到线程执行的结果1)、无回调函数的异步委托

  1. static void Main(string[] args)
  2. {
  3. //创建一个委托
  4. Func<int, int, string> func = delegate(int a, int b) { return (a + b).ToString(); };
  5. //异步调用委托
  6. IAsyncResult result = func.BeginInvoke(, , null, null);
  7. //异步获取委托返回的结果,EndInvoke方法会阻塞当前线程,直到异步委托指向的方法执行完毕才会继续往下执行
  8. string str = func.EndInvoke(result);
  9. Console.WriteLine(str);
  10. Console.ReadKey();
  11. }

2)、有回调函数的异步委托

  1. static void Main(string[] args)
  2. {
  3. //创建一个委托
  4. Func<int, int, string> func = delegate(int a, int b) { return (a + b).ToString(); };
  5. //异步调用委托
  6. func.BeginInvoke(, , MyAsyncCallback, "");
  7. Console.ReadKey();
  8. }
  9. public static void MyAsyncCallback(IAsyncResult ar)
  10. {
  11. //1、拿到异步委托执行的结果
  12. AsyncResult result = (AsyncResult)ar; //强转成AsyncResult类型
  13. var del = (Func<int, int, string>)result.AsyncDelegate; //强转成Func<int, int, string>类型
  14. string str = del.EndInvoke(result);
  15. Console.WriteLine("异步回调函数的返回结果是:"+str); //7
  16. //2、拿到回掉函数参数
  17. Console.WriteLine("回调函数拿到的参数是:" + result.AsyncState); //
  18. }
  1. static void Main(string[] args)
  2. {
  3. //创建一个委托
  4. Func<int, int, string> func = delegate(int a, int b) { return (a + b).ToString(); };
  5. //异步调用委托
  6. func.BeginInvoke(, , MyAsyncCallback, func); //最后直接把委托func当成参数传给回调函数
  7. Console.ReadKey();
  8. }
  9. public static void MyAsyncCallback(IAsyncResult ar)
  10. {
  11. var del = (Func<int, int, string>)ar.AsyncState; //直接将传进来的参数强转成Func<int, int, string>类型,
  12. string str = del.EndInvoke(ar);
  13. Console.WriteLine("异步回调函数的返回结果是:"+str); //
  14. }
  1. static void Main(string[] args)
  2. {
  3. //创建一个委托
  4. Func<string, string, bool> func = delegate(string stra, string strb) { return stra == strb; };
  5. func.BeginInvoke("", "", MyCallback, func);
  6. Console.ReadKey();
  7. }
  8.  
  9. private static void MyCallback(IAsyncResult ar)
  10. {
  11. Func<string, string, bool> del = (Func<string, string, bool>)ar.AsyncState;
  12. bool b = del.EndInvoke(ar);
  13. if (b)
  14. {
  15. Console.WriteLine("相等");
  16. }
  17. else
  18. {
  19. Console.WriteLine("不等");
  20. }
  21. }

7、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. //1、获取本机IP
  30. //IPAddress[] ipAddress = Dns.GetHostAddresses(Dns.GetHostName());
  31. IPAddress iP = IPAddress.Parse(tbIp.Text);
  32. //2、创建一个用于监听的Socket
  33. Socket serverSocket = new Socket(
  34. AddressFamily.InterNetwork,
  35. SocketType.Stream,
  36. ProtocolType.Tcp
  37. );
  38. //3、绑定IP
  39. IPEndPoint ipEndPoint=new IPEndPoint(iP,Convert.ToInt32(tbPort.Text));
  40. serverSocket.Bind(ipEndPoint);
  41.  
  42. ReceiveText("服务端开始监听");
  43. //4、建立监听队列,默认为10
  44. serverSocket.Listen();
  45.  
  46. //5、主线程一直负责监听,线程池的线程来接受客户端连接请求
  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[ * ];
  71. while (true)
  72. {
  73. int iReceive=;
  74. try
  75. {
  76. iReceive = proxSocket.Receive(buffer, , buffer.Length, SocketFlags.None);
  77. }
  78. catch
  79. {
  80.  
  81. }
  82. if (iReceive <= )
  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[] == )
  97. {
  98. ReceiveText("收到来自:" + proxSocket.RemoteEndPoint + "的消息:" + Encoding.Default.GetString(buffer, , iReceive-));
  99. }
  100. else if (buffer[] == )
  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 - ];
  111. Buffer.BlockCopy(buffer, , fileData, , buffer.Length - );
  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, , 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 + ];
  149. buffer[] = ;
  150. Buffer.BlockCopy(data, , buffer, , data.Length);
  151. item.Send(buffer, , 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 + ];
  159. buffer[] = ;
  160. Buffer.BlockCopy(data, , buffer, , data.Length);
  161. item.Send(buffer, , 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 + ];
  208. buffer[] = ;
  209. Buffer.BlockCopy(data, , buffer, , data.Length);
  210. s.Send(buffer, , 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 + ];
  217. buffer[] = ;
  218. Buffer.BlockCopy(data, , buffer, , data.Length);
  219. s.Send(buffer, , 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 + ];
  230. buffer[] = ;
  231. Buffer.BlockCopy(data, , buffer, , data.Length);
  232. item.Send(buffer, , 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 + ];
  239. buffer[] = ;
  240. Buffer.BlockCopy(data, , buffer, , data.Length);
  241. item.Send(buffer, , 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. //1、获取本机IP
  30. //IPAddress[] ipAddress = Dns.GetHostAddresses(Dns.GetHostName());
  31. IPAddress iP = IPAddress.Parse(tbIp.Text);
  32. //2、创建一个用于链接的Socket
  33. Socket clientSocket = new Socket(
  34. AddressFamily.InterNetwork,
  35. SocketType.Stream,
  36. ProtocolType.Tcp
  37. );
  38. //3、绑定IP
  39. IPEndPoint ipEndPoint = new IPEndPoint(iP, Convert.ToInt32(tbPort.Text));
  40.  
  41. //4、开始链接
  42. clientSocket.Connect(ipEndPoint);
  43. ClientSocket = clientSocket;
  44. ReceiveText("到服务端:" + clientSocket.RemoteEndPoint + "链接成功");
  45. ThreadPool.QueueUserWorkItem((s) =>
  46. {
  47. byte[] buffer = new byte[ * ];
  48. while (true)
  49. {
  50. int iReceive = ;
  51. try
  52. {
  53. iReceive = clientSocket.Receive(buffer, , buffer.Length, SocketFlags.None);
  54. }
  55. catch
  56. {
  57.  
  58. }
  59. if (iReceive <= )
  60. {
  61. ReceiveText("断开与服务端:" + clientSocket.RemoteEndPoint + "链接");
  62. return;
  63. }
  64. if (buffer[] == )
  65. {
  66. ReceiveText("收到服务端" + clientSocket.RemoteEndPoint + "发来的消息:" + Encoding.Default.GetString(buffer, , iReceive-));
  67. }
  68. else if (buffer[] == )
  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 - ];
  79. Buffer.BlockCopy(buffer, , fileData, , buffer.Length - );
  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, , 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+];
  114. buffer[] = ;
  115. Buffer.BlockCopy(data, , buffer, , data.Length);
  116. ClientSocket.Send(buffer, , 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 + ];
  153. buffer[] = ;
  154. Buffer.BlockCopy(data, , buffer, , data.Length);
  155. ClientSocket.Send(buffer, , 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. }

8、Response.Redirect原理

请求头(消息头)包含(客户机请求的服务器主机名,客户机的环境信息等):

1、Accept:用于告诉服务器,客户机支持的数据类型 (例如:Accept:text/html,image/*)

2、Accept-Charset:用于告诉服务器,客户机采用的编码格式

3、Accept-Encoding:用于告诉服务器,客户机支持的数据压缩格式

4、Accept-Language:客户机语言环境

5、Host:客户机通过这个服务器,想访问的主机名

6、If-Modified-Since:客户机通过这个头告诉服务器,资源的缓存时间

7、Referer:客户机通过这个头告诉服务器,它(客户端)是从哪个资源来访问服务器的(防盗链)

8、User-Agent:客户机通过这个头告诉服务器,客户机的软件环境(操作系统,浏览器版本等)

9、Cookie:客户机通过这个头,将Coockie信息带给服务器

10、Connection:告诉服务器,请求完成后,是否保持连接

11、Date:告诉服务器,当前请求的时间

一个http响应代表服务器端向客户端回送的数据,它包括:

一个状态行,若干个响应消息头,以及实体内容

状态行: 例如: HTTP/1.1 200 OK (协议的版本号是1.1 响应状态码为200 响应结果为 OK)

响应头(消息头)包含:

1、Location:这个头配合302状态吗,用于告诉客户端找谁

2、Server:服务器通过这个头,告诉浏览器服务器的类型

3、Content-Encoding:告诉浏览器,服务器的数据压缩格式

4、Content-Length:告诉浏览器,回送数据的长度

5、Content-Type:告诉浏览器,回送数据的类型

6、Last-Modified:告诉浏览器当前资源缓存时间

7、Refresh:告诉浏览器,隔多长时间刷新

8、Content- Disposition:告诉浏览器以下载的方式打开数据。例如:

context.Response.AddHeader("Content-Disposition","attachment:filename=icon.jpg");

context.Response.WriteFile("icon.jpg");

9、Transfer-Encoding:告诉浏览器,传送数据的编码格式

10、ETag:缓存相关的头(可以做到实时更新)

11、Expries:告诉浏览器回送的资源缓存多长时间。如果是-1或者0,表示不缓存

12、Cache-Control:控制浏览器不要缓存数据 no-cache

13、Pragma:控制浏览器不要缓存数据 no-cache

14、Connection:响应完成后,是否断开连接。 close/Keep-Alive

15、Date:告诉浏览器,服务器响应时间

9、POST和GET请求处理方式的不同点:

POST通过http请求的请求体往后台服务器传数据,数据传递量较大GET通过queryString的方式来传递数据,会自动封装到请求行的url地址后面

10、表单要想提交数据必须具备以下条件:1)、表单标签必须要有name属性 2)、表单标签不能设置为disabled

11、ASP.NET中三层架构:

BLL:业务逻辑层

DAL:数据访问层

Model:实体层

Common:常用处理组件层

DBUtility:数据库应用层

12、上传图片文件

  1. fromenctype属性一定得是multipart/form-data才能传文件
  1. <!DOCTYPE html>
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  5. <title></title>
  6. </head>
  7. <body>
  8. <form method="post" enctype="multipart/form-data" action="ImageUpload.ashx"> //
  9. <input type="file" name="imgFile" />
  10. <input type="submit" value="上传" />
  11. </form>
  12. </body>
  13. </html>
  1. public void ProcessRequest(HttpContext context)
  2. {
  3. context.Response.ContentType = "text/html";
  4. //拿到上传上来的文件
  5. HttpPostedFile file= context.Request.Files["imgFile"];
  6. string path = "/Upload/"+Guid.NewGuid().ToString()+file.FileName;
  7. file.SaveAs(context.Request.MapPath(path));
  8. string str = string.Format(@"<html><head></head><body><img src='{0}'/></body></html>"
  9. ,path);
  10. context.Response.Write(str);
  11. }

像上面程序这样上传文件有一个问题,如果上传的是一个可执行的代码文件会直接运行,对网站安全造成影响,所以在前端上传的时候加一个判断

  1. <script src="../Scripts/jQuery-3.2.1.js"></script>
  2. <script type="text/javascript">
  3. $(function () {
  4. $(":file").change(function () {
  5. var fileName = $(this).val();
  6. var ext = fileName.substr(fileName.lastIndexOf("."))
  7. if (ext == ".jpeg" || ext == ".jpg" || ext == ".png" || ext == ".gif"||ext==".bmp") {
  8. return true;
  9. } else {
  10. $(this).val("");
  11. return false;
  12. }
  13. });
  14. });
  15. </script>

但是光前端判断还不够,这样只能防止普通用户误传文件,如果有人绕过前端直接访问后台,问题依然存在,所以后台也得加判断

  1. public void ProcessRequest(HttpContext context)
  2. {
  3. context.Response.ContentType = "text/html";
  4. //拿到上传上来的文件
  5. HttpPostedFile file = context.Request.Files["imgFile"];
  6. string ext = Path.GetExtension(file.FileName);
  7. if(!(ext == ".jpeg" || ext == ".jpg" || ext == ".png" || ext == ".gif" || ext == ".bmp"))
  8. {
  9. context.Response.Write("你是猴子请来的逗b吗");
  10. context.Response.End();
  11. }
  12. else
  13. {
  14. string path = "/Upload/" + Guid.NewGuid().ToString() + file.FileName;
  15. file.SaveAs(context.Request.MapPath(path));
  16. string str = string.Format(@"<html><head></head><body><img src='{0}'/></body></html>"
  17. , path);
  18. context.Response.Write(str);
  19. }
  20. }

13、网站的防盗链

要是不做防盗链检查的话,很有可能本网站的资源会被别的网站盗链,相当于本网站免费给别的网站存储数据。

下面要做的就是防盗链:资源一般不直接显示在html里面,用一般处理程序可以在显示前进行防盗链判断,这里要判断当前请求是否来自本网站的域名和端口,是的话放行,不是就剁掉。

  1. <body>
  2. <h1>这是主网站</h1>
  3. <!--<img src="a.bmp" />-->
  4. <img src="ShowImage.ashx" />
  5. </body>
  1. public void ProcessRequest(HttpContext context)
  2. {
  3. context.Response.ContentType = "image/jpeg";
  4. //判断是否是本网站的请求,是的话放心,不是的话结束
  5. Uri refererUrl = context.Request.UrlReferrer;
  6. //判断:UrlRefrence的域名和端口是否是本网站的域名和端口
  7. Uri requestUrl = context.Request.Url;
  8. if (Uri.Compare(requestUrl, refererUrl, UriComponents.HostAndPort, UriFormat.SafeUnescaped, StringComparison.CurrentCulture) == )
  9. {
  10. context.Response.WriteFile("a.bmp");
  11. }
  12. else
  13. {
  14. context.Response.WriteFile("9.bmp");
  15. }
  16. }
  1. <body>
  2. <h1>这是子网站</h1>
  3. <img src="http://localhost:9299/FileUpload/ShowImage.ashx" />
  4.  
  5. </body>

14、给上传的图片加水印文字

  1. <html xmlns="http://www.w3.org/1999/xhtml">
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  4. <title></title>
  5. <script src="../Scripts/jQuery-3.2.1.js"></script>
  6. <script type="text/javascript">
  7. $(function () {
  8. $(":file").change(function () {
  9. var fileName = $(this).val();
  10. var ext = fileName.substr(fileName.lastIndexOf("."))
  11. if (ext == ".jpeg" || ext == ".jpg" || ext == ".png" || ext == ".gif" || ext == ".bmp") {
  12. return true;
  13. } else {
  14. $(this).val("");
  15. return false;
  16. }
  17. });
  18. });
  19. </script>
  20. </head>
  21. <body>
  22. <form method="post" enctype="multipart/form-data" action="ImageProcess.ashx">
  23. <input type="file" name="imgFile" />
  24. <input type="submit" value="上传" />
  25. </form>
  26. </body>
  27. </html>
  1. public void ProcessRequest(HttpContext context)
  2. {
  3. context.Response.ContentType = "text/html";
  4. HttpPostedFile file = context.Request.Files["imgFile"];
  5. if (file == null)
  6. {
  7. context.Response.End();
  8. }
  9. //把上传的文件做成了一个image对象
  10. Image image = Image.FromStream(file.InputStream);
  11.  
  12. Graphics graphics = Graphics.FromImage(image);
  13. string str="唐唐"; //要加的水印文字
  14. graphics.DrawString(str, new Font("宋体", ), new SolidBrush(Color.Blue), new PointF(image.Width - ( * str.Length), image.Height - ));//绘制文字到上传的图片
  15. string strPath = "/Upload/" + Guid.NewGuid().ToString() + file.FileName; //申明一个保存图片的路径
  16. image.Save(context.Request.MapPath(strPath), ImageFormat.Jpeg); //保存图片到指定的路径
  17. string strHtml = string.Format(@"<html><head></head><body><img src='{0}'/></body></html>",strPath);//将指定路径下的图片放到html字符串里
  18. context.Response.Write(strHtml);//显示上面拼写的html页面
  19. }

15、缩略图

  1. <html xmlns="http://www.w3.org/1999/xhtml">
  2. <head>
  3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  4. <title></title>
  5. <script src="../Scripts/jQuery-3.2.1.js"></script>
  6. <script type="text/javascript">
  7. $(function () {
  8. $(":file").change(function () {
  9. var fileName = $(this).val();
  10. var ext = fileName.substr(fileName.lastIndexOf("."))
  11. if (ext == ".jpeg" || ext == ".jpg" || ext == ".png" || ext == ".gif" || ext == ".bmp") {
  12. return true;
  13. } else {
  14. $(this).val("");
  15. return false;
  16. }
  17. });
  18. });
  19. </script>
  20. </head>
  21. <body>
  22. <!--<form method="post" enctype="multipart/form-data" action="ImageProcess.ashx">-->
  23. <form method="post" enctype="multipart/form-data" action="SmallImage.ashx">
  24. <input type="file" name="imgFile" />
  25. <input type="submit" value="上传" />
  26. </form>
  27. </body>
  28. </html>
  1. public class SmallImage : IHttpHandler
  2. {
  3.  
  4. public void ProcessRequest(HttpContext context)
  5. {
  6. context.Response.ContentType = "image/jpeg";
  7. HttpPostedFile file = context.Request.Files["imgFile"];
  8. if (file == null)
  9. {
  10. context.Response.End();
  11. }
  12. //把上传的文件做成了一个image对象
  13. Image image = Image.FromStream(file.InputStream);
  14. Bitmap smallImage = new Bitmap(, );
  15. Graphics g = Graphics.FromImage(smallImage);
  16. g.DrawImage(image, new Rectangle(, , , ), new Rectangle(, , image.Width, image.Height),
  17. GraphicsUnit.Pixel);
  18. string strPath = "/Upload/Small-" + Guid.NewGuid().ToString() + file.FileName;
  19. smallImage.Save(context.Request.MapPath(strPath));
  20. MemoryStream ms=new MemoryStream();
  21. smallImage.Save(ms,ImageFormat.Jpeg);//把缩略图写到内存流
  22. context.Response.BinaryWrite(ms.ToArray());
  23. }

16、asp.net基础工作原理图

17、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 完成、

18、Server.Transfer()和Response.Redirect()的区别

1)、Server.Transfer是实现了一个内部接管的效果,当浏览器发送请求到服务器时,服务器执行Server.Transfer将请求直接交给另外一个处理程序来处理,这个过程浏览器是感知不到的;

2)、Response.Redriect:当浏览器发送请求到服务器,服务器执行Response.Redirect返回一个302相应给浏览器,让浏览器重新请求另外一个地址,这个过程浏览器能够感知到;

3)、综上所述,两者实现的效果一样,但是Server.Transfer是用后台接管的方式实现,浏览器只用发起一次请求(因此只能访问内部网站),而Respnse.Redirect需要发起两次请求(因此可以访问外部网站)。

19、ViewState:帮助我们记住当前页面的状态,文本框,下拉列表的改变事件都通过此实现,其本质相当于一个内容经过Base64加密的隐藏域。适合给自己传值

20、cookie:一小段文本,明文,存储在客户端浏览器内存里面或磁盘,cookie和网站相关,cookie会随请求一起发送到后台,cookie有限制:4kb字节总数据,

使用场景:记住用户名,适用于帮助网站记住使用当前浏览器的用户相关信息。如果设置了过期时间就存在磁盘上,没有设置过期时间就存在内存。如果给cookie设置path路径就指定在该路劲下的网页才能使用cookie。子域可以访问父域的cookie,父域想要访问子域的cookie必须要将子域的cookie创建成父域的cookie。

21、Session:会话,就是持续的一段时间,如果是一般处理程序实现session必须要实现IRequiresSessionState接口。

22、Application:全局变量,也可以用来存储数据。

ASP.NET相关的更多相关文章

  1. asp.net相关的一些代码

    显示目录下的内容 using System.IO; DirectoryInfo di = new DirectoryInfo(Server.MapPath("Views/video" ...

  2. ASP.NET相关事件及JS的执行顺序

    实验代码: ASPX: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="We ...

  3. ASP.NET相关技术整理

  4. ASP.NET 相关小知识

    后台修改前台html控件属性 添加 runat=server ,后台获取// 客户端隐藏 a.Attributes[ "style "] = "display:none ...

  5. Asp.net相关知识和经验的碎片化记录

    1.解决IIS7.0下“HTTP 错误 404.15 - Not Found 请求筛选模块被配置为拒绝包含的查询字符串过长的请求”问题 方案1:在程序的web.config中system.web节点里 ...

  6. 分享阿里云推荐码 IC1L2A,购买服务器可以直接打9折,另附阿里云服务器部署ASP.NET MVC5关键教程

    阿里云推荐码为:IC1L2A 阿里云还是不错滴. 以windows server 2008 R2为例,介绍如何从全新的服务器部署MVC5 站点. 新购买的阿里云服务器是没有IIS的,要安装IIS: 控 ...

  7. 解读ASP.NET 5 & MVC6系列(4):核心技术与环境配置

    asp.net 5是下一代的asp.net,该版本进行了全部重写以适用于跨平台,新新版本中,微软引入了如下工具与命令:DNVM.DNX.DNU. DNVM(.NET Version Manager): ...

  8. 初识ASP.NET Core 1.0

    本文将对微软下一代ASP.NET框架做个概括性介绍,方便大家进一步熟悉该框架. 在介绍ASP.NET Core 1.0之前有必要澄清一些产品名称及版本号.ASP.NET Core1.0是微软下一代AS ...

  9. ASP.NET MVC 从零开始 - Web.config

    这篇文章是从我的 github 博客 http://lxconan.github.io 导入的. 在上一篇中,我们从零开始创建了一个非常简单的 ASP.NET MVC 应用程序.接下来,你是不是期望我 ...

随机推荐

  1. <正则吃饺子> :关于gson使用的一点总结

    一.场景 在群里看到的信息:在使用 gson时候,报了个错 :java.lang.IllegalArgumentException:   declares multiple JSON fields n ...

  2. linux日常管理-curl工具

    curl 在linux命令行中用于访问网站,下载东西, 可以用 curl www.qq.com 访问 出现很多源代码 ///////////////////////////////////////// ...

  3. URL网址规范化

    网址URL规范化(URL canonicalization)是近一年来在Google搜索结果中出现的一个很大的问题.它指的是搜索引擎挑选最好的URL网址作为真正网址的过程.举例来说,下面这几个URL一 ...

  4. JDBC操作MySQL(crud)

    这两天复习了一下JDBC操作MySQL,把crud操作的例子记一下, 类库链接(mysql-connector-java-5.1.37-bin.jar):http://files.cnblogs.co ...

  5. mongodb 修改操作

    $addToSet与$each结合完成批量数组更新 db.text.update({_id:1000},{$addToSet:{books:{$each:["js","d ...

  6. hibernate&nbsp;hql&nbsp;查询指定…

    以数组的形式抛出,前台页面就要把它当成一个数组来处理 以对象抛出,就要当成一个对象来处理. 在JSP页面使用标签时一定要注意这点. 版权声明:本文为博主原创文章,未经博主允许不得转载.

  7. Python开发【第三篇】:分支循环

    1. if 条件语句   语法: if 条件: 代码块 # 条件为真执行 else: # else 可选 代码块 # 条件为假执行   示例: n = int(input('请输入一个数字:')) i ...

  8. PHP开源系统学习之fluxbb_2

    谴责下某位同学,转载了我的上一篇文章,也不给个原文地址,希望这次再来转时能加上. //检查登录,在common.php判断 //cookie串: 2|dc4fab5bb354be5104bae0aff ...

  9. sed命令使用

    创建模板文件 # cat >> example.txt <<"EOF" TeSt Test test EOF 测试过程中均不使用-i参数避免模板文件内容被修 ...

  10. elementary os变成mac风(笔记)

    sudo add-apt-repository ppa:philip.scott/elementary-tweaks && sudo apt-get update sudo apt-g ...