套接字问题和 OutOfMemory 错误 [英] Problem with sockets and OutOfMemory error

查看:43
本文介绍了套接字问题和 OutOfMemory 错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个大问题.试图创建一个应用程序,它必须有两个部分:服务器端和客户端.这两个部分必须以某种方式进行通信并交换对象.我决定使用 Sockets,因为我不熟悉 WCF,而且我可以在同一台计算机上测试这两个部分(只需将它们放在 127.0.0.1 地址上侦听).

I have a huge problem. Trying to create an app that has to have two parts: server and client side. Those two parts have to communicate somehow and exchange objects. I have decides to use Sockets because i'm not familiar with WCF, and i can test both parts on same computer (just put them to listen at 127.0.0.1 address).

现在,当我尝试从客户端发送一些自定义"可序列化对象时,我在服务器端遇到了OutOfMemory"异常!我读过套接字,发送/接收对象的方法,我尝试了一些我在网上找到的代码,但没有运气!我不知道我的代码有什么问题.这是我的代码:

Now, when i try to send some "custom" serializable object from client i got "OutOfMemory" exception at server side! I read about Sockets, ways to send/receive objects, i have tried some code i found on net but no luck! I have no idea what's wrong with my code. Here's my code:

这是双方代码中定义的测试类:

This is test class defined in code of both sides:

[Serializable]
    class MyClass
    {
        public string msg="default";
    }

客户端发送代码(工作正常):

Client-side sending code (works fine):

private void cmdSendData_Click(object sender, System.EventArgs e)
    {
        try
        {
            MyClass test = new MyClass();

            NetworkStream ns = new NetworkStream(m_socWorker); //m_socWorker is socket
            BinaryWriter bw = new BinaryWriter(ns);

            MemoryStream ms = new MemoryStream();
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, test);

            bw.Write(ms.ToArray());
            MessageBox.Show("Length is: " + ms.ToArray().Length); //length is 152!
            ns.Close();
        }
        catch(System.Net.Sockets.SocketException se)
        {
            MessageBox.Show (se.Message );
        }
    }

服务器端代码(导致问题的代码):

Server-side code (the one that cause problems):

public  void OnDataReceived(IAsyncResult asyn)
    {
        try
        {
            CSocketPacket theSockId = (CSocketPacket)asyn.AsyncState ;

            NetworkStream ns = new NetworkStream(m_socWorker);
            byte[] buffer = new byte[1024];
            ns.Read(buffer, 0, buffer.Length);

            BinaryFormatter bin = new BinaryFormatter();
            MemoryStream mem = new MemoryStream(buffer.Length);

            mem.Write(buffer, 0, buffer.Length);
            mem.Seek(0, SeekOrigin.Begin);
            MyClass tst = (MyClass)bin.Deserialize(mem); //ERROR IS THROWN HERE!

            MessageBox.Show(tst.msg);

            theSockId.thisSocket.EndReceive(asyn);

            WaitForData(m_socWorker);
        }
        catch (ObjectDisposedException )
        {
            System.Diagnostics.Debugger.Log(0,"1","\nOnDataReceived: Socket has been closed\n");
        }
        catch(SocketException se)
        {
            MessageBox.Show (se.Message );
        }
    }

所以,当我尝试反序列化时出现异常.不知道出了什么问题.

So, i got exception when i try to deserialize. Have no idea what's wrong.

我威胁我的代码如果你继续制造问题,我会向 StackOverflow 人员报告你",所以我来了 :)

I have threatened my code "if you continue causing problems i'll report you to StackOverflow guys" so here i'm :)

推荐答案

首先,虽然我不确定这是否直接导致您的问题,但您的阅读逻辑存在严重问题.

First, while I'm not certain if this is the cause of your issue directly, you have a serious issue with your reading logic.

  1. 您创建了一个 1024 字节的缓冲区并读入其中,而无需检查实际读取了多少;如果传入缓冲区只有 56 个字节,您将只能读取 56 个字节(除非您对套接字本身使用阻塞读取,否则可能会超时).同样,您的缓冲区中可能有 2000 个字节,这意味着您将有 976 个字节留在缓冲区中,除非您收到更多数据,否则它们不会得到处理.这可能是一个完整的对象,客户端可能正在等待对它的响应,然后再发送.
  2. 然后您获取该缓冲区并将其再次复制到 MemoryStream 中.而不是这样做,只需采用带缓冲区的 MemoryStream 构造函数的重载.您不会以这种方式复制数据.
  3. 您在处理传入数据后调用 EndReceive ;虽然这实际上可能不会导致错误,但它不符合 Begin/End 旧式异步模式的精神.您应该在回调开始时调用 EndXXX 以获取结果.
  1. You create a 1024 byte buffer and read into it without checking to see how much was actually read; if the incoming buffer only has 56 bytes, you'll only read 56 bytes (unless you use a blocking read on the socket itself, which could time out). Likewise, your buffer could have 2000 bytes in it, which means you'd have 976 bytes left in the buffer that won't get processed until you receive more data. That could be an entire object, and the client could be waiting on a response to it before it sends any more.
  2. You then take that buffer and copy it again into a MemoryStream. Rather than doing this, just take the overload of the MemoryStream constructor that takes a buffer. You won't be copying the data that way.
  3. You call EndReceive after you've processed the incoming data; while this may not actually cause an error, it's not in the spirit of the Begin/End old-style async pattern. You should call EndXXX at the beginning of your callback to get the result.

我意识到这不是对您问题的直接回答,但您确实需要重新考虑您不使用 WCF 的决定.

I realize that this is not a direct answer to your question, but you really need to reconsider your decision not to use WCF.

几个月前我和你在同一条船上;我以前没有使用过 WCF,也没有费心去研究它是如何工作的.它对我来说是一个非常大的黑匣子,我在其他平台上做过基于套接字的通信,所以它是一个已知的数量.回想起来,我选择投身 WCF 是我能做出的最好的决定.一旦您了解了一些概念(绑定、契约以及如何使用各种属性),服务的开发就很简单了,您无需花时间编写管道.

I was in the same boat as you a couple of months ago; I had not used WCF before, and I hadn't bothered to look at how things work in it. It was a very large black box to me, and I had done socket-based communication on other platforms, so it was a known quantity. Looking back, my choice to take the plunge into WCF was the best decision I could have made. Once you've wrapped your head around some of the concepts (bindings, contracts, and how to use the various attributes), development of the service is simple and you don't have to spend your time writing plumbing.

NetTcpBinding 提供了一个基于 TCP 的绑定,可以支持长期连接和会话(这是我使用它的方式),甚至处理保持连接的消息以保持连接通过 Reliable Sessions 打开.这就像打开一面旗帜一样简单.如果您需要更具互操作性的东西(即跨平台),您可以编写自己的绑定来执行此操作并保持代码原样.

NetTcpBinding provides a TCP-based binding that can support long-lived connections and sessions (which is how I'm using it), and even takes care of keep-alive messages to keep the connection open via Reliable Sessions. It's as simple as turning on a flag. If you need something more interopable (meaning cross-platform), you can write your own binding that does this and keep your code as-is.

看一些 TCP WCF 的例子;启动和运行一些东西不会花费你很长时间,一旦你达到那个点,修改就像在你的界面中添加一个函数一样简单,然后在你的服务类中添加一个相应的函数.

Look at some of the TCP WCF examples; it won't take you terribly long to get something up and running, and once you've reached that point, modification is as simple as adding a function to your interface, then a corresponding function on your service class.

这篇关于套接字问题和 OutOfMemory 错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆