孵蛋机

说不定哪颗蛋就从这里出去,成为独当一面的文章呢

Posted by Elias on August 4, 2020

孵蛋机

前言

无数不成体系的养料都在这里,等待成为一个蛋,等待被孵化。

GDI绘图(C#)

​ C#中使用GDI绘图,需要using System.Drawing;

  1. GDI简单绘图

    想要绘制图形,首先需要有承载图形的画板和用于绘图的画笔。

    //创建GDI对象
    Graphics graphics = this.CreateGraphics();
    //创建画笔对象
    Pen pen = new Pen(Brushes.Red);
    

    绘制直线

    //创建两个点
    Point p1 = new Point(30, 50);
    Point p2 = new Point(100, 100);
    //绘制线
    graphics.DrawLine(pen,p1,p2);
    

    绘制矩形

    Size size = new Size(140, 50);
    Rectangle rec = new Rectangle(new Point(130, 50), size);
    graphics.DrawRectangle(pen, rec);
    

    绘制扇形

    Size size = new Size(140, 140);
    Rectangle rec = new Rectangle(new Point(280, 0), size);
    graphics.DrawPie(pen,rec,60,60);
    

    绘制字符串

    graphics.DrawString(
    	"要绘制的字符串",
    	new Font("宋体",20,FontStyle.Bold),
    	Brushes.Black,
    	new Point(430,50));
    

    绘制指定图片

    graphics.DrawImage(
        Image.FromFile(@"这是图片路径"),
    	x,
    	y,
    	width,
    	height);
    
  2. GDI绘图时消除闪烁现象(使用双缓冲)

    当所需绘制的图形过多且希望部分图片移动时,界面往往由于不断对图形进行绘制,且由于所有待绘制图形不能同时绘制,因此会出现部分图形先出现,部分图形后出现的现象,再加上刷新频率较快,因此导致闪烁。

    消除闪烁的方法很简单,只需我们将图形全部先绘制在虚拟画布上(而不是直接绘制在窗体上),在一次绘制完成后,再将该画布内容一次性画到窗体上,就能够避免闪烁现象。这一方法也叫做双缓冲技术

    为了实现这一技术,我们首先需要在相应窗体的InitializeComponent()中加入:

    this.DoubleBuffered = true;//双缓冲
    

    以此开启开窗体的双缓冲。

    接着需要创建一张虚拟画布,并将所有待绘制图形全部绘制到该虚拟画布上:

    //建立虚拟画布
    Bitmap bitp = new Bitmap(this.Width, this.Height);
    //将所有绘图操作绑定在虚拟画布上
    Graphics g = Graphics.FromImage(bitp);
    //开始绘图
    ......
    //所有待绘制图形绘制完毕后,将虚拟画布上的内容绘制到窗体
    this.CreateGraphics().DrawImage(bitp, 0, 0);
    //单次绘图完毕后释放绘制资源
    g.Dispose();
    //释放虚拟画布资源
    bitp.Dispose();
    

    至此,就通过使用双缓冲解决了GDI窗体绘图闪烁问题。

    至于窗体内控件使用过多导致窗体闪烁的问题,将通过另一方式实现,即在窗体的InitializeComponent()中加入一些代码,这里不再细说,有需要可以网上搜搜(绝对是因为我太懒才不写的!)

HTTP协议

希望能够使用HTTP进行信息传递

HTTP请求/相应步骤:

  1. 客户端连接到Web服务器:

    一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。

  2. 发送HTTP请求

    通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文请求行请求头部空行请求数据4部分组成。

  3. 服务器接收请求并返回HTTP相应

    Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应状态行响应头部空行响应数据4部分组成。

  4. 释放连接TCP连接

    若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求。

  5. 客户端浏览器解析HTML内容

    客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。

HTTP协议是基于TCP/IP协议之上的应用层协议

HTTP请求方法

HTTP/1.1协议中定义了8种方法,通过8种不同的方式操作指定的资源:

  1. GET:获取资源

    GET方法用来请求已被URI(URI与URL的区别见下方)识别的资源。指定的资源经服务器端解析后返回响应内容(也就是说,如果请求的资源是文本,那就保持原样返回;如果是CGI[通用网关接口]那样的程序,就返回经过执行后的输出结果)。

    该方法最常用于向服务器查询某些信息。

URI与URL的区别

URI表示的是web上每一种可用的资源,比如说HTML文档、图像、视频片段、程序等都是由一个URI进行标识的。而URL是URI的一个子集,采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。URL是URI概念的一种实现方式。

区别:URI是一种语义上的抽象概念,可以是绝对的,也可以是相对的,而URL则必须提供足够的信息来定位,是绝对的。

比如:URI:http://www.123.com/123/,该目录下可能有index.html和index.htm两个文件;而URL:http://www.123.com/123/index.html,则唯一指向一个文件。

  1. POST:传输实体文本

    POST方法用来传输实体的主体。

    向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。

  2. HEAD:获得报文首部

    HEAD方法与GET方法一样,只是不会返回报文的主体部分(向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分)。其好处在于可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据)。

  3. PUT:传输文件

    向指定资源位置上传其最新内容。

    PUT方法用来传输文件,就像FTP协议的文件上传一样,要求在请求报文的主体中包含文件内容,然后保存在请求URI指定的位置。

  4. DELETE:删除文件

    指明客户端想让服务器删除某个资源,与PUT方法相反,按URI删除指定资源。

  5. OPTIONS:询问支持的方法

    OPTIONS方法用来查询针对请求URI指定资源支持的方法(客户端询问服务器可以提交哪些请求方法)。

  6. TRACE:追踪路径

    客户端可以对请求消息的传输路径进行追踪,TRACE方法是让Web服务器端将之前的请求通信还给客户端的方法。

  7. CONNECT:要求用隧道协议连接代理

    CONNECT方法要求在与代理服务器通信时建立隧道,实现用隧道协议进行TCP通信。主要使用SSL(安全套接层)和TLS(传输层安全)协议把通信内容加密后经网络隧道传输。

HTTP请求格式(请求协议)

httpRequest

httpRequest1

HTTP相应格式(响应协议)

httpResponse

httpResponse1

使用HTTP协议向服务器接口/网站上传文件

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace HttpTest
{
    public class HttpUploadFile
    {
        /// <summary>
        /// Http上传文件
        /// </summary>

        public static string httpUploadFile(string url, string path)
        {
            //
            // 设置参数
            //
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;

            CookieContainer cookieContainer = new CookieContainer();

            request.CookieContainer = cookieContainer;

            request.AllowAutoRedirect = true;

            request.Method = "POST";

            string boundary = DateTime.Now.Ticks.ToString("X"); // 随机分隔线

            request.ContentType = "multipart/form-data;charset=utf-8;boundary=" + boundary;

            byte[] itemBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");

            byte[] endBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
            //
            //获取文件名
            //
            int pos = path.LastIndexOf(@"\");//查找该字符串中"\"最后出现的位置
			//得到文件名
            string fileName = path.Substring(pos + 1);//从字符串指定位置一直读取到字符串末尾
            //
            //请求头部信息 
            //
            StringBuilder sbHeader = new StringBuilder(string.Format("Content-Disposition:form-data;name=\"file\";filename=\"{0}\"\r\nContent-Type:application/octet-stream\r\n\r\n", fileName));

            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(sbHeader.ToString());
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);

            byte[] bArr = new byte[fs.Length];

            fs.Read(bArr, 0, bArr.Length);

            fs.Close();
            Stream postStream = request.GetRequestStream();

            postStream.Write(itemBoundaryBytes, 0, itemBoundaryBytes.Length);

            postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

            postStream.Write(bArr, 0, bArr.Length);

            postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);

            postStream.Close();
            //
            //发送请求并获取相应回应数据
            //
            HttpWebResponse response = request.GetResponse() as HttpWebResponse;
            //
            //直到request.GetResponse()程序才开始向目标网页发送Post请求
            //
            Stream instream = response.GetResponseStream();

            StreamReader sr = new StreamReader(instream, Encoding.UTF8);
            //
            //返回结果网页(html)代码
            //
            string content = sr.ReadToEnd();

            return content;
        }
    }
}

C#

  1. 打开文件对话框

    ​ ——迁移至《面向快乐的C#编程》·C#文件操作

     

  2. Action(()=>{代码;})

    第一眼看到这个代码还是一脸懵比的,不知道是在干啥,接着就去百度查了一下。下面是对这些代码的一个理解。

    首先,这是一个简写形式,这种简写是lambda表达式。这个简写形式还原后,其实就是一个匿名委托

    ()=>{代码;}这个表达式,最前面的小括号内()是委托使用的参数,大括号{}内是委托方法的具体实现,这里的小括号为空,也就是说这个委托的参数为空,这就是封装了一个不包含任何参数的方法。把它换成一般的委托定义就是:

    delegate void CommonDelegate();
    

    而匿名函数并不具备类型,因此需要进行强制转换,所以在前面加上了Action,表示将匿名方法转换成标注的委托类型。Action是.NET自定义的委托,表示一个不接受任何参数的委托方法。

    至此,就能够把这个简写形式还原为完整的写法了:

    Action (delegate(){
    	//匿名委托中要做的事情
        //...
    });
    

现在大家都是产品经理了

记录生活中的奇思妙想

  1. 桌面备忘工具

  2. 桌宠+AI=女儿