Network communication basics

Socket

Insert image description here
Socket is an intermediate software abstraction layer that communicates between the application layer and the TCP/IP protocol suite. It is a set of interfaces. Socket is usually used to implement communication between client and server. It allows client applications to establish connections with server applications and transfer data over the network.

Socket contains 5 types of information necessary for network communication
Socket example
{ Protocol: TCP/UDP Local: IP, Port Remote: IP, Port }



The basic steps of Socket communication are as follows:

  1. The server creates a Socket and binds it to the specified IP address and port.
  2. The client creates a Socket and connects to the server's IP address and port.
  3. The server accepts the client's connection request and establishes the connection.
  4. Data can be sent and received between the client and the server through Socket.
  5. After the connection ends, both the client and the server can close the Socket.

Insert image description here

TCP

sync method

Follow the figure above to establish a connection between the client and the server and send messages. The synchronization method used here will block

namespace Client
{
    
    
    class Program_Sync
    {
    
    
        static void Main(string[] args)
        {
    
    
            //创建客户端Socket
            //AddressFamily.InterNetwork:表示使用IPv4地址族。AddressFamily.InterNetworkV6:IPv6地址族
            //SocketType.Stream:表示使用流式套接字。流式套接字提供了可靠、面向连接的通信服务,数据是按照顺序传输的
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //连接服务器
            //IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            //IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8888);
            //clientSocket.Connect(ipEndPoint);
            clientSocket.Connect("127.0.0.1", 8888);

            //发送数据
            string input = Console.ReadLine();
            byte[] sendData = Encoding.UTF8.GetBytes(input);
            clientSocket.Send(sendData);

            //接收数据
            byte[] rece = new byte[1024];
            clientSocket.Receive(rece);
            string receiveStr = Encoding.UTF8.GetString(rece);
            Console.WriteLine("收到服务端消息: " + receiveStr);

            clientSocket.Close();
        }
    }
}
namespace Server
{
    
    
    class Program_Sync
    {
    
    
        static void Main(string[] args)
        {
    
    
            //创建服务端Socket
            Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //绑定端口
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8888);
            serverSocket.Bind(ipEndPoint);

            //监听端口
            //参数0表示操作系统会根据系统的设置和硬件资源等情况来决定等待队列的长度,当等待队列已满时,新的连接请求将被拒绝
            serverSocket.Listen(0);
            Console.WriteLine("服务端启动成功");

            //循环等待客户端连接
            //阻塞当前线程,直到有客户端连接到服务器,然后返回一个新的Socket对象,该Socket对象可以用于和客户端进行通信
            Socket connectSocket = serverSocket.Accept();
            Console.WriteLine("客户端连接成功, IP和端口: " + (IPEndPoint)connectSocket.RemoteEndPoint);

            //接收数据
            byte[] rece = new byte[1024];
            connectSocket.Receive(rece);
            string receiveStr = Encoding.UTF8.GetString(rece);
            Console.WriteLine("收到客户端消息: " + receiveStr);

            //发送数据
            string input = Console.ReadLine();
            byte[] sendData = Encoding.UTF8.GetBytes(input);
            connectSocket.Send(sendData);

            serverSocket.Close();
        }
    }
}
asynchronous method

Various callback methods have been added, and the code is more complex. When we call Socket's asynchronous methods (such as BeginConnect, BeginSend, BeginReceive, etc.), the bottom layer will create one or more threads to perform asynchronous operations, which can easily cause thread problems.

namespace Client
{
    
    
    class Program_Async
    {
    
    
        private static byte[] _readBuffer = new byte[1024];

        static void Main(string[] args)
        {
    
    
            //创建客户端Socket
            //AddressFamily.InterNetwork:表示使用IPv4地址族。AddressFamily.InterNetworkV6:IPv6地址族
            //SocketType.Stream:表示使用流式套接字。流式套接字提供了可靠、面向连接的通信服务,数据是按照顺序传输的
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //异步连接服务器
            clientSocket.BeginConnect("127.0.0.1", 8888, ConnectCallback, clientSocket);

            Thread.Sleep(99999999);
        }

        /// <summary>
        /// 异步连接回调
        /// </summary>
        static void ConnectCallback(IAsyncResult ar)
        {
    
    
            try
            {
    
    
                Socket clientSocket = (Socket)ar.AsyncState;
                //EndConnect方法只是完成异步连接操作,并返回连接结果,它并不会中断连接
                clientSocket.EndConnect(ar);
                Console.WriteLine("连接服务端成功");

                Send(clientSocket, "client");

                //异步接收数据
                clientSocket.BeginReceive(_readBuffer, 0, _readBuffer.Length, SocketFlags.None, ReceiveCallback, clientSocket);
            }
            catch(Exception e)
            {
    
    
                Console.WriteLine("连接失败");
            }
        }

        /// <summary>
        /// 异步发送数据
        /// </summary>
        static void Send(Socket socket, string str)
        {
    
    
            byte[] sendData = Encoding.UTF8.GetBytes(str);
            socket.BeginSend(sendData, 0, sendData.Length, SocketFlags.None, SendCallback, socket);
        }

        /// <summary>
        /// 发送回调
        /// </summary>
        static void SendCallback(IAsyncResult ar)
        {
    
    
            try
            {
    
    
                Socket socket = (Socket)ar.AsyncState;
                //EndSend完成异步发送操作
                socket.EndSend(ar);
            }
            catch (Exception e)
            {
    
    
                Console.WriteLine("发送失败");
            }
        }

        /// <summary>
        /// 接收回调
        /// </summary>
        static void ReceiveCallback(IAsyncResult ar)
        {
    
    
            try
            {
    
    
                Socket socket = (Socket)ar.AsyncState;
                //EndReceive完成异步接收操作
                int receiveCount = socket.EndReceive(ar);
                if (receiveCount == 0)
                {
    
    
                    Console.WriteLine("服务端已断开");
                    socket.Close();
                }
                else
                {
    
    
                    string receiveStr = Encoding.UTF8.GetString(_readBuffer);
                    Console.WriteLine("收到客户端消息: " + receiveStr);

                    //继续接收
                    socket.BeginReceive(_readBuffer, 0, _readBuffer.Length, SocketFlags.None, ReceiveCallback, socket);
                }
            }
            catch (Exception e)
            {
    
    
                Console.WriteLine("接收失败");
            }
        }
    }
}
namespace Server
{
    
    
    public struct ClientData
    {
    
    
        public Socket socket;
        public byte[] readBuffer;
    }

    class Program_Async
    {
    
    
        private static Dictionary<Socket, ClientData> _clientDict = new Dictionary<Socket, ClientData>();

        static void Main(string[] args)
        {
    
    
            //创建服务端Socket
            Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //绑定端口
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8888);
            serverSocket.Bind(ipEndPoint);

            //监听端口
            //参数0表示操作系统会根据系统的设置和硬件资源等情况来决定等待队列的长度,当等待队列已满时,新的连接请求将被拒绝
            serverSocket.Listen(0);
            Console.WriteLine("服务端启动成功");

            //异步Accept
            serverSocket.BeginAccept(AcceptCallback, serverSocket);

            Thread.Sleep(99999999);
        }

        static void AcceptCallback(IAsyncResult ar)
        {
    
    
            try
            {
    
    
                Socket serverSocket = (Socket)ar.AsyncState;
                //EndSend完成异步发送操作
                Socket connectSocket = serverSocket.EndAccept(ar);
                Console.WriteLine("客户端连接成功, IP和端口: " + (IPEndPoint)connectSocket.RemoteEndPoint);
                ClientData data = new ClientData();
                data.socket = connectSocket;
                data.readBuffer = new byte[1024];
                _clientDict.Add(connectSocket, data);

                //接收其他客户端
                serverSocket.BeginAccept(AcceptCallback, serverSocket);

                //接收数据
                connectSocket.BeginReceive(data.readBuffer, 0, 1024, SocketFlags.None, ReceiveCallback, connectSocket);

                //发送数据
                Send(connectSocket, "111");
            }
            catch (Exception e)
            {
    
    
                Console.WriteLine("Accept失败");
            }
        }

        /// <summary>
        /// 异步发送数据
        /// </summary>
        static void Send(Socket socket, string str)
        {
    
    
            byte[] sendData = Encoding.UTF8.GetBytes(str);
            socket.BeginSend(sendData, 0, sendData.Length, SocketFlags.None, SendCallback, socket);
        }

        /// <summary>
        /// 发送回调
        /// </summary>
        static void SendCallback(IAsyncResult ar)
        {
    
    
            try
            {
    
    
                Socket socket = (Socket)ar.AsyncState;
                //EndSend完成异步发送操作
                socket.EndSend(ar);
            }
            catch (Exception e)
            {
    
    
                Console.WriteLine("发送失败");
            }
        }

        /// <summary>
        /// 接收回调
        /// </summary>
        static void ReceiveCallback(IAsyncResult ar)
        {
    
    
            try
            {
    
    
                Socket socket = (Socket)ar.AsyncState;
                //EndReceive完成异步接收操作
                int receiveCount = socket.EndReceive(ar);
                //客户端调用Socket.Shutdown后receiveCount为0
                if (receiveCount == 0)
                {
    
    
                    Console.WriteLine("客户端关闭, IP和端口: " + (IPEndPoint)socket.RemoteEndPoint);
                    _clientDict.Remove(socket);
                    socket.Close();
                }
                else
                {
    
    
                    byte[] buffer = _clientDict[socket].readBuffer;
                    string receiveStr = Encoding.UTF8.GetString(buffer);
                    Console.WriteLine("收到客户端消息: " + receiveStr);

                    //继续接收
                    socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, socket);
                }
            }
            catch (Exception e)
            {
    
    
                Console.WriteLine("接收失败");
            }
        }
    }
}
Poll method transforms synchronization method

When calling the Socket.Poll(int microSeconds, SelectMode mode) method, when the microSeconds parameter is 0, it means that it will not wait for any time and will return immediately. This method will immediately check the reading status of the Socket connection. If the data can be read, it will return true; if the data cannot be read, it will return false. So, in this sense, this method is non-blocking. Because it needs to be continuously tested, all performance consumption is large.

namespace Client
{
    
    
    class Program_Poll
    {
    
    
        static void Main(string[] args)
        {
    
    
            //创建客户端Socket
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //连接服务器
            clientSocket.Connect("127.0.0.1", 8888);

            while (true)
            {
    
    
                //Poll方法用于轮询Socket连接状态,检查Socket连接是否处于可读、可写或异常状态,第一个参数是轮询的超时时间
                if (clientSocket.Poll(0, SelectMode.SelectRead))
                {
    
    
                    Receive(clientSocket);
                }
                if (clientSocket.Poll(0, SelectMode.SelectWrite))
                {
    
    
                    Send(clientSocket, "client1");
                }
                //避免CPU占用率过高
                Thread.Sleep(10);
            }
        }

        static void Send(Socket socket, string str)
        {
    
    
            byte[] sendData = Encoding.UTF8.GetBytes(str);
            socket.Send(sendData);
        }

        static void Receive(Socket socket)
        {
    
    
            byte[] rece = new byte[1024];
            socket.Receive(rece);
            string receiveStr = Encoding.UTF8.GetString(rece);
            Console.WriteLine("收到服务端消息: " + receiveStr);
        }
    }
}
namespace Server
{
    
    
    class Program_Poll
    {
    
    
        public struct ClientData
        {
    
    
            public Socket socket;
            public byte[] readBuffer;
        }

        private static Dictionary<Socket, ClientData> _clientDict = new Dictionary<Socket, ClientData>();
        static void Main(string[] args)
        {
    
    
            //创建服务端Socket
            Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //绑定端口
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8888);
            serverSocket.Bind(ipEndPoint);

            //监听端口
            //参数0表示操作系统会根据系统的设置和硬件资源等情况来决定等待队列的长度,当等待队列已满时,新的连接请求将被拒绝
            serverSocket.Listen(0);
            Console.WriteLine("服务端启动成功");

            while (true)
            {
    
    
                if(serverSocket.Poll(0, SelectMode.SelectRead))
                {
    
    
                    Accept(serverSocket);
                }

                foreach(var data in _clientDict.Values)
                {
    
    
                    if(data.socket.Poll(0, SelectMode.SelectRead))
                    {
    
    
                        Receive(data.socket);
                    }
                    if (data.socket.Poll(0, SelectMode.SelectWrite))
                    {
    
    
                        Send(data.socket, "222");
                    }
                }

                Thread.Sleep(10);
            }
        }

        static Socket Accept(Socket socket)
        {
    
    
            Socket connectSocket = socket.Accept();
            Console.WriteLine("客户端连接成功, IP和端口: " + (IPEndPoint)connectSocket.RemoteEndPoint);

            ClientData data = new ClientData();
            data.socket = connectSocket;
            data.readBuffer = new byte[1024];
            _clientDict.Add(connectSocket, data);

            return connectSocket;
        }

        static void Send(Socket socket, string str)
        {
    
    
            byte[] sendData = Encoding.UTF8.GetBytes(str);
            socket.Send(sendData);
        }

        static void Receive(Socket socket)
        {
    
    
            byte[] buffer = _clientDict[socket].readBuffer;
            socket.Receive(buffer);
            string receiveStr = Encoding.UTF8.GetString(buffer);
            Console.WriteLine("收到客户端消息: " + receiveStr);
        }
    }
}
Select method

The Select method is used to select between multiple Socket objects to determine which Socket objects are ready for I/O operations. The first three parameters represent the list of Socket objects to be checked, and the last parameter represents the waiting timeout. . The Select method blocks program execution until one or more Socket objects are ready for I/O operations or times out.

namespace Client
{
    
    
    class Program_Select
    {
    
    
        private static List<Socket> _readCheckList = new List<Socket>();
        private static List<Socket> _writeCheckList = new List<Socket>();

        static void Main(string[] args)
        {
    
    
            //创建客户端Socket
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //连接服务器
            clientSocket.Connect("127.0.0.1", 8888);

            while (true)
            {
    
    
                _readCheckList.Clear();
                _writeCheckList.Clear();
                _readCheckList.Add(clientSocket);
                _writeCheckList.Add(clientSocket);
                Socket.Select(_readCheckList, _writeCheckList, null, 10);

                foreach(var item in _readCheckList)
                {
    
    
                    Receive(item);
                }

                foreach (var item in _writeCheckList)
                {
    
    
                    Send(item, "111");
                }
            }
        }

        static void Send(Socket socket, string str)
        {
    
    
            byte[] sendData = Encoding.UTF8.GetBytes(str);
            socket.Send(sendData);
        }

        static void Receive(Socket socket)
        {
    
    
            byte[] rece = new byte[1024];
            socket.Receive(rece);
            string receiveStr = Encoding.UTF8.GetString(rece);
            Console.WriteLine("收到服务端消息: " + receiveStr);
        }
    }
}
namespace Server
{
    
    
    class Program_Select
    {
    
    
        public struct ClientData
        {
    
    
            public Socket socket;
            public byte[] readBuffer;
        }

        private static Dictionary<Socket, ClientData> _clientDict = new Dictionary<Socket, ClientData>();
        private static List<Socket> _readCheckList = new List<Socket>();
        private static List<Socket> _writeCheckList = new List<Socket>();

        static void Main(string[] args)
        {
    
    
            //创建服务端Socket
            Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //绑定端口
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8888);
            serverSocket.Bind(ipEndPoint);

            //监听端口
            //参数0表示操作系统会根据系统的设置和硬件资源等情况来决定等待队列的长度,当等待队列已满时,新的连接请求将被拒绝
            serverSocket.Listen(0);
            Console.WriteLine("服务端启动成功");

            while (true)
            {
    
    
                _readCheckList.Clear();
                _writeCheckList.Clear();
                _readCheckList.Add(serverSocket);
                _writeCheckList.Add(serverSocket);
                foreach (var item in _clientDict.Keys)
                {
    
    
                    _readCheckList.Add(item);
                    _writeCheckList.Add(item);
                }

                Socket.Select(_readCheckList, _writeCheckList, null, 10);

                foreach (var item in _readCheckList)
                {
    
    
                    if(item == serverSocket)
                    {
    
    
                        Accept(item);
                    }
                    else
                    {
    
    
                        Receive(item);
                    }
                }

                foreach (var item in _writeCheckList)
                {
    
    
                    Send(item, "333");
                }
            }
        }

        static Socket Accept(Socket socket)
        {
    
    
            Socket connectSocket = socket.Accept();
            Console.WriteLine("客户端连接成功, IP和端口: " + (IPEndPoint)connectSocket.RemoteEndPoint);

            ClientData data = new ClientData();
            data.socket = connectSocket;
            data.readBuffer = new byte[1024];
            _clientDict.Add(connectSocket, data);

            return connectSocket;
        }

        static void Send(Socket socket, string str)
        {
    
    
            byte[] sendData = Encoding.UTF8.GetBytes(str);
            socket.Send(sendData);
        }

        static void Receive(Socket socket)
        {
    
    
            byte[] buffer = _clientDict[socket].readBuffer;
            socket.Receive(buffer);
            string receiveStr = Encoding.UTF8.GetString(buffer);
            Console.WriteLine("收到客户端消息: " + receiveStr);
        }
    }
}

UDP

sync method
namespace Client
{
    
    
    class Program_UDPSync
    {
    
    
        static void Main(string[] args)
        {
    
    
            //创建客户端Socket,不需要连接
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            Send(clientSocket, "123");
        }

        static void Send(Socket socket, string str)
        {
    
    
            byte[] sendData = Encoding.UTF8.GetBytes(str);
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8888);
            //发送到对应的ip和端口
            socket.SendTo(sendData, ipEndPoint);
        }
    }
}
namespace Server
{
    
    
    class Program_UDP_Sync
    {
    
    
        static void Main(string[] args)
        {
    
    
            //UDP使用数据包
            Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            //只需要绑定,不需要监听
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 8888);
            serverSocket.Bind(ipEndPoint);
            Console.WriteLine("服务端启动成功");

            Receive(serverSocket);
        }

        static void Receive(Socket socket)
        {
    
    
            byte[] rece = new byte[1024];
            socket.Receive(rece);
            //ReceiveFrom只接收给定ip地址的数据
            //socket.ReceiveFrom();
            string receiveStr = Encoding.UTF8.GetString(rece);
            Console.WriteLine("收到客户端消息: " + receiveStr);
        }
    }
}

Http

Http protocol is a simple protocol based on TCP. The following are commonly used GET and POST methods.

namespace Client
{
    
    
    class Program_Http
    {
    
    
        static void Main(string[] args)
        {
    
    
            //Get();
            Post();
        }

        private static void Get()
        {
    
    
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://www.metools.info");
            request.Method = "GET";
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream responseStream = response.GetResponseStream();
            string result = new StreamReader(responseStream).ReadToEnd();
            Console.WriteLine(result);
            responseStream.Close();
        }

        private static void Post()
        {
    
    
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://coolaf.com/tool/params?r=rtest&t2=rtest2");
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            using (StreamWriter write = new StreamWriter(request.GetRequestStream(), Encoding.GetEncoding("UTF-8")))
            {
    
    
                write.Write("s=stest&i=itest2");
            }
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream responseStream = response.GetResponseStream();
            string result = new StreamReader(responseStream).ReadToEnd();
            Console.WriteLine(result);
            responseStream.Close();
        }
    }
}

Multithreading

Basic usage of Thread

public class ParaTest
{
    
    
    public string str1;
    public string str2;
    public ParaTest(string s1, string s2)
    {
    
    
        str1 = s1;
        str2 = s2;
    }

    public void Task()
    {
    
    
        Console.WriteLine(str1 + str2);
    }
}

class Program_Thread
{
    
    
    public static int _sum;
    public static object _locker = new object();
    

    static void Main(string[] args)
    {
    
    
        //默认为前台线程,主线程结束后还会运行
        Thread thread1 = new Thread(Task1);
        Thread thread2 = new Thread(Task2);
        Thread thread3 = new Thread(() => 
        {
    
    
            //传递任意类型参数
            Task3("111", 222);
        });

        ParaTest para = new ParaTest("333", "444");
        //通过实例传递参数
        Thread thread4 = new Thread(para.Task);

        Console.WriteLine(thread1.ThreadState + " --1");

        thread1.Start();
        Console.WriteLine(thread1.ThreadState + " --2");

        //设置优先级
        //thread1.Priority = ThreadPriority.AboveNormal;

        //改为后台线程,随着主线程结束而结束
        //thread1.IsBackground = true;

        //阻塞线程,直到thread1执行完毕
        //thread1.Join();

        //传递参数
        thread2.Start("ttt");

        //停止线程
        //thread1.Abort();

        while (true)
        {
    
    
            Console.WriteLine(_sum);
            Thread.Sleep(1);
        }
    }

    private static void Task1()
    {
    
    
        for(int i = 0; i < 100; ++i)
        {
    
    
            Console.WriteLine("111");
            //加锁,避免同时修改变量
            lock (_locker)
            {
    
    
                _sum++;
            }
        }
    }

    private static void Task2(object obj)
    {
    
    
        for (int i = 0; i < 100; ++i)
        {
    
    
            Console.WriteLine("222" + obj.ToString());
            lock (_locker)
            {
    
    
                _sum--;
            }
        }
    }

    private static void Task3(string str, int i)
    {
    
    
    }
}

When using multi-threading, be careful to avoid deadlock problems (two threads hold the resources that each other needs)

Semaphore and mutex

Semaphore is a mechanism used to synchronize access to shared resources between threads or processes. It is a counter used to control access to shared resources.
There are two basic operations of semaphores: P (wait) and V (release)

  1. P (wait) operation: When a thread or process needs to access a shared resource, it performs a P operation. If the value of the semaphore is greater than 0, it means that the resource is available, and the thread or process can continue to execute; if the value of the semaphore is 0, it means that the resource has been occupied, and the thread or process will be blocked until the resource is available.
  2. V (release) operation: When a thread or process completes access to a shared resource, it will perform a V operation and increase the value of the semaphore by 1. This way, other threads or processes waiting for the resource can be awakened and continue execution.

A mutex (Mutex) can be regarded as a special form of Semaphore with a semaphore of 1. It can only be acquired by one thread. Other threads need to wait for the thread to release the lock before they can access the resource.

class Program_Semaphore
{
    
    
    //信号量,参数为初始值和最大值
    private static Semaphore _semaphore = new Semaphore(2, 2);
    //互斥量,类似于Semaphore(1, 1)
    private static Mutex _mutex = new Mutex();

    static void Main(string[] args)
    {
    
    
        Thread thread1 = new Thread(Task1);
        Thread thread2 = new Thread(Task2);
        Thread thread3 = new Thread(Task3);

        thread1.Start();
        thread2.Start();
        thread3.Start();
    }

    private static void Task1()
    {
    
    
        //等待
        _semaphore.WaitOne();
        Console.WriteLine("111");
        //释放
        _semaphore.Release();
    }

    private static void Task2()
    {
    
    
        _semaphore.WaitOne();
        _mutex.WaitOne();
        Console.WriteLine("222");
        _mutex.ReleaseMutex();
    }

    private static void Task3()
    {
    
    
        _semaphore.WaitOne();
        Console.WriteLine("333");
    }
}

Priority inversion: refers to an unreasonable phenomenon that may occur when using a semaphore, that is: a high-priority task is blocked by a low-priority task (the high-priority task is waiting for the semaphore, and the semaphore Owned by a low-priority task), causing high-priority tasks to be delayed in scheduling. But other medium-priority tasks can grab CPU resources. Judging from the phenomenon, it seems that medium-priority tasks have higher priority than high-priority tasks.

Thread Pool

Thread Pool (ThreadPool) provides a mechanism to manage and reuse multiple worker threads, which can manage thread resources more efficiently.

static void Main(string[] args)
{
    
    
    //将工作项添加到线程池中进行异步执行
    ThreadPool.QueueUserWorkItem(Task1);
    ThreadPool.QueueUserWorkItem((satte)=> 
    {
    
    
        Task2();
    });
    ThreadPool.QueueUserWorkItem(Task3);

    //线程池中当前可用的工作线程数量和IO线程数量
    ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads);
    Console.WriteLine("工作线程数:" + workerThreads + " IO线程数量:" + completionPortThreads);

    //获取线程池的最大工作线程数量和IO线程数量
    ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
    Console.WriteLine("最大工作线程数:" + maxWorkerThreads + " 最大IO线程数量:" + maxCompletionPortThreads);

    Thread.Sleep(100000);
}

private static void Task1(object state)
{
    
    
    Console.WriteLine("111");
}

private static void Task2()
{
    
    
    Console.WriteLine("222");
}

private static void Task3(object state)
{
    
    
    Console.WriteLine("333");
}

Network communication in Unity

UnityWebRequest encapsulates the network communication functions provided by C# and supports various common network protocols.

public class Test : MonoBehaviour
{
    
    
    private void Start()
    {
    
    
        //StartCoroutine(DownLoadText());
        //StartCoroutine(DownLoadText());
        //StartCoroutine(DownLoadAssetBundle());
        StartCoroutine(PostTest());
    }

    IEnumerator DownLoadText()
    {
    
    
        UnityWebRequest unityWebRequest = UnityWebRequest.Get("https://www.baidu.com");
        yield return unityWebRequest.SendWebRequest();

        if (unityWebRequest.result == UnityWebRequest.Result.Success)
        {
    
    
            //返回字符串数据
            Debug.Log(unityWebRequest.downloadHandler.text);
            //返回原始字节数组,适用于处理图像、音频、视频
            Debug.Log(unityWebRequest.downloadHandler.data);
        }
    }

    IEnumerator DownLoadTexture()
    {
    
    
        UnityWebRequest unityWebRequest = UnityWebRequestTexture.GetTexture("图片地址");
        yield return unityWebRequest.SendWebRequest();

        if (unityWebRequest.result == UnityWebRequest.Result.Success)
        {
    
    
            DownloadHandlerTexture downloadHandlerTexture = (DownloadHandlerTexture)unityWebRequest.downloadHandler;
            Debug.Log(downloadHandlerTexture.texture.width);
        }
    }

    IEnumerator DownLoadAssetBundle()
    {
    
    
        UnityWebRequest unityWebRequest = UnityWebRequestAssetBundle.GetAssetBundle("bundle地址");
        yield return unityWebRequest.SendWebRequest();

        if (unityWebRequest.result == UnityWebRequest.Result.Success)
        {
    
    
            AssetBundle assetBundle = ((DownloadHandlerAssetBundle)(unityWebRequest.downloadHandler)).assetBundle;
            //从bundle中加载资源
            GameObject go = assetBundle.LoadAsset<GameObject>("Cube");
            //实例化资源
            GameObject.Instantiate(go);
        }
    }

    IEnumerator PostTest()
    {
    
    
        //http不安全,默认不能使用,需要更改设置
        UnityWebRequest unityWebRequest = UnityWebRequest.PostWwwForm("http://coolaf.com/tool/params?r=rtest&t2=rtest2", "s=stest&i=itest2");
        yield return unityWebRequest.SendWebRequest();

        if (unityWebRequest.result == UnityWebRequest.Result.Success)
        {
    
    
            Debug.Log(unityWebRequest.downloadHandler.text);
        }
    }
}

Insert image description here
For security reasons, Unity does not allow downloading via http by default. You need to set it up to download.

Guess you like

Origin blog.csdn.net/sinat_34014668/article/details/133967945