BeginRead 内存不足异常
Out of memory exception with BeginRead
这个小项目背后的想法是开发一个不同的聊天应用程序,我想发送对象而不是纯字符串。到目前为止,这就是我所拥有的。
如果我在构造函数上反序列化,它工作得很好(UserDTO 目前只有 2 个字符串字段),但是,我计划让多个客户端随时向服务器发送数据。即使在阅读了 MS 的文档之后,我也很难理解它是如何工作的以及如何修复错误(像这样,它在 Deseralize 行给出了一个 "Exception of type 'System.OutOfMemoryException' was thrown."),我想从你们那里得到一些想法。
请注意任何试图编译它的人:Binaryformatter 有一种方法可以做到这一点:假设 UserDTO 具有属性字符串名称、字符串电子邮件
将此 class 应用于客户端和服务器,您必须使用 class 库构建它并将此引用添加到两个项目,因为不知何故 binaryformater 说即使您创建相同的 class 在这两个项目中,反序列化声明它无法映射对象。我将在下面留下我正在使用的客户端示例。
服务器:
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
中的字节来反序列化。
这个小项目背后的想法是开发一个不同的聊天应用程序,我想发送对象而不是纯字符串。到目前为止,这就是我所拥有的。
如果我在构造函数上反序列化,它工作得很好(UserDTO 目前只有 2 个字符串字段),但是,我计划让多个客户端随时向服务器发送数据。即使在阅读了 MS 的文档之后,我也很难理解它是如何工作的以及如何修复错误(像这样,它在 Deseralize 行给出了一个 "Exception of type 'System.OutOfMemoryException' was thrown."),我想从你们那里得到一些想法。
请注意任何试图编译它的人:Binaryformatter 有一种方法可以做到这一点:假设 UserDTO 具有属性字符串名称、字符串电子邮件 将此 class 应用于客户端和服务器,您必须使用 class 库构建它并将此引用添加到两个项目,因为不知何故 binaryformater 说即使您创建相同的 class 在这两个项目中,反序列化声明它无法映射对象。我将在下面留下我正在使用的客户端示例。
服务器:
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
中的字节来反序列化。