如题:Tcp无保护消息边界...这个大家都知道,如果用Tcp协议连续发送多次数据,就会出现一次接收的问题...现在求一个最佳"接收"解决方案.......客户端连发3个数据包:
socket.Send("111");
socket.Send("222");
socket.Send("333数据乱发长度不等");有什么有效的方法让服务器端3次接收.....---------异步开发 能不能达到这个效果....如果能搞一个好例子看下高手们把你们的知道的链接...代码...新颖的思路,想法...贴出来 欣赏一下  不胜感激......

解决方案 »

  1.   

    不管你是采用SOCKET异步还是同步方式
    当你socket.Send频率过高,并且每次发送数据长度小于8K(SOCKET缓存),就很有可能会出现粘包,也就是说你发送端发送
    socket.Send("111"); 
    socket.Send("222"); 
    socket.Send("333数据乱发长度不等");最后有可能在接收端接收到的是一个被连接在一起的字符串“111222333数据乱发长度不等”好像没有一个比较完美的办法可以解决,请参考: http://blog.csdn.net/binghuazh/archive/2009/05/28/4222516.aspx
      

  2.   

    占位看看!
    一直接触Scoket代码比较少!
      

  3.   

    那是底层做的事儿,不用管他,你上层定义好协议的头和尾,接收到头之后,如果没有收到尾就继续收,直到收到尾为止,比如用:SOAP协议,SIP协议等等
      

  4.   

    如果真的追求效率的那,那么建议用windows或Linux的socket,那个速度可以做到很快很快很快(我一个客户端一秒发一千条数据,服务端可以连接1000个客户端并对其数据进行处理),足以满足你的要求,
      

  5.   

    这个叫做长连接,长连接需要你自己制定很多协议,例如任何一方超时怎么办等等。其实如果不是什么电信主干通讯,完全使用短连接。短连接就是客户端向服务器发送一个请求,然后收到回复,就断开Stream。同样,服务端收到一个请求,处理了消息,就立刻断开Stream。这样做不论客户端还是服务端都能在重新建立连接时自我修复不少通讯中的故障现象。实际上在你的例子中,客户端可以并行地发起三个请求,服务端可以并行地处理三个请求。这样岂不更好?!
      

  6.   

    使用socket进行长连接编程,我发现90%以上把长连接的控制方法都想象的太简单了。
      

  7.   

    前几天刚写了个长连接,即客户端发起连接后,不间断的发送数据包,发几次服务器端接收几次,我是用的TcpListener 时刻监听,当有连接时,开辟一个新的线程专门用来处理这个链接过程中的传输,TcpListener 本身封装在一个线程里面。
      

  8.   

    建议楼主去网上查查TCP传输的通常方式
     
    我给你提供一个最简单也最好理解的解决方案吧。
    首先客户端是知道我当次会话传输数据的长度吧,其实这就是个相互规定的协议而已,你们做传输客户端和服务端应该先定好协议
    例如:
    socket.Send("111");  // 第一次(假设是第一个包)
    socket.Send("222");  //第二次(假设是第二个包)
    socket.Send("333数据乱发长度不等"); //第三次(假设是第三个包)
    一般应该是这样做,发送每个包的时候在包头都要带上这个包的长度,其实就是你send(byte[])的时候,在byte[]前几个字节放入当前包的长度,
    例如:当前发送的数据为"111"那么你先要取到“111” 的长度,然后放到待发送的byte[]的前2个字节里(不一定是前两个,这个要客户端和服务端相一致,到时候服务端只取前2个字节即可知道包的长度了),然后再把“111”序列化成byte[] 放到待发送的byte[]里去。然后发送即可,这样服务端得到数据之后首先要解析这个包的长度,然后再根据这个长度去取相同长度的数据. 我说到这够明白了么?
    在给你解释一下吧
    假设socket.Send("111");  
    socket.Send("222"); 
    socket.Send("asdfsafd乱七八糟不定长");
    这时候出现服务端一次性接收的情况按照我之前说的结构来做的话
    那你服务端接受到的数据就是这样的
    111的长度+111的byte[]数组+222的长度+222的byte[]数组+asdfsafd乱七八糟不定长的长度+asdfsafd乱七八糟不定长的byte[]数组
    当然 111的长度   222的长度  这些都是在客户端 .Length 求出来的,然后序列化即可
    在服务端只需取到第一个包的长度,按照长度取相应长度的数据,这个样能取到111,以此类推,这样每个包都可以分开了,只要你逻辑写的对,这样分包绝对没有问题
      

  9.   

    这个要在你在服务器端自己判断的,Socket只负责有数据到来的时候通知你有数据来了。
      

  10.   

    namespace sys.io
    {
    using System;
    using System.Collections.Generic;
    using System.Text; #region BufferedStream
    /// <summary>
    /// 缓存流
    /// </summary>
    public class BufferedStream : System.IO.Stream
    {
    System.IO.Stream stream;
    /// <summary>
    /// 构建一个内存缓冲流
    /// </summary>
    public BufferedStream() : base() { stream = new System.IO.MemoryStream(); }
    /// <summary>
    /// 从基础流构建流
    /// </summary>
    /// <param name="stream">源流</param>
    public BufferedStream(System.IO.Stream stream) { this.stream = stream; }
    /// <summary>
    /// 从字节数组构建缓冲流
    /// </summary>
    /// <param name="bytes">字节数组</param>
    public BufferedStream(byte[] bytes) { stream = new System.IO.MemoryStream(bytes); } /// <summary>
    /// 将整个流内容写入字节数组,而与 System.IO.MemoryStream.Position 属性无关。
    /// </summary>
    /// <exception cref="System.InvalidOperationException">如果源流不是一个内存流,将引发此异常</exception>
    /// <returns></returns>
    public byte[] ToArray()
    {
    System.IO.MemoryStream ms = stream as System.IO.MemoryStream;
    if (ms == null)
    throw new InvalidOperationException();
    return ms.ToArray();
    }
    public void Write(long value)
    {
    this.Write(BitConverter.GetBytes(value));
    }
    public void Write(ulong value)
    {
    this.Write(BitConverter.GetBytes(value));
    }
    public void Write(ushort value)
    {
    this.Write(BitConverter.GetBytes(value));
    }
    public void Write(int value)
    {
    this.Write(BitConverter.GetBytes(value));
    }
    public void Write(DateTime value)
    {
    this.Write(BitConverter.GetBytes(value.Ticks));
    }
    public void Write(uint value)
    {
    this.Write(BitConverter.GetBytes(value));
    }
    public void Write(byte[] bytes)
    {
    this.Write(bytes, 0, bytes.Length);
    }
    public void Write(string value)
    {
    byte[] buff = Encoding.UTF8.GetBytes(value);
    this.Write(BitConverter.GetBytes((ushort)buff.Length));
    this.Write(buff);
    }
    public void WriteObject(object obj)
    {
    byte[] bytes = null;
    using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
    {
    using (System.IO.Compression.GZipStream gz = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress))
    {
    System.Runtime.Serialization.IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
    formatter.Serialize(gz, obj);
    bytes = ms.GetBuffer();
    }
    }
    this.Write(bytes.Length);
    this.Write(bytes);
    }
    public void WriteUserId(string userId)
    {
    byte[] buff = Encoding.UTF8.GetBytes(userId);
    this.WriteByte((byte)buff.Length);
    this.Write(buff);
    } public object ReadObject()
    {
    int len = this.ReadInt();
    byte[] bytes = this.Read(len);
    using (System.IO.MemoryStream ms = new System.IO.MemoryStream(bytes))
    {
    using (System.IO.Compression.GZipStream gz = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress))
    {
    System.Runtime.Serialization.IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
    return formatter.Deserialize(gz);
    }
    }
    }
    public uint ReadUInt()
    {
    return BitConverter.ToUInt32(Read(4), 0);
    }
    public int ReadInt()
    {
    return BitConverter.ToInt32(Read(4), 0);
    }
    public ushort ReadUShort()
    {
    byte[] bytes = Read(2);
    return BitConverter.ToUInt16(bytes, 0);
    }
    public DateTime ReadDateTime()
    {
    byte[] bytes = Read(8);
    return new DateTime(BitConverter.ToInt64(bytes, 0));
    }
    public string ReadString()
    {
    ushort len = ReadUShort();
    byte[] buff = Read(len);
    return Encoding.UTF8.GetString(buff);
    }
    public string ReadUserId()
    {
    byte len = (byte)ReadByte();
    byte[] buff = Read(len);
    return Encoding.UTF8.GetString(buff);
    }
    public byte[] Read(int len)
    {
    byte[] buff = new byte[len];
    this.Read(buff, 0, len);
    return buff;
    } public override bool CanRead
    {
    get { return stream.CanRead; }
    } public override bool CanSeek
    {
    get { return stream.CanSeek; }
    } public override bool CanWrite
    {
    get { return stream.CanWrite; }
    } public override void Flush()
    {
    stream.Flush();
    } public override long Length
    {
    get { return stream.Length; }
    } public override long Position
    {
    get
    {
    return stream.Position;
    }
    set
    {
    stream.Position = Position;
    }
    } public override int Read(byte[] buffer, int offset, int count)
    {
    return stream.Read(buffer, offset, count);
    } public override long Seek(long offset, System.IO.SeekOrigin origin)
    {
    return stream.Seek(offset, origin);
    } public override void SetLength(long value)
    {
    stream.SetLength(value);
    } public override void Write(byte[] buffer, int offset, int count)
    {
    stream.Write(buffer, offset, count);
    } public override void Close()
    {
    stream.Close();
    base.Close();
    }
    }
    #endregion
    }Send:
    BufferedStream bs = new BufferedStream(tcpClient.GetStream());
    bs.Write("111");
    bs.Write("222");
    bs.Write("333");
    bs.Write(DateTime.Now);Receive:
    BufferedStream bs = new BufferedStream(tcpClient.GetStream());
    string str1=bs.ReadString();
    string str2=bs.ReadString();
    string str3=bs.ReadString();
    DateTime dt = bs.ReadDateTime();
      

  11.   

    TCP的话 你用tcpclient连接。
    然后用NetWorkStream或许连接的网络流。
    用networkstream 对远程主机进行读数据和写数据。
    例如NetWorkStream ns=new NetWorkStream ();
    ns.write();
    ns.flush();
    ns.write();
    ns.flush()
    就可以一个一个发了
      
      

  12.   

    在现有的TCP协议下, 由于是无消息边界的流传输; 只能自己处理消息的边界;
    通用的做法是, 使用特殊标记, 以及长度字段;
      

  13.   

    111的长度+111的byte[]数组+222的长度+222的byte[]数组+asdfsafd乱七八糟不定长的长度+asdfsafd乱七八糟不定长的byte[]数组 在服务端只需取到第一个包的长度,按照长度取相应长度的数据,这个样能取到111....-------------------
    我想知道你是怎么在接收端----得到到第一个包的长度的
    是用btye[] by = new byte[1];接收 还是用 btye[] by = new byte[10]; 比较大一点的数组接收
      

  14.   


    我认为缺陷就是----要用个一个固定的长度的byte[]数组去接收 发送字符长度比如  第一次发送 "111" 长度为 3  ,3是一个字节
          第二次发送 "222" 长度为 3  ,3是一个字节
          第三次发送 "3333333333333" 长度为 13  ,13是2个字节
          第四次发送 "4444444444444444.....更长" ,比如长度为 1111  ,1111是4个字节
          ...更多那么接收端最少要声明一个 >=4的数据,每次接收都固定截取前>=4个字节 就以最大发4位数大小的字节为例那么第一次发送就不能发:"3111"  接收的时候截取前4个字节 就会 接到长度为3111了而是要发3***111-------接收时先接前4位  3*** 去掉*** 得到字符3 在转换成数字3
    在根据这个3  又截取3位---得到"111"第二次发送 同理 发3***222  接收同理第三次发 13**3333333333333  接收同理第四次发 11114444444444444444.....  先接收前4位 转换成数字1111 在截取1111个字节 ----------------------------------
    如果发送数据更大了....一个5位数 发3****111
    ----------------------------------呵呵就这么说一说  不知道是不是这个样的
      

  15.   

    郁闷了郁闷了,快疯了
    客户端:
                string a1="111";
                Socket.Send(GetPacket(string a1));
                string a2 = "222";
                Socket.Send(GetPacket(string a2));
                string a3 = "123sdaf乱七八糟不定长";
                Socket.Send(GetPacket(string a2));        private byte[] GetPacket(string context)
            {
                byte[] contextByte = Encoding.ASCII.GetBytes(a1);
                byte[] lengthByte = BitConverter.GetBytes(contextByte.Length);
                //假设前2个字节为长度 OK?我们规定好的
                byte[] sendByte = new byte[contextByte.Length + lengthByte.Length];
                int offset = 0;
                Buffer.BlockCopy(lengthByte, offset, sendByte, 0, lengthByte.Length);
                offset += lengthByte.Length;
                Buffer.BlockCopy(contextByte, offset, sendByte, 0, contextByte.Length);
            }
    服务端:            //假设recvByte是你收到的数据
                byte[] recvByte = new byte[1024];
                byte[] lengthByte = new byte[2];
                int offset = 0;
                int length;
                //第一个包
                Buffer.BlockCopy(recvByte, offset, lengthByte, 0, 2);
                offset += 2;
                length=BitConverter.ToInt32(lengthByte, 0);
                byte[] firstPacket = new byte[length];
                Buffer.BlockCopy(recvByte, offset, firstPacket, 0, length);
                offset+=length;
                //第二个包
                Buffer.BlockCopy(recvByte, offset, lengthByte, 0, 2);
                offset += 2;
                length = BitConverter.ToInt32(lengthByte, 0);
                byte[] secondPacket = new byte[length];
                Buffer.BlockCopy(recvByte, offset, secondPacket, 0, length);
                offset += length;
                //第三个包
                Buffer.BlockCopy(recvByte, offset, lengthByte, 0, 2);
                offset += 2;
                length = BitConverter.ToInt32(lengthByte, 0);
                byte[] thridPacket = new byte[length];
                Buffer.BlockCopy(recvByte, offset, thridPacket, 0, length);
                offset += length;
      
    这时候firstPacket  secondPacket   thridPacket 分别是你得到的3个数据
    直接
    string a1=Encoding.ASCII.GetString(firstPacket);
    string a2=Encoding.ASCII.GetString(secondPacket);
    string a3=Encoding.ASCII.GetString(thridPacket);
    这样就回来了
    额……楼主你要是不给我多分我都亏死了
      

  16.   

    修正一下
       private byte[] GetPacket(string context) 
            { 
                byte[] contextByte = Encoding.ASCII.GetBytes(context); //这里应该是context
                byte[] lengthByte = BitConverter.GetBytes(contextByte.Length); 
                //假设前2个字节为长度 OK?我们规定好的 
                byte[] sendByte = new byte[contextByte.Length + lengthByte.Length]; 
                int offset = 0; 
                Buffer.BlockCopy(lengthByte, offset, sendByte, 0, lengthByte.Length); 
                offset += lengthByte.Length; 
                Buffer.BlockCopy(contextByte, offset, sendByte, 0, contextByte.Length); 
            } 
      

  17.   


    2 个字节是一个 ushort
    4 个字节是一个 uint我想,用 4 个字节已经绰绰有余了吧, 你该不会发大于 uint.MaxValue 长度的数据包吧...
      

  18.   

    UDP不会出现粘包,因为它有消息边界
      

  19.   

    我资源中有现成代码,“Socket编程实例 (F2.0)”,“C# Socket F3.5”都可以实现。
      

  20.   

    没什么好的方案,要就自己定制协议,例如加一些分割符来判断包,这是传递string一些简单的东西,但是如果要传递表或dataset怎么办呢!?所以说用wcf比较好吧
      

  21.   

    这个问题,我们解决了.你自己在每次发送数据的时候带两面三刀部分信息,比如:你的接收的时候,首4个字节记录消息的长度,根据这个长度信息Read,读出来的就是第一个消息,接着在读4个字节长度,根据这个长度信息Read,读出来的就是第二个消息,依次类推.问题解决.
      

  22.   

    进来学习下
    刚好要学习Socket
      

  23.   

    长连接的用处跟一般人想象的完全不同。假设你做一个服务,假设想给1000个客户端服务,如果是长连接方式,那么你的服务应该启动多少线程来维系这种连接呢?同时,如果不进行链路检测,那么浪费是多么巨大啊?而每一个客户端上如果都有不止一个应用需要跟服务器搞什么长连接,这岂不是灾难?!所以你只是做一个小程序,测试一段长连接功能,实际上你做的东西一旦拿到生产环境就根本是灾害程序,不能用起来。所以我建议你先搞好短连接就可以了。既然客户端想发送多个信息,那么就把多个信息打包成一个数据包(一个结构由三个字段,每一个都是一个更简单的结构一样),然后一次性地send到服务器,然后从服务器收听一个结果,这一个结果也是三个结果的打包。
      

  24.   

    什么时候使用长连接?假设我们有10万个客户都跟几大移动、电信部门的通信网关连接,而我们的系统只跟7、8个类似CMPP之类的网关建立联系,这种情况下我们用长连接或许是正确的选择。这时候,人家设计高级系统的人,早给你规定好详细的长连接通讯协议了,而且各家的可能都不一样。
      

  25.   

    类似CMPP之类的网关建立联系  -->  类似CMPP网关之类的服务建立联系
      

  26.   


    如果是 点 --对 -- 点 的话 用短连接 还是行吧(如 客户端只是向服务器上传和下载文件)如果是 客户---服务器---客户  (公司做一个聊天程序) 用短连接就不行了吧现在对于Socket的一些基本知识,基本用法 现在掌握的差不多了---
    掌握这些 基础的还是容易,要是 达到 sp1234 你对Socket,对编程的理解...我们现在难啊我们公司不是软件公司啊,作出来的东西无法体会到成千上万的人用...我们公司就那么100吧号人,最多就是100个线程......(不是很清楚100个线程是什么概率...有啥负面影响)如果我做的东西 100个人用不出现啥问题...不出问题,找不到问题,找不到错误...我就无法优化程序,就学不到更多的知识..----------------这个贴现在没结,看回复的人蛮多的----可能对新手有点作用,我开始学的时候,怎么都想不通 发3次,为啥一次就接收了.....后来买了本网络编程的书看才看明白-----这里有人提到 "粘包"---发送的时候可能粘包 -------接收的时候也可能粘包----------------先放这里 等几天接吧
      

  27.   

    ...
    int BufListLen =  Pro->CreateBufList(m_Rx, m_RxLen);
    if (!BufListLen)
    {
    return 0;
    }
    ...
    粘包时,将接收到的数据按照协议产生一个报文队列。
      

  28.   

    没有想到,新手来这看这么多高手在聊socket,谢谢学习了!
      

  29.   

    不知道为什么,我用stream write,一次只会发送一个字符,而不是整个字符串.
      

  30.   

    不知道为什么,我用stream write,一次只发送一个字符,而不是整个字符串.
      

  31.   

    最近也在socket,丢包,粘包都遇到了谈说中
      

  32.   

    如果是传送文件?又怎么传哦?不如说MINA框架?MINA2(我采用的版本是MINA2 RC1版本)中我采用第一种方式来读取消息报文。 
    具体代码:可以利用IoBuffer的prefixedDataAvailable方法得到消息头,可惜看了MINA2的源代码之后,prefixedDataAvailable方法的参数只是是1,2,4,也就是说只能设定1,2,4位长度的消息头,这样如果你是自定义长度的报文头,那可就不支持了,不过可以修改MINA2的源码来实现自己特殊的要求。 
    请高手提一些宝贵意见哦