当前位置:编程学习 > C#/ASP.NET >>

C# Socket异步接收的问题

public static void readCallback(IAsyncResult ar) {
    StateObject state = (StateObject) ar.AsyncState;
    Socket handler = state.WorkSocket;

    // Read data from the client socket.
    int read = handler.EndReceive(ar);

    // Data was read from the client socket.
    if (read > 0) {
        state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,read));
        handler.BeginReceive(state.buffer,0,StateObject.BufferSize, 0,
            new AsyncCallback(readCallback), state);
    } else {
        if (state.sb.Length > 1) {
            // All the data has been read from the client;
            // display it on the console.
            string content = state.sb.ToString();
            Console.WriteLine("Read {0} bytes from socket.\n Data : {1}",
               content.Length, content);
        }
        handler.Close();
    }
}

上面是MSDN上的例子,
在异步接收的时候主要有以下几个问题:
1、客户端发送过来的消息(一个字符串)都没有特殊的开始以及结束标志。(即没有自定义的文件头和尾),
然而我需要将一条消息完整的接收之后才能进行解析,但是消息的长度有可能大于接收缓冲区的大小,因此可能需要读次接收,
什么时候知道这条消息接收完成了?
2、如果客户端发送数据的速度非常快,那么有可能上一条消息还没有完整的接收完成,下一条消息已经发送过来,
这样的话此次接收到的数据就是上一条消息的后半部分和这条消息的前半部分。当然如果消息够长、客户端发送速度够快,
那情况就会更加复杂。
综上所述,怎么完整的接收一条条完整地消息? --------------------编程问答-------------------- 没有回复啊。。。 --------------------编程问答-------------------- 1,实际中我们可能会用一个协议来把要发送的消息包装一下,我们解析时,只看协议是否能正确解析出来就是了
2,这种情况应该不会出现,至少我没遇到过。 --------------------编程问答-------------------- 每一次传从要加标记,例如num1,endnum1  num2,endnum2
然后判断这些标记,就可以知道那个没穿了 --------------------编程问答-------------------- 一般来说read = 0就接收完成了 --------------------编程问答-------------------- 如果只是传字符串,那说明你搞了半天只是在玩玩打打。真正的项目需要定义消息结构,哪里是一个消息的开头,哪里是结尾,哪里是中间填充的间隔。而消息的构成就更加复杂了,MSN和QQ就有完全不一样的消息结构。这个就是所谓应用层通信协议的东西了。Socket本身只是一个信息通道罢了,研发重要的就是定义通信协议。 --------------------编程问答-------------------- 如2楼所说,我们在做socket时,也是先把协议定义好,在一个完整的数据包中,有包头,包尾,校验码,包长度等等,如果一条信息是被分成了几个包发过来的,那还会在中间加上总包号和当前包序号.

缓冲区最大设过8K,效果还可以. --------------------编程问答-------------------- 这些是协议应该解决的问题。向协议的设计者问去。包头、长度、校验码总要吧 --------------------编程问答--------------------
引用 6 楼 nextsea 的回复:
如2楼所说,我们在做socket时,也是先把协议定义好,在一个完整的数据包中,有包头,包尾,校验码,包长度等等,如果一条信息是被分成了几个包发过来的,那还会在中间加上总包号和当前包序号. 

缓冲区最大设过8K,效果还可以.


正解! --------------------编程问答-------------------- 举个例子:要发一个100M的文件,简单的协议格式“报头-报文长度-控制码-内容-校验码-报尾”:
发送时:
先发控制码=1的报文,内容是:我要发的文件名称、总大小、分片大小(或者分成多少片)等等;
再发控制码=2的报文,内容是:切片序号、大小等等;
最后发控制码=3的报文,内容是:发送结束等等;

当然了,你还可以扩展,接受端报告服务器端我接受的结果怎样,是否需要重发还是补发某个切片呵呵。

用这种模式本人成功发送过几百M的大型文件。其实上G的也可以发,只是发送端没有足够的内存切片而已
--------------------编程问答--------------------
引用 5 楼 lextm 的回复:
如果只是传字符串,那说明你搞了半天只是在玩玩打打。真正的项目需要定义消息结构,哪里是一个消息的开头,哪里是结尾,哪里是中间填充的间隔。而消息的构成就更加复杂了,MSN和QQ就有完全不一样的消息结构。这个就是所谓应用层通信协议的东西了。Socket本身只是一个信息通道罢了,研发重要的就是定义通信协议。

正解 --------------------编程问答-------------------- 因为客户端已经存在了,现在只是开发服务器端。所以客户端发生什么数据我没有办法控制。 --------------------编程问答-------------------- 而且客户端有好几种,因此我根本就没有办法去定义什么通信协议之类的东西,
我这边只能被动的接收数据。 --------------------编程问答-------------------- 关注一下。学习一下。~ --------------------编程问答-------------------- 如果你用tcp协议就用TcpClient类
udp也有对应的类

发送:
第一步,计算你要发送的消息的长度,比如计算结果,这个消息100字节
第二步,把这个消息的长度用一个固定长度的消息发送出去,比如用一个4字节的int
第三步,发送消息

接收
第一步,先读取4个字节,转换成int,那么你就知道了接下来要读多少数据,比如说100字节
第二步,读取100字节,解析

BitConverter 转换消息长度

是不是说的太罗嗦了,晕。。。。。 --------------------编程问答-------------------- 现在客户端已经存在(而且有几种不同的客户端),客户端发送什么数据我无法控制。服务器只是负责接收每一条数据,然后对每条数据进行解析。客户端可能有5000个左右,保持常连接,每几秒钟都会有数据发送到服务器。有些数据需要服务器回复。 --------------------编程问答-------------------- tcp 协议的消息边界,有三种方法:
1、固定消息长度
2、分隔符
3、消息长度与消息同时发送

没别的办法 --------------------编程问答-------------------- 1、客户端是已经存在的,数据有长有短(长度不定)。
2、几种客户端数据格式不一样,因此分隔符也不能定。
3、和1一样,没有办法要求客户端数据带上消息长度。 --------------------编程问答-------------------- 尝试着解析消息,解析失败,就继续接收,解析成功就清空缓存,准备下次接收,再设置一个接收消息的超时时间,超过时间后就当接收失败


这样只是蒙着来的

tcp只有那3种方法确定消息边界
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,