C#中异步socket

1 篇文章 0 订阅

Socket是什么

参考:https://blog.csdn.net/jia12216/article/details/82702960

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
vv

Socket通信过程介绍

服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
在这里插入图片描述

单线程、多线程、同步、异步概念理解

单线程:一个任务从头至尾由一线程完成,在一个任务完成之前,不接受第二个任务。
多线程 ,:将一个任务拆分成不同的阶段(部分),并交给不同的 线程 分别处理。

什么是同步,什么是异步
异步:和同步相对,同步是顺序执行,而异步是彼此独立,在等待某个事件的过程中继续做自己的事,不要等待这一事件完成后再工作。线程是实现异步的一个方式,异步是让调用方法的主线程不需要同步等待另一个线程的完成,从而让主线程干其他事情。
我们把在完成了一次调用后通过状态通知回调来告知调用者的方式称为异步过程
在异步过程中当调用一个方法时,调用者并不能够立刻得到结果,只有当这个方法调用完毕后调用者才能获得调用结果。这样做的好处是什么呢?答案是高效。
以数据传输为例:不必等待该数据传输完成并返回socket通信结果,直接继续传输。一个 顾客一边等待配置、一边做些别的事情,就是多线程了。

异步和多线程:不是同等关系,异步是目的,多线程只是实现异步的一个手段,实现异步可以采用多线程技术或者交给其他进程来处理。
显而易见,异步 可以提供更高的效率,它可以利用 等待 的时间去完成一些事情。

异步Socket编程代码

代码参考https://gameinstitute.qq.com/community/detail/119099

服务端代码

using System;  
using System.Collections.Generic;  
using System.Text;  
using System.Net;  
using System.Net.Sockets;  
  
namespace AsyncServer  
{  
    public class AsyncTCPServer  
    {  
        public void Start()  
        {  
            //创建套接字  
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6065);  
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
            //绑定端口和IP  
            socket.Bind(ipe);  
            //设置监听  
            socket.Listen(10);  
            //连接客户端  
            AsyncAccept(socket);  
        }  
  
        /// <summary>  
        /// 连接到客户端  
        /// </summary>  
        /// <param name="socket"></param>  
        private void AsyncAccept(Socket socket)  
        {  
            socket.BeginAccept(asyncResult =>  
            {  
                //获取客户端套接字  
                Socket client = socket.EndAccept(asyncResult);  
                Console.WriteLine(string.Format("客户端{0}请求连接...", client.RemoteEndPoint));  
                AsyncSend(client, "服务器收到连接请求");  
                AsyncSend(client, string.Format("欢迎你{0}",client.RemoteEndPoint));  
                AsyncReveive(client);  
            }, null);  
        }  
  
        /// <summary>  
        /// 接收消息  
        /// </summary>  
        /// <param name="client"></param>  
        private void AsyncReveive(Socket socket)  
        {  
            byte[] data = new byte[1024];  
            try  
            {  
                //开始接收消息  
                socket.BeginReceive(data, 0, data.Length, SocketFlags.None,  
                asyncResult =>  
                {  
                    int length = socket.EndReceive(asyncResult);  
                    Console.WriteLine(string.Format("客户端发送消息:{0}", Encoding.UTF8.GetString(data)));  
                }, null);  
            }  
            catch (Exception ex)  
            {  
                Console.WriteLine(ex.Message);  
            }  
        }  
  
        /// <summary>  
        /// 发送消息  
        /// </summary>  
        /// <param name="client"></param>  
        /// <param name="p"></param>  
        private void AsyncSend(Socket client, string p)  
        {  
            if (client == null || p == string.Empty) return;  
            //数据转码  
            byte[] data = new byte[1024];  
            data = Encoding.UTF8.GetBytes(p);  
            try  
            {  
                //开始发送消息  
                client.BeginSend(data, 0, data.Length, SocketFlags.None, asyncResult =>  
                {  
                    //完成消息发送  
                    int length = client.EndSend(asyncResult);  
                    //输出消息  
                    Console.WriteLine(string.Format("服务器发出消息:{0}", p));  
                }, null);  
            }  
            catch (Exception e)  
            {  
                Console.WriteLine(e.Message);  
            }  
        }  
    }  
}  
其中使用的异步操作函数

参考 https://blog.csdn.net/freesundark/article/details/5565069
在这里插入图片描述

(1)以BeginAccept(AsynscCallBack,object)为例,开始一个异步操作接受一个连接尝试。

参数:一个委托。一个对象。对象包含此请求的状态信息。
其中回调方法必须使用EndAccept方法
应用程序调用BeginAccept方法后,系统会使用单独的线程执行指定的回调方法并在EndAccept上一直处于阻塞状态,直至监测到挂起的链接。EndAccept会返回新的socket对象供你来同远程主机数据交互。返回的socket即为Client

(2)BeginSend()表示开始将数据异步发送到连接的Socket,它最常用的声明如下所示。
 public IAsyncResult BeginSend(byte[] buffer,  int offset,int size,SocketFlags socketFlags,  AsyncCallback callback,object state);  

Buffer表示要发送的数据,offset表示buffer中发送数据的位置,size为发送字节数的大小,socketFlags指SocketFlags值的按位组合。

(3)Socket构造函数:
public socket(AddressFamily 寻址类型, SocketType 套接字类型, ProtocolType 协议类型)

但需要注意的是套接字类型与协议类型并不是可以随便组合。
从上表中可以看出,这些方法都是成对出现的。这些方法能避免网络通信中的阻塞现象。这些方法的使用机制是在Begin开头的方法中注册一个回调函数,当对应的事件发生时,调用该回调函数,且在回调函数中调用对应的End开头的方法。

客户端代码

using System;  
using System.Collections.Generic;  
using System.Text;  
using System.Net;  
using System.Net.Sockets;  
  
namespace AsyncClient  
{  
    public class AsyncTCPClient  
    {  
        /// <summary>  
        /// 连接到服务器  
        /// </summary>  
        public void AsynConnect()  
        {  
            //端口及IP  
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6065);  
            //创建套接字  
            Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  
            //开始连接到服务器  
            client.BeginConnect(ipe, asyncResult =>  
            {  
                client.EndConnect(asyncResult);  
                //向服务器发送消息  
                AsynSend(client,"你好我是客户端");  
                AsynSend(client, "第一条消息");  
                AsynSend(client, "第二条消息");  
                //接受消息  
                AsynRecive(client);  
            }, null);  
        }  
  
        /// <summary>  
        /// 发送消息  
        /// </summary>  
        /// <param name="socket"></param>  
        /// <param name="message"></param>  
        public void AsynSend(Socket socket, string message)  
        {  
            if (socket == null || message == string.Empty) return;  
            //编码  
            byte[] data = Encoding.UTF8.GetBytes(message);  
            try  
            {  
                socket.BeginSend(data, 0, data.Length, SocketFlags.None, asyncResult =>  
                {  
                    //完成发送消息  
                    int length = socket.EndSend(asyncResult);  
                    Console.WriteLine(string.Format("客户端发送消息:{0}", message));  
                }, null);  
            }  
            catch (Exception ex)  
            {  
                Console.WriteLine("异常信息:{0}", ex.Message);  
            }  
        }  
  
        /// <summary>  
        /// 接收消息  
        /// </summary>  
        /// <param name="socket"></param>  
        public void AsynRecive(Socket socket)  
        {  
            byte[] data = new byte[1024];  
            try  
            {  
                //开始接收数据  
                socket.BeginReceive(data, 0, data.Length, SocketFlags.None,  
                asyncResult =>  
                {  
                    int length = socket.EndReceive(asyncResult);  
                    Console.WriteLine(string.Format("收到服务器消息:{0}", Encoding.UTF8.GetString(data)));  
                    AsynRecive(socket);  
                }, null);  
            }  
            catch (Exception ex)  
            {  
                Console.WriteLine("异常信息:", ex.Message);  
            }  
        }  
    }  
}  

参考https://blog.csdn.net/qq_40544338/article/details/103599590

C#中=>是什么意思?

lambda表达式,表示一个匿名函数,=>前面的是参数,后面的是函数体。你可以把它当作一个函数。

  • 5
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值