转载: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. git图示所有分支的历史

    1.第一种方法 git gui 菜单栏上 repository-->visual all branch history 或者直接使用命令gitk --all 2.在git bash中,使用命令查 ...

  2. USACO3.35A Game(记忆化)

    刚开始理解有点误,想成每步都是最优的 ,结果卡在第六组数据上,, 无奈瞧了下别人的 发现自己理解错了,,我看的还是中文翻译.. 简单的记忆化 /* ID: shangca2 LANG: C++ TAS ...

  3. Muduo-Base-TimeStamp类

    Muduo的时间戳类. 主要功能: 能够获取当前的时间 能够将当前的时间以string的形式返回 能够获取两个时间戳类的时间差 能够获取当前精确的时间(微秒级) #ifndef TIMESTAMP_H ...

  4. 理解wait notify的好例子

    import java.util.concurrent.TimeUnit; public class Example2 { /** * @param args */ public static voi ...

  5. Educational Codeforces Round 3

    A. USB Flash Drives 水题,排序即可 ]; int main() { int n,m; scanf("%d%d",&n,&m); ;i<n; ...

  6. mysql常用的一些命令,用于查看数据库、表、字段编码

    1.查看数据库支持的所有字符集         show character set;或show char set; 2.查看当前状态 里面包括当然的字符集设置         status或者\s ...

  7. div border-radius画圆

    不要指定border-width属性: <html> <style type="text/css"> div{ border-style: solid; b ...

  8. 关于升级linux下apache

    1:Check whether Apache is already installed. # rpm -qa | grep -i http httpd-tools-2.2.8-3.i386 httpd ...

  9. 基于OpenCV的人脸识别[iOS开发笔记(2)]

    开始了OpenCV的试水工作了... 1.Get ready 在OpenCV中我们会使用函数cv::CascadeClassifier 来进行人脸检测.但是在使用本函数之前我们需要添加一个XML文件对 ...

  10. C#中npoi操作Excel[版本2.0.1读写2003、2007格式]

    下载npoi2.0.1dll文件:http://download.csdn.net/detail/pukuimin1226/5851747 public static void test1()     ...