2016-09-07 42 views
2

这个小项目背后的想法是开发一个聊天应用程序,区别在于我想发送对象而不是纯粹的字符串。到目前为止,这就是我所拥有的。内存异常与BeginRead

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

注意给谁试图编译这个: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"); 
    } 
} 
+0

何时'while(true);'循环退出? (回答:当程序内存耗尽时,我假设) – Quantic

+0

仅用于测试目的,它现在从不退出,主要是反序列化部分给我一个很难的时间(当使用字符串和Streamwriter时,它适用于多个客户端) – abr

+0

@Quantic我怀疑这是问题,因为循环没有增加正在使用的内存量。 – EJoshuaS

回答

1

而不是做所有的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中的字节进行反序列化。

+0

好吧,这的确像我上面写的那样工作,但问题会变成:用户如何以异步的方式发送数据,因为这只会执行一次 – abr

+1

在那种情况下,最终使用'byte []'你有。这就是您所有数据的存储位置。你不能使用'GetStream()',因为它已被读取。 'readBuffer'包含你的数据,你必须进行检查以确定它是否具有所有的数据实际上是'UserDTO'或者你只有一些数据。要点是,不要将该流用于反序列化。使用您已有的字节创建对象。如果你的对象可以包含超过2000个字节,你可能想要查看BitConverter或BinaryReader,因为如果它包含了,你需要知道UserDTO何时开始/结束。 – TyCobb

+0

谢谢你的帮助,我更新了这个问题,因为它给了我一个奇怪的错误atm,你认为发生了什么? – abr