c# - BeginRead 内存不足异常

标签 c# object tcpclient networkstream binaryformatter

这个小项目背后的想法是开发一个不同的聊天应用程序,我想发送对象而不是纯字符串。到目前为止,这就是我所拥有的。

如果我在构造函数上反序列化,它工作得很好(UserDTO 目前只有 2 个字符串字段),但是,我计划让多个客户端随时向服务器发送数据。我很难理解它是如何工作的以及如何修复错误(像这样,它在 Deseralize 行给出了“类型为‘System.OutOfMemoryException’的异常被抛出。”),即使在阅读了 MS 的文档之后,我也会喜欢你们的一些想法。

请注意任何试图编译它的人:Binaryformatter 有一种方法可以做到这一点:假设 UserDTO 具有属性字符串名称、字符串电子邮件 将此类应用于客户端和服务器,您必须使用类库构建它并将它的引用添加到两个项目,因为不知何故 binaryformater 说即使您在两个项目中创建相同的类,反序列化声称它无法映射目的。我将在下面留下我正在使用的客户端示例。

服务器:

class Program {
const int serverPort = 60967;
static List<UserConnection> clientList = new List<UserConnection>();
static TcpListener listener;
static Thread listenerThread;


static void Main(string[] args) {
        listenerThread = new Thread(new ThreadStart(DoListen));
        listenerThread.Start();
        Console.WriteLine("Server Started");
        //while (true) {
            string a = Console.ReadLine()
        //}
   }

static void DoListen() {
        try {
            listener = new TcpListener(System.Net.IPAddress.Any, serverPort);
            listener.Start();
            Console.WriteLine("Listening [...]");
            do {
                UserConnection client = new UserConnection(listener.AcceptTcpClient());
                //clientList.Add(client);
                Console.WriteLine("New connection found"); 
            } while (true);
        }
        catch (Exception ex) {
            Console.WriteLine(ex.ToString());
        }
    }
}



public class UserConnection {
private TcpClient clientInfo;
private byte[] readBuffer = new byte[2000];
const int READ_BUFFER_SIZE = 2000;

public UserConnection(TcpClient client) {
    clientInfo = client;
    clientInfo.GetStream().BeginRead(readBuffer, 0, READ_BUFFER_SIZE, new AsyncCallback(StreamReceiver), null);
}

private void StreamReceiver(IAsyncResult ar) {
    try
    {
        if (client.GetStream().CanRead) {
        lock (clientInfo.GetStream()) {
            var strm = clientInfo.GetStream();
            int BytesRead = clientInfo.GetStream().EndRead(ar);
            BinaryFormatter formatter = new BinaryFormatter();
            var mydat = (UserDTO)formatter.Deserialize(strm);
        }
        lock (clientInfo.GetStream()) {
            clientInfo.GetStream().BeginRead(readBuffer, 0, READ_BUFFER_SIZE, new AsyncCallback(StreamReceiver), null);
        }
    }

    catch (Exception e) {
     Console.WriteLine(ex.ToString());
    }
}

客户:

class Program {
    static void Main(string[] args) {
            ConnectResult("localhost", 60967);
            Console.ReadLine();
        }
    }

    static string ConnectResult(string ip, int port) {
        try {
            TcpClient client = new TcpClient(ip, port);
            AttemptLogin(client);
            return "Connection Succeeded";
        }
        catch (Exception ex) {
            return "Server is not active.  Please start server and try again.      " + ex.ToString();
        }
    }

    static void AttemptLogin(TcpClient client) {
        UserDTO obj = new UserDTO("email", "username");
        IFormatter formatter = new BinaryFormatter();
        var stream = client.GetStream(); 
        formatter.Serialize(stream, obj);
        Console.WriteLine("Sent Object");
    }
}

最佳答案

与其执行所有 BeginRead() 调用,不如尝试获取流并将其传递给 BinaryFormatter.DeSerialize() 方法。

public UserConnection(TcpClient client) {
    clientInfo = client;
    //clientInfo.GetStream().BeginRead(readBuffer, 0, READ_BUFFER_SIZE, new AsyncCallback(StreamReceiver), null);
    var strm = clientInfo.GetStream();
    BinaryFormatter formatter = new BinaryFormatter();
    var mydat = (UserDTO)formatter.Deserialize(strm);
}

我猜你的流位置已经移动了,如果不是在最后的话。当您将它传递给 Deserialize() 时,就没有数据可供它读取了。事实上,如果您的 DTO 不能容纳超过 2000 个字节,您的 byte[] readBuffer 可能拥有您想要的所有数据。如果是这种情况,那么您应该能够使用 readBuffer 中的字节来反序列化。

关于c# - BeginRead 内存不足异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39373748/

相关文章:

c# - .NET 中的 EntityFramework - 将子实体添加到现有父实体时,正在验证/添加父实体

c# - 如何使用 RestSharp 反序列化名为 “value” 的属性而不破坏代码风格?

javascript - 如何在单例类中调用同级函数?

关于属性更改的 Php 运行方法

javascript - 将我的变量放在命名空间下

c# - 为什么 NetworkStream.ReadAsync 没有超时?

c# - 删除一行 - Sql C#

c# - C#中字符串和StringBuilder的区别

c# - 让 HTTPClient 等待数据写入

c# - Windows 服务中的 TCP IP 监听器