The idea behind this small project is developing a chat application with a difference that I want to send objects instead of just plain strings. So far, this is what I have.
If I deserialize on the constructor, it works just fine (UserDTO only has 2 string fields for now), however, I plan on having multiple clients sending data to the server anytime they wish. I'm having some difficulty understanding how it works and how to fix the error (like this, it gives an "Exception of type 'System.OutOfMemoryException' was thrown." at the Deseralize line) even after reading MS's documentation and I'd like some ideas from you guys.
Note to whoever tries to compile this: Binaryformatter has a way of doing this as in: Let's say UserDTO has properties string Name, string Email Applying this class to a client and the server, you must build it using a class library and add reference of this to both projects, because somehow binaryformater says that even tho if you create the same class in both projects, deserializing claims it cannot map the object. I'll be leaving a sample of the client that I am using below.
Server:
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());
}
}
Client:
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");
}
}
Instead of doing all of the BeginRead()
calls, try just taking the stream and passing it into the BinaryFormatter.DeSerialize()
method.
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);
}
My guess is that your stream position is already moved, if not at the end. When you pass it into the Deserialize()
, there just isn't anymore data for it to read. In fact, your byte[] readBuffer
probably has all of the data you wanted if your DTO can't hold more than 2000 bytes. If this is the case, then you should be able to use the bytes in readBuffer
to deserialize instead.