线程和异步通信

实现的功能:

本功能是实现局域网下用户端呼叫服务器端,并在服务器端弹出提示框

(PS:我们用主机名实现通信)

需要学习和用到的类:

类名引用作用
Threadusing System.Threading线程,可以创建并控制线程,设置其优先级并获取其状态最为常用的类
Socketusing System,Net.Sockets异步通信,能够随时发送数据,并且能够随时接受服务器发送过来的数据,能够判断服务器端或端口网络的连接状态,随时查看与服务器通讯是否通畅
IPAddressusing System.Net提供了对IP地址的转换、处理等功能
IPEndPointusing System.Net应用程序连接到主机上的服务所需的主机和端口信息,通过组合服务的主机IP地址和端口号
Dnsusing System.Net提供了一系列静态的方法,用于获取提供本地或远程域名等功能

Thread类方法:

  • Thread.Start():启动线程的执行;
  • Thread.Suspend():挂起线程,或者如果线程已挂起,则不起作用;
  • Thread.Resume():继续已挂起的线程;
  • Thread.Interrupt():中止处于 Wait或者Sleep或者Join 线程状态的线程;
  • Thread.Join():阻塞调用线程,直到某个线程终止时为止;
  • Thread.Sleep():将当前线程阻塞指定的毫秒数;
  • Thread.Abort():以开始终止此线程的过程。如果线程已经在终止,则不能通过Thread.Start()来启动线程。

属性:

IsBackground

  1. 当在主线程中创建了一个线程,那么该线程的IsBackground默认是设置为FALSE的。
  2. 当主线程退出的时候,IsBackground=FALSE的线程还会继续执行下去,直到线程执行结束。
  3. 只有IsBackground=TRUE的线程才会随着主线程的退出而退出。
  4. 当初始化一个线程,把Thread.IsBackground=true的时候,指示该线程为后台线程。后台线程将会随着主线程的退出而退出。
  5. 原理:只要所有前台线程都终止后,CLR就会对每一个活在的后台线程调用Abort()来彻底终止应用程序。

实例化

Thread threadWatch = new Thread(WatchConnecting);
  • Thread是线程,一个线程一般会用来执行某个操作,而这个具体这个操作这是通过一个委托指向某个函数。
  • 在实例化Thread的实例,需要提供一个委托,在实例化这个委托时所用到的参数是线程将来启动时要运行的方法。在.net中提供了两种启动线程的方式,一种是不带参数的启动方式(ThreadStart),另一种是带参数的启动的方式(ParameterizedThreadStart)。

Socket类方法:

  • ------------------相关类--------------------------
  • •IPAddress类:包含了一个IP地址
  • •IPEndPoint类:包含了一对IP地址和端口号
  • --------------------方法们------------------------------
  • Socket (): 创建一个Socket
  • Bind(): 绑定一个本地的IP和端口号(IPEndPoint)
  • Listen(): 让Socket侦听传入的连接尝试,并指定侦听队列容量
  • Connect(): 初始化与另一个Socket的连接
  • Accept(): 接收连接并返回一个新的socket
  • Send(): 输出数据到Socket
  • Receive(): 从Socket中读取数据
  • Close(): 关闭Socket (销毁连接)
  • –如:

    –IPAddress addr = IPAddress.Parse("127.0.0.1");

    –IPEndPoint endp = new IPEndPoint(addr, 10001);

    服务端先绑定:serverWelcomeSocket.Bind(endp)

    客户端再连接:clientSocket.Connect(endp)

Socket通信基本流程图

IPAdress类方法

  • Parse ():将IP地址字符串转换为IPAdress实例
  • TryParse():确定字符串是否为有效的IP地址
  • MapToIPv4():将IPAddress对象映射到IPv4地址
  • IsLoopback():指示指定IP是否是回环地址
  • GetAddressBytes():以字节数组形式提供IPAddress的副本
  • Equals() :比较两个IP地址

IPEndPoint类 

 我们可以通过2种构造方法来创建IPEndPoint类:

  •  IPEndPoint(long address, int port)(ipv6)
  •  IPEndPoint(IPAddress address, int port)(ipv4)

Dns类

  • GetHostAddresses():获取指定主机的IP地址,返回一个IPAddress类型的数组。
  • GetHostName():获取本机主机名。

实现功能需要两个类,一个服务器端所需要的类(ReceiveOrder)一个是用户所需要的类(Sendorder)

ReceiveOrder类

public class ReceiveOrder
    {
        Thread threadWatch = null; //负责监听客户端的线程
        Socket socketWatch = null; //负责监听客户端的套接字
        Socket socConnection = null;//创建一个负责和客户端通信的套接字 

        public void Receive()
        {
            bool IsContain = false;
            //定义一个套接字用于监听客户端发来的信息  包含3个参数(IP4寻址协议,流式连接,TCP协议)
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //服务端发送信息 需要1个IP地址和端口号
            //获取文本框输入的IP地址
            //IPAddress ipaddress = IPAddress.Parse(txtIP.Text.Trim()); 
            //将主机名转化为IP地址
            IPAddress[] ips = Dns.GetHostAddresses("DESKTOP-RN1CDVF");
            string ic = Convert.ToString(ips[1]);
            IPAddress ipaddress = IPAddress.Parse(ic);
            //将IP地址和端口号绑定到网络节点endpoint上 
            IPEndPoint endpoint = new IPEndPoint(ipaddress, int.Parse("1")); //获取文本框上输入的端口号
            //监听绑定的网络节点                                                                 
            socketWatch.Bind(endpoint);
            //将套接字的监听队列长度限制为20
            socketWatch.Listen(20);
            //创建一个监听线程 
            threadWatch = new Thread(WatchConnecting);
            //将窗体线程设置为与后台同步
            threadWatch.IsBackground = true;
            //启动线程
            threadWatch.Start();
            //启动线程后 txtMsg文本框显示相应提示
        }
        /// <summary>
        /// 监听客户端发来的请求
        /// </summary>
        private void WatchConnecting()
        {
            while (true)  //持续不断监听客户端发来的请求
            {
                socConnection = socketWatch.Accept();               
                ParameterizedThreadStart pts = new ParameterizedThreadStart(ServerRecMsg);
                Thread thr = new Thread(pts);
                thr.IsBackground = true;
                //启动线程
                thr.Start(socConnection);
            }
        }
        /// <summary>
        /// 发送信息到客户端的方法
        /// </summary>
        /// <param name="sendMsg">发送的字符串信息</param>
        private void ServerSendMsg(string sendMsg)
        {
            //将输入的字符串转换成 机器可以识别的字节数组
            byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendMsg);
            //向客户端发送字节数组信息
            socConnection.Send(arrSendMsg);            
        }

        /// <summary>
        /// 接收客户端发来的信息 
        /// </summary>
        /// <param name="socketClientPara">客户端套接字对象</param>
        private void ServerRecMsg(object socketClientPara)
        {
            try
            {
                Socket socketServer = socketClientPara as Socket;
                while (true)
                {
                    //创建一个内存缓冲区 其大小为1024*1024字节  即1M
                    byte[] arrServerRecMsg = new byte[1024 * 1024];
                    //将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
                    int length = socketServer.Receive(arrServerRecMsg);
                    //将机器接受到的字节数组转换为人可以读懂的字符串
                    string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);

                    MessageBox.Show(strSRecMsg);                    
                }
            }
            catch (Exception)
            {


            }

        }
        private DateTime GetCurrentTime()
        {
            DateTime currentTime = new DateTime();
            currentTime = DateTime.Now;
            return currentTime;
        }

    }

Sendorder类

public  class Sendorder
    {
        //创建 1个客户端套接字 和1个负责监听服务端请求的线程  
        Socket socketClient = null;
        Thread threadClient = null;
        public void Send()
        {
            bool IsContain = false;          

            //定义一个套字节监听  包含3个参数(IP4寻址协议,流式连接,TCP协议)
            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //需要获取文本框中的IP地址                
            IPAddress[] ips = Dns.GetHostAddresses("DESKTOP-RN1CDVF");
            string ic = Convert.ToString(ips[1]);
            IPAddress ipaddress = IPAddress.Parse(ic);
            //将获取的ip地址和端口号绑定到网络节点endpoint上
            IPEndPoint endpoint = new IPEndPoint(ipaddress, int.Parse("1"));
            //这里客户端套接字连接到网络节点(服务端)用的方法是Connect 而不是Bind
            socketClient.Connect(endpoint);
            //创建一个线程 用于监听服务端发来的消息
            threadClient = new Thread(RecMsg);
            //将窗体线程设置为与后台同步
            threadClient.IsBackground = true;
            //启动线程
            threadClient.Start();
            ClientSendMsg("你有订单");
        }
        /// <summary>
        /// 接收服务端发来信息的方法
        /// </summary>
        private void RecMsg()
        {
            try
            {
                while (true) //持续监听服务端发来的消息
                {
                    //定义一个1M的内存缓冲区 用于临时性存储接收到的信息
                    byte[] arrRecMsg = new byte[
                        1024 * 1024];
                    //将客户端套接字接收到的数据存入内存缓冲区, 并获取其长度
                    int length = socketClient.Receive(arrRecMsg);
                    //将套接字获取到的字节数组转换为人可以看懂的字符串
                    string strRecMsg = Encoding.UTF8.GetString(arrRecMsg, 0, length);
                    
                }
            }
            catch (Exception)
            {

                
            }
            
        }
        /// <summary>
        /// 发送字符串信息到服务端的方法
        /// </summary>
        /// <param name="sendMsg">发送的字符串信息</param>
        private void ClientSendMsg(string sendMsg)
        {
            //将输入的内容字符串转换为机器可以识别的字节数组
            byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(sendMsg);
            //调用客户端套接字发送字节数组
            socketClient.Send(arrClientSendMsg);
            
        }
        /// <summary>
        /// 获取当前系统时间的方法
        /// </summary>
        /// <returns>当前时间</returns>
        private DateTime GetCurrentTime()
        {
            DateTime currentTime = new DateTime();
            currentTime = DateTime.Now;
            return currentTime;
        }

    }

参考博客:https://www.cnblogs.com/vaevvaev/p/6861708.html

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值