转载:http://www.cnblogs.com/tianzhiliang/archive/2011/03/02/1969187.html

前几天“X教授”发Email与我讨论Socket通信方面的问题,主要涉及4个方面内容,现将回信公布出来,希望园友们能积极参与讨论,提出更好的解决方案。

下面是“X教授”的来信:

===========================================================

您好,我看了您写的几篇博文,想请教你几个.net Socket通信方面的问题,这些问题以前一直困扰着我。 
1、按照你深入探析C# Socket的文中的说法。 
对于Socket的同步操作来说,Socket的RceiveBuffer和SendBuffer没有用处,因我发送时是从应用程序缓存(这里指字节数据)直接拷贝到基础系统发送缓冲区,接收时是从基础系统接收缓冲区拷贝到应用程序的缓存。 
Socket本身的接收缓存与发送缓存,是否只与异步Socket操作有关。在异步操作中又分为两种,一种是以BeginXXX系列操作,以BeginSend为例,对这种操作我的理解是,从线程池中取一个线程,把数据拷贝到Socket的自带的SendBuffer中,调用BenginSend的主线程然后立刻返回,该发送线程挂起,由操作系统把SendBuffer中的数据拷贝到基础系统缓冲区,发送完成后,挂起的线程激活,调用EndSend进行相应的操作,释放异步对象等资源。 
以上我的理解是否正确。 
2、除XXXAsync系列操作外, BeginXXX系统的Socket操作是否也是用的完成端口机制。 
3、.net与C/C++写的结构体通信。目前我熟悉的就两种: 
第一种是了MarShal类进行结构体的转换操作,但托管与非拖管之间交互时的封送开销,使得其效率不高。 
第二种是用流的方式去解析数据包。然后按包结构,一个字段一个字段的去读取。比如比流出读取一个浮点型,binr.ReadSingle();此种效率还可以。接收与解析好几M的数据没有问题。 
我想问一下,有没有效率更高的方法。 
4、服务器给客户端转发数据,当客户端接收包的地方堵塞(可能是socket.Receive),有没有什么好的方案,让服务器自动丢包。

===========================================================

下面是我的回信:

===========================================================

X教授,您好: 
非常抱歉,最近比较忙,耽误给您回复了。对于您提出的几个问题,我只能作浅层次的回答,更深的研究,我们以后慢慢探讨,共同学习。 
第一个问题: 
你的理解是正确的,对于同步发送,是直接拷贝发送数据到基础系统的发送缓冲区,与Socket本身的Buffer无关。对于异步发送,是将Socket自带的Buffer空间内的所有数据,拷贝到基础系统发送缓冲区,并立即返回。 
在实际开发中,个人觉得采用异步接受、同步发送。也许你会感到很惊讶,很明显,异步操作明显比同步操作效率高很多,为什么发送要采用同步呢?不知道你在开发过程中有没有遇到过“现在已经正在使用此 SocketAsyncEventArgs 实例进行异步套接字操作”错误,这个错误是由于SAEA对象在一个时刻中只能处于StartAccept、StartReceive、StartSend状态中的一种,试想,当Socket服务器处于高压力情形下,一条Socket连接在很短的时间内要发送大量数据,当Socket处于StartSend状态下尚未触发回调函数时,又一次调用此Socket的StartSend方法,便会抛出该异常。这也有改进方案:记录Socket的当前状态,并存储在Socket的UserToken对象下,当要执行StartSend时,判断状态。不过这样效率会很慢,远远低于同步发送的效率,当高并发时,还要用大量的锁机制来维护线程的同步,得不偿失。不知道你有没有更好的改进方案,如果有,请告知我,不胜感激。 
第二个问题: 
BeginXXX系统的Socket操作采用的是完成端口机制,在初始化SAEA对象时,会为SAEA对象设定回调函数。 
SocketAsyncEventArgs acceptEventArg = new SocketAsyncEventArgs(); 
acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed); 
第三个问题: 
建议使用流的方式解析数据包。 
在解析数据包的过程中,不知道您有没有遇到过粘包的现象,我觉得对粘包的处理是影响解析效率的关键,请参见博文:http://www.cnblogs.com/tianzhiliang/archive/2010/08/31/1813659.html。 
第四个问题: 
我觉得采用“心跳”是一个不错的解决方案。 
“心跳”分为两种,第一种是客户端发起的心跳,第二种是服务端发起的心跳。 
客户端发起的心跳:客户端每隔一段时间发送策略消息给Socket服务器,Socket服务器原路返回策略消息,如果客户端在设定时间段内没有收到Socket服务器的返回消息,经重试机制后,判定Socket服务器已Down,关闭连接。 
服务端发起的心跳:服务端实时记录每条Socket的IO操作时间,每隔一段时间获取所有Socket列表的快照,扫描每条Socket,如果该Socket的IO操作时间距当前时间已超出设定值,则判定客户端Down,关闭连接。

一封给“X教授”的回信(讨论Socket通信)的更多相关文章

  1. C#调用C/C++动态库 封送结构体,结构体数组

    因为实验室图像处理的算法都是在OpenCV下写的,还有就是导航的算法也是用C++写的,然后界面部分要求在C#下写,所以不管是Socket通信,还是调用OpenCV的DLL模块,都设计到了C#和C++数 ...

  2. “IT学子成长指导”专栏及文章目录 —贺利坚

    迂者专栏关键词 就 业 大一 大二 大三 大四 自学 职 场 专业+兴趣 研究生 硕士 规 划 考 研 大学生活 迷 茫 计算机+专业 基本功 学习方法 编程 基 础 实践 读书 前 途 成 长 社团 ...

  3. 强哥的分享--如何使用Spring Boot做一个邮件系统

    http://springboot.fun/ actuator是单机.集群环境下要使用Spring Boot Admin将各个单机的actuator集成越来 mvn clean package -Dm ...

  4. (转)我看PhD by 王珢

    我看PhD by 王垠 前段时间看了一下这些关于 PhD 的负面信息: 一个专门反对读 PhD 的 BLOG 叫“100 Reasons NOT to Go to Graduate School”(下 ...

  5. [转]为什么我要用 Node.js? 案例逐一介绍

    原文地址:http://blog.jobbole.com/53736/ 介绍 JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样, ...

  6. iOS:iOS开发非常全的三方库、插件等等

    iOS开发非常全的三方库.插件等等 github排名:https://github.com/trending, github搜索:https://github.com/search. 此文章转自git ...

  7. 【转】为什么我要用 Node.js? 案例逐一介绍

    原文转自:http://blog.jobbole.com/53736/ 介绍 JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样, ...

  8. Node.js(转) -- 临时来说还看不懂!

    转自:http://blog.jobbole.com/53736/ 本文由 伯乐在线 - Lellansin 翻译.未经许可,禁止转载!英文出处:toptal.欢迎加入翻译组. 介绍 JavaScri ...

  9. CTSC2017总结

    这个博客已经弃坑近一年了,自从去年国赛大力卡线进队后这近一年来我的情况从博客一年没更就可见一斑,OI水平原(zhi)地(xian)踏(fu)步(chong),炉石和双升的姿势水平倒是提高不少. 在经历 ...

随机推荐

  1. Learning WCF Chapter2 WCF Contracts and Serialization

    So far I’ve talked about the standards behind it all,but in fact WCF hides most of this from the dev ...

  2. linux kernel API and google android compile guide

    (1)linux kernel API website: http://docs.knobbits.org/local/linux-doc/html/regulator/index.html http ...

  3. 基础算法(二分,贪心):NOIP 2012 疫情控制

    题目大意 给出一棵n个节点的树,根是1,要在除根节点以外的点建立检查点,使得从每条根到叶子的路径上都至少存在一个检查点.检查点由军队来建立.初始军队的位置是给定的,移动军队走一条边需要花费这条边的权值 ...

  4. DATE_FORMAT()(转)

    mysql中DATE_FORMAT(date, format)函数可根据format字符串格式化日期或日期和时间值date,返回结果串. 也可用DATE_FORMAT( ) 来格式化DATE 或DAT ...

  5. Device Tree常用方法解析

    Device Tree常用方法解析 Device Tree在Linux内核驱动中的使用源于2011年3月17日Linus Torvalds在ARM Linux邮件列表中的一封邮件,他宣称“this w ...

  6. 一个简单的DELPHI程序注册码设计 .

    当你辛辛苦苦用DELPHI做好了一个你认为十分不错的程序,你是否想把它发布出去成为共享软件呢  做为一个共享软件,注册码肯定是少不了的,你可以通过判断程序是否注册来进行功能,时间或一些其它限制.现在就 ...

  7. C文件操作之写入字符串到指定文件并在屏幕显示

  8. MySQL数据库MyISAM和InnoDB存储引擎的比较(转)

    MySQL有多种存储引擎,MyISAM和InnoDB是其中常用的两种.这里介绍关于这两种引擎的一些基本概念(非深入介绍). MyISAM是MySQL的默认存储引擎,基于传统的ISAM类型,支持全文搜索 ...

  9. Git 版本控制工具(学习笔记)

    GIT(分布式) 一.Git 初始版本控制工具 1. 安装Git Ubuntu系统下,打开shell界面,输入: sudo apt-get install git-core  之后回车输入密码,即可完 ...

  10. Scanner类的.next()和.hashNext()方法

    使用Scanner类可以很方便地便获取用户的键盘输入,Scanner是一个基于正则表达式的文本扫描器,它可以从文件.输入流 .字符串中解析出基本类型值和字符串值.Scanner类提供了多个构造器,不同 ...