C# 异步Socket

摘要:
C#异步套接字(BeginXXXX)服务器代码前言:它主要用于接收IPC(客户端)发送的捕获图像,我相信您也会搜索其他资源。2.对于这种Socket通信,服务器和客户端需要就消息的格式达成一致,客户端需要在与服务器连接时检查身份信息。接收到数据后,如果服务器首先将其编译为字符串,然后将密码获取为字节[]。
C# 异步Socket (BeginXXXX)服务器代码

前言:

1、最近维护公司的一个旧项目,是Socket通讯的,主要用于接收IPC(客户端)发送上来的抓拍图像,期间要保持通讯,监测数据包并进行处理。但是看之前那人写的代码个人觉得并不是很适合自己,于是就重写了,不过项目暂时弃置了,为了以后能够方便使用,也方便更多像我一样还是渣渣程序员的人,记录一些心得。我还是坚信那句话,分享才能够进步得更快

2、其实在做之前我对这个东西了解也很少,毕竟以我的认识,在国内C#更多地是用来开发网站,于是也在网上看了很多前辈贴的代码,我尝试过直接复制粘贴,发现很多都用不了最后自己写了才发现原来是这么一回事。所以在这里也奉劝各位不要做伸手党,通过自己的理解才能够将别人的知识转变成为自己的资本

开始

1、Socket 通信分为同步和异步两种模式,客户端一般用同步,异步多用于服务端。至于两者的区别,很多前辈已经有博客阐述过了,我这里就贴其中一个链接帮助大家理解:http://www.cnblogs.com/BLoodMaster/archive/2010/07/02/1769774.html。万一这个链接失效,相信大家也会搜索到其他资源的

2、做这种Socket通信,我觉得关键点在于【数据处理】而不是建立链接,但往往很多不了解人会遇到各种困难,比如Socket链接关闭,丢包,粘包之类的。通用做法就是

  2.1:使用缓冲区,将接收到的字节数组全部储存起来,再去分析数据,获取有效部分。

  2.2:服务器跟客户端需要约定好报文的格式,一般来说至少要有【数据头标识】、【数据实体长度】、【数据尾标识】,这样才能更好地对数据进行处理,否则你很难界定到底哪一段数据才是你想要的。

  2.3:数据分析一定要少用字符串或者字符拆解,因为这样很有可能获取到的长度是错误的(里面有很多空字节,或者编码解码问题导致字符串长度不一致),所以一定要用字节数组来处理,通过约定好的编码解码格式,查找标识所在位置进行数据拆解。【比如:客户端跟服务器连接需要核对身份信息,因此对一字符串进行的特殊加密再编码发送,服务器接收到数据之后如果先编译成了字符串再获取密码转成byte[],长度跟之前记录的很可能就会不一样】。不过对于获取报文头信息这一类通过字符串来拆解更为方便

3、在建立连接时通常发生的问题就是没有循环接收客户端消息导致socket被释放,或者只接受到客户端了几条消息之后就停了,我也遇到过这个问题,所以建立连接的关键在于BeginAccept和BeginReceive两个方法的递归循环调用

4、接下来就是贴代码了,这里只有服务器的,客户端的我还没有做以后补全了会发上来,入口函数是公开的,主要方法全部在这里,至于辅助函数(比如获取IP地址,检查端口是否被占用、获取发送消息大家可以自己去找一下吧,毕竟这些已经有很多前辈开源了)

  4.1:由于本人只是一渣渣野生程序猿,如果大家有什么不同的看法请提出来,交流也是一种很好的进步方式

  4.2:如果大家觉得有用,还是希望能够推荐一下,让更多新人看到,让大家能够彼此学习,也不枉费我写博客的力气,谢谢

  4.3:我更希望有大神来告诉我不足的地方,因为我知道这些代码写得并不好~

复制代码
public void Create_Server_Socket()
        {
            Thread th_server = null;
            string result = string.Empty;
            try
            {
                socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ip = Pubilc.Helper.Computer.GetIPv4();
                IPEndPoint point = new IPEndPoint(ip, this._port);
                socketServer.Bind(point);
                socketServer.Listen(this._listen);
                th_server = new Thread(() =>
                {
                    if (this._isRunning)
                        socketServer.BeginAccept(AcceptCallBack, socketServer);
                    else
                        Close_Server_Socket();
                });
                th_server.IsBackground = true;
                th_server.Start();
            }
            catch (Exception ex)
            {
                if (th_server.IsAlive)
                    th_server.Abort();
                ShowLog(ex.Message);
            };
        }
        public void Close_Server_Socket()
        {
            if (socketServer != null)
            {
                socketServer.Close();
            }
        }

        void AcceptCallBack(IAsyncResult ar)
        {
            Socket socketServer = (Socket)ar.AsyncState;
            try
            {
                Socket socketAccept = socketServer.EndAccept(ar);
                DynamicBuffer state = new DynamicBuffer();
                state.workSocket = socketAccept;
                socketAccept.BeginReceive(state.Buffers, 0, state.Buffers.Length, SocketFlags.None, ReceiveCallBack, state);
            }
            catch(Exception ex)
            {
                LogHelper.WriteLog(typeof(SocketHelper_Server), ex);
                ShowLog("AcceptCallBack" + ex.Message);
            }
            finally
            {
                if (this._isRunning)
                    socketServer.BeginAccept(AcceptCallBack, socketServer);
            }

        }
        void ReceiveCallBack(IAsyncResult ar)
        {
            string sendMsg = string.Empty;
            DynamicBuffer state = (DynamicBuffer)ar.AsyncState;
            Socket socketAccept = state.workSocket;
            try
            {
                int len = socketAccept.EndReceive(ar);
                if (len > 0)
                {
                    state.WritBuffer();
                }
                else
                {
                    sendMsg=doMsg.CheckConnection(socketAccept.RemoteEndPoint.ToString());
                    if (!string.IsNullOrEmpty(sendMsg))
                    {
                        byte[] buffer = Encoding.Default.GetBytes(sendMsg);
                        state.sb.AddRange(buffer);
                    }
                    else
                    {
                        socketAccept.Shutdown(SocketShutdown.Both);
                        socketAccept.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.WriteLog(typeof(SocketHelper_Server), ex);
                ShowLog("ReceiveCallBack" + ex.Message);
            }
            finally
            {
                if (this._isRunning)
                {
                    try
                    {
                        Thread th_send = null;
                        th_send = new Thread(() =>
                        {
                            Send(ref state);
                            th_send.Abort();
                        });
                        th_send.IsBackground = true;
                        th_send.Start();
                        socketAccept.BeginReceive(state.Buffers, 0, state.Buffers.Length, SocketFlags.None, ReceiveCallBack, state);
                    }
                    catch (Exception ex)
                    {
                        showLog(ex.Message);
                        LogHelper.WriteLog(typeof(IpcServerDo), ex);
                    }
                }
            }
        }
        void Send(ref DynamicBuffer state)
        {
            byte[] buffer = null;
            string sendMsg = string.Empty;
            Socket socketAccept = state.workSocket;
            Dictionary<string, byte[]> data;
            state.GetAllData(out data);
            if (data.Count > 0)
            {
                sendMsg = doMsg.AcceptFromIpc(socketAccept.RemoteEndPoint.ToString(), ref data);
                if (!string.IsNullOrEmpty(sendMsg))
                {
                    buffer = Encoding.Default.GetBytes(sendMsg.ToCharArray());
                    socketAccept.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, SendCallBack, socketAccept);
                }
                Send(ref state);
            }
        }
        void SendCallBack(IAsyncResult ar)
        {
            Socket socketAccept = (Socket)ar.AsyncState;
            try
            {
                int sendBytes = socketAccept.EndSend(ar);
            }
            catch(Exception ex)
            {
                LogHelper.WriteLog(typeof(SocketHelper_Server), ex);
            }
        }
复制代码

4、下面是State对象类,其实这个就是相当于缓冲区,将东西放到这里来保存,包括socket对象,其实有用的就是上面的声明部分和构造函数,至于下面的写入方法和数据拆解,缓冲区清理的方法我都觉得有待提高,因为用这种方法我在接收一张500KB左右的图片竟然要10秒才有返回结果(整个逻辑流程完成并发送数据的时间),这是不可以接受的,所以下面的数据处理方法,大家见仁见智吧,根据自己的需求去找到自己适合的方法,这里只是提供思路

复制代码
/// <summary>
    /// 循环队列
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class DynamicBuffer
    {
        /// <summary>
        /// 缓冲区大小
        /// </summary>
        public int bufferSize { get; set; }
       /// <summary>
       /// 通讯对象
       /// </summary>
        public Socket workSocket { get; set; }
        /// <summary>
        /// 缓冲区
        /// </summary>
        public byte[] Buffers { get; set; }
        /// <summary>
        /// 储存区
        /// </summary>
        public List<byte> sb;
        public DynamicBuffer()
        {
            this.bufferSize = 1024 *64;
            this.sb = new List<byte>();
            this.Buffers = new byte[bufferSize];
        }
        /// <summary>
        /// 将缓冲区数据放入储存区
        /// </summary>
        public void WritBuffer()
        {
            int endPosition = 0;
            byte[] buffer;
            int len = 0;
            for (endPosition = this.Buffers.Length - 1; endPosition >= 0; endPosition--)
            {
                //由于发现数据中有很多

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Python集成开发环境(IDE:Integrated Development Environment): PyCharmhmmlearn使用简介下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

蓝牙协议体系结构

蓝牙协议体系结构   整个蓝牙协议体系结构可分为底层硬件模块、中间协议层和高端应用层三大部分。   链路管理层(LMP,Link Management Protocol)、基带层(BB)和射频(RF)构成蓝牙的底层模块。RF通过2.4GHz无需授权的ISM频段,实现数据位流的过滤和传输,它主要定义了蓝牙收发器应该满足的要求。BB层负责跳频和蓝牙数据及信息帧...

关于stm32 HardFault_Handler 异常的处理 死机

在系统开发的时候,出现了HardFault_Handler硬件异常,也就是死机,尤其是对于调用了os的一系统,程序量大,检测堆栈溢出,以及数组溢出等,找了半天发现什么都没有的情况下,估计想死的心都有了。如果有些程序开始的时候一切没有问题,但是运行几个小时候,会发现死机了,搞个几天下来估计蛋都碎了一地吧。。。一般来说运行操作系统  是以下几个问题 1.开始的...

tcpip详解笔记(15) TCP协议连接过程

TCP是一个面向连接的协议,在发送数据之前,双方必须通过三次握手协议建立连接,而在终止连接的时候执行4次握手协议。 连接建立和终止 先看一下telnet连接服务器80端口的抓包:   上图由wireshark抓取,并显示了TCP状态图(注意:由于网络阻塞,发生了丢包现象,4是对2的重发,而5是对4的响应(同3相同))。 根据上图可以看到建立一个TCP连接的...

tableau-空间分析(tableau入门day-5)

目录 1.场景一---背景地图添加和使用 2.场景二---双轴图流动地图的使用 场景一 使用场景:与分析相关联的背景地图插入,可与分析信息结合更紧密,方便用户理解,可以是公司内部人员分布,工厂平面图设备位置,及学校教学楼分布等信息,也可是人体图研究容易受伤部位等 知识点① 背景地图的添加 知识点② 页面的使用 知识点③ 高亮笔的用法 背景地图添加 地图...

vuex数据持久化存储

  想想好还是说下vuex数据的持久化存储吧。依稀还记得在做第一个vue项目时,由于刚刚使用vue,对vue的一些基本概念只是有一个简单的了解。当涉及到非父子组件之间通信时,选择了vuex。只是后来竟然发现,刷新页面,数据去哪了???一脸懵逼。其实vuex本质上只是一个公共变量,是存储在浏览器内存中的,刷新页面,浏览器内存重置,数据也会被清空。如果要做数据...

avalon最佳实践

最近从angular的QQ群与新浪微博拉了许多人来用我的avalon,成为第一批登上方舟,脱离DOM苦海的人。短短三个月内,5群的朋友也搞出几个切实实行的案例了。为应对粉丝们高益高涨的热情,遂放出此文章。 avalon的数据绑定需要经过扫描才能起作用,框架自身会在domReady时进行一次扫描,通过ms-include加载子模板时,也会对当前模板进行一次扫...