rb622
rb622
采纳率40%
2017-09-01 08:26 阅读 3.3k

c# Socket,tcp接收时会粘包?

private void RecMsg(object sokConnectionparn)
{
Socket sokClient = sokConnectionparn as Socket;
while (true)
{

            byte[] arrMsgRec = new byte[1024 * 1024 * 3+3];
            // 将接受到的数据存入到输入  arrMsgRec中;
            int length = -1;
            try
            {
                length = sokClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;

            }
            catch (SocketException se)
            {
                ShowMsg("异常:" + se.Message);

                dictSocket.Remove(sokClient.RemoteEndPoint.ToString());

                dictThread.Remove(sokClient.RemoteEndPoint.ToString());

                DeleteLib(sokClient.RemoteEndPoint.ToString());

                break;
            }
            catch (Exception e)
            {
                ShowMsg("异常:" + e.Message);
                dictSocket.Remove(sokClient.RemoteEndPoint.ToString());
                dictThread.Remove(sokClient.RemoteEndPoint.ToString());
                DeleteLib(sokClient.RemoteEndPoint.ToString());
                break;
            }
            try
            {
                if (arrMsgRec[0] == 0)  // 表示接收到的是数据;
                {
                    string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1);// 将接受到的字节数据转化成字符串;
                    ShowMsg(strMsg);
                }
                if (arrMsgRec[0] == 1) // 表示接收到的是文件;
                {
                    filesource = sokClient.RemoteEndPoint.ToString();

                    //var i = BitConverter.ToInt32(arrMsgRec, arrMsgRec.Length-3);
                    if (System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1).Contains("FileName"))
                    {
                        string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1);
                        bpp.FileName = strMsg.Split(':')[1];
                        bpp.Index = 0;
                        savepath = "";
                        savepath = Path.Combine(savepath, bpp.FileName);
                    }
                    else if (System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1).Contains("PackageCount"))
                    {
                        string strMsg = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length - 1);
                        bpp.PackageCount = int.Parse(strMsg.Split(':')[1]);
                    }

                    else if (arrMsgRec[1] == 22 && arrMsgRec[2] == 33)
                    {
                        //int i = BitConverter.ToInt32(arrMsgRec, arrMsgRec.Length - 3);
                        byte[] buffer = new byte[length - 3];
                        Buffer.BlockCopy(arrMsgRec, 3, buffer, 0, buffer.Length);
                        if (!string.IsNullOrEmpty(bpp.FileName))
                        {

                            Thread fw = new Thread(() => FileWrite(savepath, bpp.Index, 1024 * 1024 * 3, buffer.Length, buffer));
                            fw.IsBackground = true;
                            fw.Start();
                        }
                    }
                    else
                    {
                        stringtobyte("Err:" + bpp.Index.ToString(), 1);
                        dictSocket[filesource].Send(stringtobyte("Err:" + bpp.Index.ToString(), 1));
                    }

                }
            }
            catch(Exception ex)
            {
                //MessageBox.Show(ex.Message);

            }
        }
    }
            用这个作为后台线程接收,然后发文件(客户端线程分包自动发的)的同时传输信息的话会粘包吧,好像是这个说法,就是那一包文件数据会收不到,然后聊天信息会出现乱码,求教怎么解决,新手实在搞不定- -谢谢.
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

1条回答 默认 最新

  • code68 dsad sad ad 2017-09-01 08:55

    当socket接收到数据后,会根据buffer的大小一点一点的接收数据,比如:

    对方发来了1M的数据量过来,但是,本地的buffer只有1024字节,那就代表socket需要重复很多次才能真正收完这逻辑上的一整个消息。
    对方发来了5条2个字符的消息,本地的buffer(大小1024字节)会将这5条消息全部收入囊下...
    那么,如何处理呢?下面我以最简单的一种文本消息来demo

    根据上面所描述的情况,最重要的关键落在了下面3个因素的处理上

    消息的结尾标记
    接收消息时判断结尾标记
    当本次buffer中没有结尾标记时怎么处理
    我把写好的核心算法贴出来:

     StringBuilder sb = new StringBuilder();             //这个是用来保存:接收到了的,但是还没有结束的消息
            public void ReceiveMessage(object state)            //这个函数会被以线程方式运行
            {
                Socket socket = (Socket)state;
                while(true)
                {
                    byte[] buffer = new byte[receiveBufferSize];  //buffer大小,此处为1024
                    int receivedSize=socket.Receive(buffer);
    
                    string rawMsg=System.Text.Encoding.Default.GetString(buffer, 0, receivedSize);
                    int rnFixLength = terminateString.Length;   //这个是指消息结束符的长度,此处为\r\n
                    for(int i=0;i<rawMsg.Length;)               //遍历接收到的整个buffer文本
                    {
                        if (i <= rawMsg.Length - rnFixLength)
                        {
                            if (rawMsg.Substring(i, rnFixLength) != terminateString)//非消息结束符,则加入sb
                            {
                                sb.Append(rawMsg[i]);
                                i++;
                            }
                            else
                            {
                                this.OnNewMessageReceived(sb.ToString());//找到了消息结束符,触发消息接收完成事件
                                sb.Clear();
                                i += rnFixLength;
                            }   
                        }
                        else
                        {
                            sb.Append(rawMsg[i]);
                            i++;
                        }
                    }
                }
            }
    

    A2DTcpClient client = new A2DTcpClient("127.0.0.1", 5000);
    client.NewMessageReceived += new MessageReceived(client_NewMessageReceived);
    client.Connect();
    client.Send("HELLO");
    client.Close();

        static void client_NewMessageReceived(string msg)
        {
            Console.WriteLine(msg);
        }
    
    点赞 3 评论 复制链接分享

相关推荐