日期:2014-05-16  浏览次数:21001 次

求助~~~~关于socket的问题,标题要长~~~~~~~~~~~~~~~
最近在考虑优化通讯服务端的事情。查过一些资料,资料里面都说使用异步的socket会导致系统缓冲区满,出现10055错误,所以除了accpet之外。。。。我不敢使用异步了,其实是否使用icop我不是很在意。
我现在需要的是有谁能给我提供一个思路,一个海量数据接收发送的socket服务端的优化。
我自己写的服务端,往往同时处理1000个客户端就会出现掉包的情况(我自己写的1000个线程同时发送接收10个字以内的字符串,服务器电脑就是我自己的笔记本。。。WIN7,I5-M系列CPU,6G内存,64bit系统),苦恼啊~~

我看到网上有一个商业版的Beetle组件,可以实现海量数据的接收发送,而且还稳定。仔细看了下他文章的描述,感觉这个组件的思路是这样的:
使用合并数据包的方式,将socket的发送操作尽量减少,每次传输的都是体积大的数据包。但是有个问题,OS的缓冲区只有64K大小,他无非就是send的次数少一点,数据一样多,他怎么保证不会10055呢?
组件要钱的··咱没钱,而且我们自己就是搞开发的,不花这个冤枉钱,因此我过来求助了,有什么好的想法也可以说上两句,三个臭皮匠顶个诸葛亮嘛··如果讨论有结果了,我就将大家提供的宝贵思路综合综合,写个服务端socket放到论坛上来,开源嘛。

在此,求助了····
------解决方案--------------------
 
引用:
...
其实我问的问题啊····是这样的,比如我的socket一般可以监听,但是当我的客户端发送一个740MB以下的byte[]的时候,我的监听socket就会拒绝监听,其他的客户端就会报错(服务器积极拒绝之类的)。为什么是740MB左右,因为.net自带的序列化,当序列化一个超过740MB左右的对象的时候,会直接异常,不知道为什么。我的服务端的recv是绝对的异步,不存在阻塞的问题,那么我奇怪的地方就在于为什么我接收一个大的对象的时候,我的socket连监听不正常了?难道我的socket的缓冲区满了?但是如果这样就满了,那么FTP是怎么做到的呢?他也是在传输大文件,但是没见过socket停止监听啊···

这个问题,我的猜测最有可能的情况就是序列化与反序列化过程,吃掉了你进程的所有内存,因为这个过程,与FTP的传输是不同的,FTP只是读取文件,将流放入缓冲区,socket从缓冲区读数据,发送 。也就是说,占用的笼统来说就是缓冲区大小的内存。序列化反序列化不同,它需要一个已存在或被构建的对象在内存中,那么,这个对象有多大,就要吃掉多大甚至*2的内存。
sbwwkmyd解释了32B与64B系统分配给进程的内存空间是有限的,也就是说,新的连接请求,因资源不足(因为也要为新建的连接分配缓冲区,如果你没有 预先分配的话),而遭到拒绝了。
------解决方案--------------------
可能你还是没有看明白我的意思,我建议你去掉服务器端的序列化/反序列化操作,而是将接收的数据,直接写入文件,然后,你再从客户端发送大数据,监测一下,就应该可以解释了。
------解决方案--------------------
引用:
fastcsharp的基于函数方式,我还真没看懂意思···一会去百度一下
因为我认为网络通讯的本质就是远程函数调用,所以fastCSharp就是直接基于函数定义的TCP调用。因为这些函数可能很早就存在的,把它变成可远程调用的不需要额外的代码。比如
    //这个Attribute定义服务配置
    [fastCSharp.setup.cSharp.tcpServer(Service = "tcpLongConnection", IsIdentityCommand = true, IsAsynchronous = true, Port = 12345)]
    public partial class tcpLongConnection
    {
        //这个Attribute标识此函数是可以远程调用的
        [fastCSharp.setup.cSharp.tcpServer(CommandIentity = 1)]
        private bool test(int A, string B, byte[] C, out int count)
        {
        }
    }
编译以后,fastCSharp会自动生成代理服务端与客户端代码。
//服务器端启动服务
new namespace.tcpServer.tcpLongConnection().Start();
//客户端调用
bool value = new namespace.tcpClient.tcpLongConnection().test(0, "ABC", new byte[]{0,1,2},out count);
如果是夸类服务(只支持静态函数),不需要new客户端,直接
tcpLongConnection.tcpClient.test(0, "ABC", new byte[]{0,1,2},out count);

------解决方案--------------------
还有溢出问题,如果是程序段溢出错误,那么我应该能捕捉到,就算没有捕捉到,我的服务端应该就此挂掉了,但是我人为的断开了这个客户端的大量数据发送方式之后,我的socket立马就好了······

你断开这个客户端,可能你的服务器端socket接收数据部分会异常,然后释放了接收队列。
不是我有意的为难你啊。。。。你说的情况,我之前考虑过,但是发现不是这个原因。
我的客户端发送都是依次发送的,因为我的客户端的发送是同步发送,我是用的一个循环,每次循环同步发送1KB的数据,就这样,服务端也是同步接收,但是服务端的同步接收不用担心阻塞,因为我是在beginreceive回调中做的同步接收,根本与accept没有任何关系。

accept也是要接收数据的,同样需要使用缓冲队列。但是你既然都确认是串行操作了,那我也没办法在继续猜测了,因为我没有碰到过你这种情况。而且拆成了小数据同步循环,应该与大数据也没有任何关系了。