首页 新闻 赞助 找找看

关于.Net 中Socket运行机制的问题

0
悬赏园豆:50 [已解决问题] 解决于 2010-12-14 22:42

请问在.Net的Socket中,通信双方数据传输的机制是怎么样的? 我需要在发送方不断地发送图像,接收方不断地地接收图片。发送方发送每张图片前,先发送图片的大小DataSize。接收方接收时先接收四字节,并转成一个整型变量,即图片的大小DataSize,然后再根据DataSize设置接收缓存的大小,接着再接收图片。

接收方代码如下:

void receive()
        {
            byte[] tmp = new byte[4];
            //接收图片大小
            sClient.Receive(tmp, 0, 4, 0);      
            DataSize = BitConverter.ToInt32(tmp, 0);

            sClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, DataSize);//设置接收缓存
            buffer = new byte[DataSize];
            sClient.Receive(buffer, 0, DataSize, 0); //接收图片
            ms = new MemoryStream(buffer);
            bmp = new Bitmap(ms);
            pictureBox1.Image = bmp;//显示图片

           theThread = new Thread(new ThreadStart(receive));
           theThread.Start();//继续接收下一张图片
            
            return;
        }

  发送代码如下:

     for (;;)
                {  int DataSize;
                    //准备数据
                    ms = new MemoryStream();
                    SendImage[index].Save(ms, ImageFormat.Bmp);
                    bytData = ms.ToArray();
                    DataSize = bytData.Length;  
                    byte[] SizeBuff = BitConverter.GetBytes(DataSize);
                    sendSocket.Send(SizeBuff, 0, SizeBuff.Length, 0);//发送图片大小                  

        sendSocket.BeginSend(bytData, 0,DataSize, 0, new AsyncCallback(SendCallback), sendSocket);  //发送图片
                    SendDone.WaitOne();
                }

回调函数如下:

  private void SendCallback(IAsyncResult ar)
        {
            try
            {
                Socket sendSocket = (Socket)ar.AsyncState;
                sendSocket.EndSend(ar);
                SendDone.Set();

            }
            catch (System.Exception e)
            {
                MessageBox.Show("error3:" + e.Message + "\n" + e.Source);

            }

        }

实验过程中总是会报“算术运算导致溢出”,经变量监视发现接收到的DataSize会出现负值或者超大的数,从而导致溢出。但DataSize是发送端传送过来的图片大小,不可能出现负数或超大的数。我想肯定是传送和接收的过程中出现的错误。但本人对Socket编程实在不熟,所以请教各位Socket传输的过程是怎么样的?尤其是以下问题请各位解答:

 发送方发送的数据在接收方未接收时都存放在哪的(我知道有sendBuffer,但实验中貌似在接收方接收之前,发送方可以连续发送好几个sendBuffer大小的数据)?  另外,接收方用receive接收指定大小的数据时,如果receiveBuffer中的数据还未达到指定的数量,接收方会怎么做? 在接收方缓冲已满的情况下,发送方会自动停止发送数据吗?还是会继续发送?

请知道的朋友不吝赐教,不胜感激!

Green Billow的主页 Green Billow | 初学一级 | 园豆:60
提问于:2010-12-12 22:46
< >
分享
最佳答案
0

应该是接受和发送不同步造成的

收获园豆:50
eaglet | 专家六级 |园豆:17139 | 2010-12-13 08:36
对的,我也这么认为。那么socket传输过程具体是怎么样的呢?请赐教!
Green Billow | 园豆:60 (初学一级) | 2010-12-13 11:03
你的接收代码写的不对 sClient.Receive 这个函数不能保证肯定能接收到你指定 size 的数据,这个函数有个返回值,用于告诉你实际接收了多少字节,你必须判读这个返回值。具体你可以看微软的例子是怎么写的。
eaglet | 园豆:17139 (专家六级) | 2010-12-13 19:38
我也知道receive返回的是接受的字节数,您说的例子应该是指while(byts>0){}这样确保接收所有数据吧。但是,我这里是连续发送图片,所以byts>0可能是下一帧数据进入接收缓存导致的,这样就无法区分开连续的两张图片。试验中发现逐步调试时程序可以顺利运行,而直接运行时就会报错。我想可能是发送速度过快导致数据丢失导致错误的吧。请问.Net中有没有什么机制使得发送方和接收方达成同步,即只有当接收方的应用程序从socket缓存中接收数据后,发送方才发下一帧数据。请赐教,麻烦了,实在是被这个问题搞的够呛!
Green Billow | 园豆:60 (初学一级) | 2010-12-14 00:44
问题肯定是这个问题造成,你单步是好的,是因为单步的等待时间很长,数据全部接受过来了,但如果连续跑,数据不一定能在你接收时全部发送到。 你不要写 while(bytes>0) ,写成 remain = DataSize; while (remain > 0) { remain -= sClient.Receive(buffer, DataSize-remain, remain); //最后一个参数我不知道是什么意思,不知道 sClient 到底是个什么类,反正大概就这个意思吧。 } }
eaglet | 园豆:17139 (专家六级) | 2010-12-14 03:46
谢谢您的帮助。终于调好了,就是你说的这个问题造成的。我最后改成了 int begin=0; while (true) { byts = sClient.Receive(buffer, begin, DataSize, 0); if (byts <= 0) break; begin += byts; DataSize -= byts; } 谢谢您的帮助!以后多多交流!
Green Billow | 园豆:60 (初学一级) | 2010-12-14 22:39
其他回答(1)
0

不需要分两次发送吧。receive函数的返回值就是你读取到的字节数,所以在消息内容里加四个字节包含消息长度,和receive的返回值比较就知道了是不是接收正确。

不过我觉得溢出应该是你使用了长连接,循环发送导致的。

socket我也就是前端时间搞过,没有深入。说的不对还请包含

高凡凡高 | 园豆:95 (初学一级) | 2010-12-13 13:21
谢谢您的回答。但我考虑过,因为图片是连续发送的,所以必须先知道当前要接收的图片的大小,否则无法判断当前图片数据在哪里结束,这样连续两张图片就可能混在一起,使得无法得到完整的图片。
支持(0) 反对(0) Green Billow | 园豆:60 (初学一级) | 2010-12-13 14:26
可以给每张图片发送开始和结束的时候加上起始码和结束码试试
支持(0) 反对(0) aixuexi | 园豆:210 (菜鸟二级) | 2010-12-13 17:12
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册