C#的.net桌面开发笔记

网络

链接

1.网络链接:端口号是与是一种用于网络通信的标识符,用于标识计算机上的不同网络应用程序或服务。在TCP/IP协议中,端口号是一个16位的数字,范围从0到65535。其中0到1023之间的端口号被称为"知名端口",用于标识常见的网络服务,例如HTTP、FTP等。而大于1023的端口号被称为"动态端口",用于临时分配给客户端应用程序。

2.设备链接:串口号是一种用于串行通信的标识符,通常用于连接计算机与外部设备,例如打印机、传感器等。串口号一般由一个数字表示,例如COM1、COM2等,用于标识计算机上的串口接口。串口通信是一种逐位传输数据的方式,数据通过一根串行传输线依次发送和接收。

通信参数
  1. 波特率(Baud Rate)是指每秒钟传输的比特数,常见的波特率有9600、115200等。
  2. 数据位(Data Bits)指的是每个字节中实际传输的数据位数,常见的数据位有5、6、7、8。
  3. 停止位(Stop Bits)指的是用于标识一个数据传输结束的位数,常见的停止位有1和2。
  4. 校验位(Parity)用于检测数据传输中的错误,常见的校验位有无校验、奇校验和偶校验。
  5. 流控制(Flow Control)用于调节数据传输的速度,常见的流控制方式有硬件流控制和软件流控制。
读取

设备->软件:软件通常会从对应的缓冲区读取信息。及串口链接中serialPort.Read就是从串口缓存区中读取的信息。

软件->设备:设备读取软件发送的信息通常是从缓存区读取的。缓存区是一块内存区域,用于临时存储数据。当软件发送信息时,这些信息会被暂时存放在缓存区中,然后设备会从缓存区中读取这些信息进行处理或传输。

serialPort类

SerialPort类是在C#的System.IO.Ports命名空间中定义的一个类,用于在计算机和串行设备之间进行通信。它提供了一组方法和属性,可以方便地进行读取和写入串行数据。

成员:

  1. portName:表示串口的名称,例如"COM1","COM2"等。

  2. baudRate:表示串口的波特率,即数据传输的速度。

  3. dataBits:表示每个字节的数据位数,通常为8位。

  4. parity:表示奇偶校验方式,有None、Odd、Even等选项。

  5. stopBits:表示停止位的个数,通常为1或2。

  6. ReadTimeout(读取超时):设置读取数据的超时时间,当超过该时间仍未读取到数据时,将引发超时异常。

  7. ReadBufferSize(读取缓冲区大小):设置读取数据时的缓冲区大小,用于存储从串口读取的数据。

  8. WriteBufferSize(写入缓冲区大小):设置写入数据时的缓冲区大小,用于存储待发送到串口的数据。

  9. DtrEnable(DTR 使能):DTR (Data Terminal Ready) 是一个控制信号线,用于指示通信设备是否准备好接收或发送数据。该参数用于启用或禁用 DTR 信号线。

  10. RtsEnable(RTS 使能):RTS (Request To Send) 是一个控制信号线,用于请求发送数据。该参数用于启用或禁用 RTS 信号线。

方法:

  1. open():打开串口,建立与设备的连接。

  2. close():关闭串口,断开与设备的连接。

  3. isOpen():判断串口是否已经打开。

  4. read(size):从串口读取指定大小的数据。

  5. write(data):向串口写入数据。

  6. flush():清空串口的接收缓冲区。

  7. setPortName(port):设置串口的名称。

  8. setBaudRate(baudrate):设置串口的波特率。

  9. setDataBits(databits):设置每个字节的数据位数。

  10. setParity(parity):设置奇偶校验方式。

  11. setStopBits(stopbits):设置停止位的个数。

初始化:

new SerialPort(串口名称,波特率,无奇偶校验位,数据位,停止位)

线程

线程的创建

C#创建线程不仅可以通过函数来创建,还可以使用匿名方法、Lambda 表达式或者委托来创建线程。下面是几种常见的创建线程的方法:

1. 使用Thread类:通过创建Thread类的实例并将要执行的方法作为参数传递给Thread类的构造函数来创建线程。
   示例代码:

   ```csharp
   void MyMethod()
   {
       // 线程执行的代码
   }

   Thread thread = new Thread(MyMethod);
   thread.Start();
   ```

2. 使用匿名方法:直接在Thread类的构造函数中定义匿名方法作为线程的执行体。
   示例代码:

   ```csharp
   Thread thread = new Thread(delegate ()
   {
       // 线程执行的代码
   });
   thread.Start();
   ```

3. 使用Lambda 表达式:使用Lambda 表达式作为线程的执行体。
   示例代码:

   ```csharp
   Thread thread = new Thread(() =>
   {
       // 线程执行的代码
   });
   thread.Start();
   ```

4. 使用委托:创建委托,并将要执行的方法作为委托的参数传递给Thread类的构造函数。
   示例代码:

   ```csharp
   void MyMethod()
   {
       // 线程执行的代码
   }

   Action action = MyMethod;
   Thread thread = new Thread(new ThreadStart(action));
   thread.Start();
   ```
UI线程控件

UI线程控件指的是用户界面(UI)线程上的控件。在大部分图形用户界面(GUI)应用程序中,包括网页和移动应用程序,UI线程用于处理与用户界面相关的任务,例如处理用户输入、更新界面上的控件等。因此当前控件线程访问其他控件线程会造成访问异常,可以使用来进行忽略线程权限检查。

 Control.CheckForIllegalCrossThreadCalls = false; //忽略线程权限检查

数据库

ADO.NET框架数据库链接
 // 通过读取配置文件进行数据库连接
        public static string connstr = ConfigurationManager.ConnectionStrings["connstr"].ToString();

        /// 
        /// 执行增、删、改
        /// 
        /// 
        /// 
        private static int UpDate(string sqlstr)
        {
            MySqlConnection conn = new MySqlConnection(connstr);
            MySqlCommand comm = new MySqlCommand(sqlstr, conn);
            try
            {
                conn.Open();
                int result = comm.ExecuteNonQuery();
                return result;
            }
            catch (System.Exception ex)
            {
                // 写入系统日志
                throw ex;
            }
            finally
            {
                conn.Close();
            }
        }

        /// 
        /// 查询:获取单一结果
        /// 
        /// 
        /// 
        public static object GetSingleResult(string sqlstr)
        {
            MySqlConnection conn = new MySqlConnection(connstr);
            MySqlCommand comm = new MySqlCommand(sqlstr, conn);
            try
            {
                conn.Open();
                object result = comm.ExecuteScalar();
                return result;
            }
            catch (System.Exception ex)
            {
                // 写入系统日志
                throw ex;
            }
            conn.Close();
        }

        /// 
        /// 查询:获取结果集合
        /// 
        /// 
        /// 
        public static MySqlDataReader GetDataReader(string sqlstr)
        {
            MySqlConnection conn = new MySqlConnection(connstr);
            MySqlCommand comm = new MySqlCommand(sqlstr, conn);
            try
            {
                conn.Open();
                return comm.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (System.Exception ex)
            {
                // 写入系统日志
                conn.Clone();
                throw ex;
            }
            finally
            {
                conn.Close();
            }
        }

MySqlDataReader,MySqlConnection和MySqlCommand都是与MySQL数据库交互的类。它们属于ADO.NET框架中的类,用于在C#中连接、查询和读取MySQL数据库。

  • MySqlDataReader,数据阅读器,是用于从数据库中读取数据的类。通过执行查询语句并使用ExecuteReader方法,可以获取一个可用于逐行读取查询结果的数据流,从数据库中读取数据时,它会保持与数据库的连接,以便能够连续地从数据库中读取数据。一次性读取一行,可以通过reader.FieldCount指令来获取一行多少列。
  • MySqlConnection,Conn,是用于建立与MySQL数据库的连接的类。它提供了连接字符串和一些方法来打开、关闭和管理数据库连接。需要手动打开以及即使关闭。
  • MySqlCommand,Comm,是用于在MySQL数据库中执行SQL语句的类。可以通过实例化MySqlCommand对象,并将SQL语句和关联的连接传递给它,然后使用ExecuteNonQuery、ExecuteScalar或ExecuteReader等方法来执行SQL语句。ExecuteReader方法返回的是MySqlDataReader。

在类似于MySQL的关系型数据库中,还有其他一些常用类似的类,用于进行数据库交互。例如:

  • SqlDataAdapter: 用于填充 DataSet(数据集)和 DataTable(数据表),可以通过执行SQL语句或存储过程来检索和更新数据。
  • SqlCommandBuilder: 用于自动生成用于插入、更新和删除数据的 SQL 语句,它基于已给定的 SELECT 语句。
  • SqlDataReader: 用于从数据库中以只进流的方式读取数据,对于大量数据或只需逐行处理数据时比较有效。
  • SqlParameter: 用于向 SQL 语句传递参数,并保护代码免受 SQL 注入攻击。

 控件

在.NET桌面开发中,具有控件树,可以使用Control类的Find方法来根据变量存放的控件Name获取到对应的控件对象,然后通过该对象来设置控件的属性。

例如,假设您有一个变量存放了一个按钮的Name,您可以使用以下代码来设置该按钮的Text属性:

string controlName = "button1"; // 假设变量存放了按钮的Name
Button button = this.Controls.Find(controlName, true).FirstOrDefault() as Button; // 查找到对应的按钮对象
if (button != null)
{
    button.Text = "新的按钮文本"; // 设置按钮的Text属性
}

需要注意的是,Find方法是在当前窗体的控件集合中进行查找,如果需要在整个应用程序中查找,使用Application.OpenForms属性。

数据类型

C#中有多个数据结构可用,以下是其中一些常见的数据结构:

  1. 数组(Array):用于存储同类型的元素,并通过索引访问元素。
  2. 列表(List):使用动态数组实现的有序集合,可以动态添加或删除元素。
  3. 链表(LinkedList):由节点组成的有序集合,每个节点包含一个值和一个指向下一个节点的引用。
  4. 栈(Stack):后进先出(LIFO)的数据结构,只允许在栈顶进行插入和删除操作。
  5. 队列(Queue):先进先出(FIFO)的数据结构,只允许在队列尾部插入元素,在队列头部删除元素。
  6. 字典(Dictionary):键值对的集合,通过键来访问值,键是唯一的。
  7. 集合(Set):唯一元素的无序集合,不允许重复元素。
  8. 哈希表(Hashtable):基于键值对的集合,通过哈希函数将键映射到值。
  9. 树(Tree):由节点组成的层次结构,每个节点可以有多个子节点。
  10. 图(Graph):由节点和边组成的非线性结构,节点可以相互连接。
List

List是 有序集合,所以具有下表标识。

List是一个非常常用的数据结构,它是一个可变长度的数组容器。它提供了一些方便的方法来操作和管理元素,比如添加、删除、查找等。

List是一个泛型类,可以存储任意类型的元素。你可以创建一个List对象,并指定元素的类型,例如:

List numbers = new List(); // 创建一个存储整数的List
List names = new List(); // 创建一个存储字符串的List
List names = new List(); // 创建一个存储object的List 
  

要向List中添加元素,可以使用Add方法:

numbers.Add(10);
numbers.Add(20);
numbers.Add(30);

要访问List中的元素,可以使用索引。List中的元素从0开始编号,所以第一个元素的索引是0,第二个元素的索引是1,依此类推。也可以通过foreach来进行遍历:

int firstNumber = numbers[0]; // 获取第一个元素
int secondNumber = numbers[1]; // 获取第二个元素
foreach(int i in test)      //通过foreach遍历 
{
    Console.WriteLine(i);
}

可以使用Count属性获取List中元素的数量:

int count = numbers.Count;

要删除List中的元素,可以使用Remove方法:

numbers.Remove(20); // 删除值为20的元素
哈希表

Hashtable和Dictionary都是用于存储键值对的数据结构,同样是哈希表数据结构,但它们有一些区别。

主要区别如下:

  1. 实现方式:Hashtable是通过散列函数将键映射到索引来存储数据,而Dictionary则是使用泛型来实现的键值对集合。

  2. 键类型:Hashtable允许使用任意对象作为键,而Dictionary要求键类型必须是可哈希的(即要求实现了GetHashCode方法和Equals方法)。

  3. 线程安全性:Hashtable是线程安全的,因为它的所有操作都是同步的。而Dictionary不是线程安全的,如果涉及多个线程同时访问,需要使用额外的同步机制来保证线程安全。

  4. 性能:由于Hashtable的线程同步机制,在多线程环境下性能稍低于Dictionary。

 Hashtable例子

 
using System;
using System.Collections;

class Program
{
    static void Main()
    {
        // 创建一个空的 Hashtable
        Hashtable myHashtable = new Hashtable();

        // 添加键值对
        myHashtable["apple"] = 5;
        myHashtable["banana"] = 3;
        myHashtable["orange"] = 2;

        // 访问值
        Console.WriteLine(myHashtable["apple"]);  // 输出:5

        // 检查是否包含某个键
        if (myHashtable.Contains("banana"))
        {
            Console.WriteLine("My hashtable contains 'banana'.");
        }

        // 遍历所有的键值对
        foreach (DictionaryEntry entry in myHashtable)
        {
            Console.WriteLine("Key: " + entry.Key + ", Value: " + entry.Value);
        }
    }
}

Dictionary例子 

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        // 创建一个空的 Dictionary
        Dictionary myDictionary = new Dictionary();

        // 添加键值对
        myDictionary["apple"] = 5;
        myDictionary["banana"] = 3;
        myDictionary["orange"] = 2;

        // 访问值
        Console.WriteLine(myDictionary["apple"]);  // 输出:5

        // 检查是否包含某个键
        if (myDictionary.ContainsKey("banana"))
        {
            Console.WriteLine("My dictionary contains 'banana'.");
        }

        // 遍历所有的键值对
        foreach (KeyValuePair kvp in myDictionary)
        {
            Console.WriteLine("Key: " + kvp.Key + ", Value: " + kvp.Value);
        }
    }
}

DictionaryEntry类型是C#中的一个结构体,用于表示Dictionary中的键值对。它包含两个属性:Key和Value,分别表示字典或哈希表中的键和对应的值。

DictionaryEntry主要用于遍历字典和哈希表元素,通过迭代器可以逐个访问字典中的键值对。在遍历过程中,每个键值对都被封装成一个DictionaryEntry结构体,方便获取键和值。

 集合

set和list都是集合的数据结构,下面是Set和List的一些主要区别:

  1. 重复元素:List允许包含重复的元素,而Set不允许。

  2. 顺序:List是有序的,可以按照添加顺序或索引进行访问。Set是无序的,没有特定的顺序。

  3. 搜索效率:由于List是有序的,可以使用二分搜索算法进行快速搜索。Set使用哈希表实现,因此搜索效率更高。

  4. 内存占用:由于Set需要维护唯一性,因此可能会占用更多的内存空间。而List只需按顺序存储元素即可。

JSON

JSON优点是值可以是json类型,及就可以实现嵌套。

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

class Program
{
    static void Main(string[] args)
    {
        // 创建一个 JObject 对象
        JObject json = new JObject();

        // 添加第一层嵌套的属性
        json["name"] = "John";
        json["age"] = 30;

        // 创建一个第二层嵌套的 JObject 对象
        JObject address = new JObject();
        address["street"] = "123 Main St";
        address["city"] = "New York";
        address["state"] = "NY";

        // 将第二层嵌套的 JObject 对象添加到第一层嵌套的 JObject 对象中
        json["address"] = address;

        // 创建一个数组
        JArray hobbies = new JArray();
        hobbies.Add("reading");
        hobbies.Add("playing guitar");
        hobbies.Add("hiking");

        // 将数组添加到第一层嵌套的 JObject 对象中
        json["hobbies"] = hobbies;

        // 打印 JSON 数据
        Console.WriteLine(json.ToString());
    }
}

输出 

{
    “name”: “John”,
    “age”: 30,
    “address”: 
    {
        “street”: “123 Main St”,
        “city”: “New York”,
        “state”: “NY”
    },
    “hobbies”: 
    [
        “reading”,
        “playing guitar”,
        “hiking”
    ]
}
  • 数组(Array)用方括号(“[]”)表示。

  • 对象(0bject)用大括号(“{}”)表示。

  • 名称/值对(name/value)组合成数组和对象。

  • 名称(name)置于双引号中,值(value)有字符串、数值、布尔值、null、对象和数组。

  • 并列的数据之间用逗号(“,”)分隔

 json在c#中可以使用.或[]来进行表示,遍历json里面的数据可以通过将json数据提取成动态或静态类型来处理。

dynamic val = JsonConvert.DeserializeObject(JSON);
foreach(var i in val[val])
{
     MessageBox.Show(i[test]);
}
for(int i=0;i<((JArray)val["val"]).Count;i++)
{
     MessageBox.Show(val[val][i]);
}

 类型

动态类型和静态类型

        动态类型和静态类型是编程语言中常见的两种类型系统。它们的区别主要在于类型检查的时机和方式。 

        静态类型指的是在编译阶段进行类型检查的类型系统。在静态类型语言中,变量的类型在编译过程中确定,并且类型错误会在编译时被发现。编译器会检查变量的声明和使用是否符合语言定义的类型规则。这样可以提前发现潜在的类型错误,减少运行时错误的风险。

        动态类型指的是在运行时进行类型检查的类型系统。在动态类型语言中,变量的类型在运行时确定,并且类型错误会在运行时被发现。变量可以在运行时改变其类型,而不需要提前进行声明或定义。这样可以提供更大的灵活性和简化开发过程,但也增加了运行时错误的风险。

        总结来说,静态类型语言在编译阶段进行类型检查,提前发现潜在错误;而动态类型语言在运行时进行类型检查,提供更大的灵活性。

参数传递

按值传递(默认)和引用传递(ref)。基本类型都是大部分都是默认按值,只有引用类型默认是按地址传递。string因为一经创建就不能修改,虽然也是引用类型,但是默认是按值传递的,因为一经创建实际就是新的string了。

按值

void ChangeValue(int num)
{
    num = 10;
}

int value = 5;
ChangeValue(value);
Console.WriteLine(value); // 输出结果为5,原始实参的值不受方法内部的修改影响

 引用

void ChangeValue(ref int num)
{
    num = 10;
}

int value = 5;
ChangeValue(ref value);
Console.WriteLine(value); // 输出结果为10,原始实参的值受方法内部的修改影响

闭包

 int downlocation = 0;   //可放置控件位置坐标(当前最低控件底边坐标+控件间隔距离)
                using (var tempForm = new Form())
                {
                    int tibutton = 0;   //提交按钮是否显示
                    Hashtable conval = new Hashtable();
                    for (int i=0; i< ((JArray)val["val"]).Count;i++)//控件层
                    {
                        
                        if (val["val"][i]["type"] == "Button")
                        {
                            tibutton = 1; //提交按钮不显示
                            int controllerhight = 20;   //控件高度
                            int controllerinterval = 5;    //控件间隔
                            for (int coarray_position = 0; coarray_position < ((JArray)val["val"][i]["val"]["name"]).Count; coarray_position++)
                            {
                                string control_name = val["val"][i]["val"]["name"][coarray_position];
                                string control_value = val["val"][i]["val"]["val"][coarray_position];
                                Console.WriteLine(control_name);
                                Console.WriteLine(control_value);
                                var button = new Button();
   
                                button.Text = control_name;
                                button.Size = new System.Drawing.Size(tempForm.Width, controllerhight);
                                button.Location = new Point(0, downlocation);
                                downlocation = downlocation + controllerhight + controllerinterval;
                                button.Click += (s, ev) =>
                                {
                                    MessageBox.Show(control_value);

                                    this.Text = control_value;
                                };
                                tempForm.Controls.Add(button);

                            }
                        }
                        else if (val["val"][i]["type"] == "Radio")
                        {
                            
                            var groupbox = new GroupBox();  //容器
                            groupbox.Text = val["val"][i]["name"];
                            int controllerhight = 20;   //容器高度=控件最低位置+控件高度+预定值
                            int controllerinterval = 5;    //容器间隔
                            int radiointerval = 5;        //控件间隔
                            int radioheight = 20;      //控件高度

                            for (int coarray_position = 0; coarray_position < ((JArray)val["val"][i]["val"]["name"]).Count; coarray_position++)
                            {
                                string control_name = val["val"][i]["val"]["name"][coarray_position];
                                string control_value = val["val"][i]["val"]["val"][coarray_position];
                                Console.WriteLine(control_name);
                                Console.WriteLine(control_value);
                                var radiobox = new RadioButton();
                                
                                radiobox.Text = control_name;
                                radiobox.Size = new System.Drawing.Size(tempForm.Width, radioheight);
                                radiobox.Location = new Point(0, controllerhight);
                                controllerhight = controllerhight + radioheight + radiointerval;
                                radiobox.Click += (s, ev) =>
                                {
                                    MessageBox.Show(control_value);
                                    conval[groupbox.Text] = control_value;
                                };
                                groupbox.Controls.Add(radiobox);
                                

                            }
                            
                            groupbox.Size = new System.Drawing.Size(tempForm.Width, controllerhight);    //容器大小
                            groupbox.Location = new Point(0, downlocation);                           //容器位置
                            downlocation = downlocation + controllerinterval + controllerhight;     //重新设置最低位置
                            tempForm.Controls.Add(groupbox);
                        }

           
                    }
                    if(tibutton==0)
                    {
                        var button = new Button();      //提交按钮
                        button.Text = "提交";
                        button.Size = new System.Drawing.Size(tempForm.Width, 20);
                        button.Location = new Point(0, downlocation);
                        button.Click += (s, ev) =>
                        {
                            
                            foreach (DictionaryEntry entry in conval)
                            {
                                MessageBox.Show("Key: " + entry.Key + ", Value: " + entry.Value);
                            }

                        };
                        tempForm.Controls.Add(button);
                    }
                    tempForm.ShowDialog();

                }
            }

在这段代码中,conval[groupbox.Text] = control_value;代码因为闭包实现了显示对应的值的功能。并没有一直显示最后一个函数,因为每次当for循环一次后,for循环内部就形成了闭包,内部存储的数据都有单独的存放,之后的循环再次创建以及赋值也不会影响循环内创建或设置的变量。及函数内部创建的变量的值会被保留。

闭包是一种编程概念,它可以让一个函数捕获并保存其所在作用域的状态。换句话说,闭包可以让函数访问其外部作用域中的变量,即使在函数执行完毕后,这些变量也会被保存下来。

当一个嵌套函数(内部函数)引用了外部函数的变量时,就会创建一个闭包。内部函数可以访问外部函数的变量,这是由于内部函数保留了对外部作用域的引用。

闭包的工作原理如下:

  1. 当外部函数执行时,会创建一个新的执行上下文,并将该执行上下文添加到调用栈中。在这个执行上下文中,会创建一些局部变量。

  2. 如果内部函数引用了外部函数的变量,则会将这些变量添加到内部函数的作用域链中。

  3. 当外部函数执行完毕时,它的执行上下文会从调用栈中弹出,但闭包中引用的外部变量不会被销毁。

  4. 内部函数可以继续访问和操作闭包中的外部变量,因为它仍然保留了对外部作用域的引用。

闭包的特点:

  • 闭包可以访问和修改外部函数的变量。

  • 外部函数的执行上下文在内部函数执行完毕后不会被销毁,以便内部函数可以继续访问外部变量。

  • 闭包可以作为返回值,或者作为参数传递给其他函数。

TRY 

try
{
    // 可能会抛出异常的代码
}
catch (Exception ex)
{
    // 异常处理代码
}
finally
{
    // 最终执行代码
}
 
  1. try语句块:包含有可能会抛出异常的代码,如果在这段代码中发生了异常,那么程序就会跳转到catch语句块来进行异常处理。

  2. catch语句块:用于捕获异常和处理异常。在catch语句块中,我们可以使用Exception类的各种方法来查看捕获到的异常的具体信息,并根据情况进行处理。

  3. finally语句块:无论try语句块中的代码是否有异常,都会执行的代码块。通常在这个块中,我们会进行一些资源的回收或清理工作。

 string转int转换

Convert.ToInt32()和int.Parse()都可以将字符串转换为整数类型,但是它们有以下区别:

  1. Convert.ToInt32()可以将null转换为0,而int.Parse()会抛出异常。
  2. Convert.ToInt32()可以将一些非数字字符串转换为整数类型,例如"true"会被转换为1,"false"会被转换为0,而int.Parse()会抛出异常。

网络

 net

同步和异步

c#有两种发送和接收模式。

同步传输(阻塞传输)是数据发送或接收后,可以得知数据是否发送成功或者失败,在发送或接收完成之前会阻塞,系统挂起,等待完成。相当于执行到发送指令,系统就把在发送缓存区的数据开始发送。

异步传输(非阻塞传输)是不管数据是否发送成功,继续执行指令,系统不会阻塞。相当于执行到发送指令,系统会把数据存放在发送缓存区,由底部来进行发送,系统并不关心是否发送。

c#默认是同步传输,及传输数据之后就有返回值,可以知道数据是否发送成功。c#的异步传输采用回调函数实现,c#封装好一个异步类,我们把需要执行的函数注册进类即可。

  1. BeginAccept:开始一个异步的Accept操作,等待客户端连接。

  2. EndAccept:结束一个异步的Accept操作,并返回一个新的Socket对象,该对象表示连接的客户端。

  3. BeginConnect:开始一个异步的Connect操作,尝试连接到指定的服务器。

  4. EndConnect:结束一个异步的Connect操作。

  5. BeginReceive:开始一个异步的Receive操作,等待接收数据。

  6. EndReceive:结束一个异步的Receive操作,并返回接收到的数据字节数。

  7. BeginSend:开始一个异步的Send操作,发送数据。

  8. EndSend:结束一个异步的Send操作,并返回发送的数据字节数。

  9. BeginDisconnect:开始一个异步的Disconnect操作,关闭连接。

  10. EndDisconnect:结束一个异步的Disconnect操作。

1553B

C#的.net桌面开发笔记_第1张图片

1553B数据传输通过双绞线进行,每个节点都有一个独特的地址,并且可以作为总线上的发送器或接收器。数据传输分为两种类型:命令/响应(Command/Response)和广播(Broadcast)。命令/响应模式下,一个节点向另一个节点发送指令并等待响应;而广播模式下,则是所有节点都能够接收到同样的信息。

BC:总线控制器, bus controller:它是在总线上唯一被安排为执行建立和启动数据传输任务的终端。

RT:远程终端,remote terminal:它是用户子系统到数据总线上的接口,他在BC的控制下提取数据或接受数据。1553B总线上最多可以连接32个RT设备。每个RT设备都有唯一的地址码,范围从0到31。这些地址码用于识别和寻址特定的RT设备。

BM/MT:总线监视器,bus monitor terminal:它“监控”总线上的信息传输,以完成对总线上的数据源进行记录和分析,但他本身不参与总线的通信。

子地址:每个节点都有一个唯一的主地址和多个子地址。当一个节点发送消息时,它可以选择将消息发送到其主地址或任何一个子地址。如果消息被发送到了一个子地址,那么只有具有该子地址的节点才会接收到该消息。

复用方法:采用了时间分割多路复用(Time Division Multiplexing, TDM)技术。1553B总线中的每个设备都有自己的接收和发送缓冲区,当总线上出现空闲时间时,各个设备会根据优先级依次请求发送数据。总线控制器会根据请求的优先级选择一个设备进行数据传输,在该设备的时间片内,它可以向总线发送数据或者从总线接收数据。当该设备的时间片结束后,总线控制器会选择下一个设备进行数据传输。将一秒分割成好几份,一份即一帧,每个帧周期又被分割成好几份子帧,一个子帧发送数据。

EMGU.CV

简介

emgucv是opencv的封装,在c#中可以方便的进行调用,不用再创建动态链接库。

常用格式

  1. Image格式:源自 Bitmap 和 Metafile 的类提供功能的抽象基类。
    注: 可以利用PictureBox组件显示

  2. Mat格式:Mat是一个类,记录和存储图像数据,主要由两个数据部分组成: < 矩阵头(大小,通道,数据类型等) > 和 < 数据块(像素值) > 。

  3. Bitmap格式:封装 GDI+ 位图,此位图由图形图像及其属性的像素数据组成。 Bitmap 是用于处理由像素数据定义的图像的对象 。
    注: 可以利用PictureBox组件显示

  4. Image格式:这个类包含两个泛型参数:TColor和TDepth,定义一个Image对象时,需要指定色彩空间类型和数据深度。
    : 不可以利用PictureBox组件显示

  5. UMat格式Mat类型的父类UMat,Mat,只有当你知道自己在做什么时才应该使用。在大多数情况下,您应该使用Matrix类。
    注: 不可以利用PictureBox组件显示

  6. Matrix格式Matrix是OpenCV的cvMat的包装器。
    注: 不可以利用PictureBox组件显示

关于Emgu中图像数据格式说明(Mat,Image,BitMap)_emgucv mat转bitmap_啥都亿点点的研究生的博客-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/lichaoqi1/article/details/131216768

常用类

  1. Image类:表示图像数据。它包括多个子类,如Bgr、Gray、Hsv等,分别表示不同的图像颜色空间。

  2. Mat类:与Image类类似,也是表示图像数据。不同的是,Mat类是基于OpenCV的cv::Mat类实现的,而Image类则是Emgu CV自己定义的。Mat类的性能更高。

  3. Bitmap类:表示Windows GDI中的位图数据。

  4. VideoCapture类:表示视频捕获设备,可以用来从摄像机、视频文件、网路视频等获取视频数据。

  5. VideoWriter类:表示视频写入设备,可以用来将视频数据写入到文件、网络流等。

  6. CascadeClassifier类:表示基于Haar特征的目标检测器,可以用来检测人脸、车辆等物体

类型转换

bitmap------>Image

Image test = bitmap.ToImage();

bitmap------>mat

Mat bitmat = BitmapExtension.ToMat(bitimg); 

Image------>bitmap

Bitmap bitmap = image.ToBitmap();

Image------>mat

Mat mat = image.Mat;

mat------>bitmap

Bitmap bitmap = mat.ToBitmap();

mat------>Image

Image immat = mat.ToImage();

Bitmap:

Bitmap 是 .NET Framework 中的一个类,用于表示由像素组成的位图图像。它常用于 Windows 窗体应用程序中,用于表示界面上的图像。在 EmguCV 中,Bitmap 可以通过 Convert 方法转换为 Image 对象,然后再进行图像处理。

Image

Image 是 EmguCV 中用于表示彩色图像的类,其中 Bgr 表示像素的顺序为蓝、绿、红,byte 表示像素深度为 8 位。它是 EmguCV 中最基本的图像类型之一,可以进行大部分的图像处理操作。在 EmguCV 中,Image 可以通过 Convert 方法转换为 Bitmap 或 Mat 对象。

Mat:

Mat 是 EmguCV 中用于表示图像的矩阵类。它是 OpenCV 中的一个概念,用于表示一张图像的像素数据。在 EmguCV 中,Mat 可以通过 ToImage 方法转换为 Image 对象,或者通过 ToBitmap 方法转换为 Bitmap 对象。

Mat 对象具有更高的灵活性和可操作性,它可以通过各种方式创建和修改,还可以与各种文件格式交互。在进行图像处理时,Mat 对象通常是最常用的图像类型之一。

你可能感兴趣的:(笔记,服务器,c#,后端)