binary formatter deserialize from memory stream freezing - c#

I am trying to do a client-server application that communicate through sockets and their messages are serialez and deserialised using BinaryFormatter. My code is freezing and does absolutely nothing when reaching deserialize, and I don't understand why since I have no exception. I also can not step into with debugger, everything is freezing. This is my code:
public class Serializer
{
public static MemoryStream ToStream(object obj)
{
var stream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(stream, obj);
return stream;
}
public static object FromStream(MemoryStream stream)
{
Console.WriteLine("Starting from stream");
var formatter = new BinaryFormatter();
stream.Seek(0, SeekOrigin.Begin);
object rez = formatter.Deserialize(stream); //NEVER GOES OVER THIS
Console.WriteLine("Starting deserialization" + rez);
return formatter.Deserialize(stream);
}
}
public class Connection
{
private Socket socket;
public Connection(Socket socket)
{
this.socket = socket;
Console.WriteLine($"Connected to client: {socket.RemoteEndPoint}");
Task.Factory.StartNew(() => Execute(socket));
}
private void Execute(Socket socket)
{
while (true)
{
var buffer = new byte[2048];
var bytesCount = socket.Receive(buffer);
if(bytesCount != 0)
{
var msgReceived = (Message)Serializer.FromStream(new MemoryStream(buffer, 0, buffer.Length));
Console.WriteLine($"Received msg: {msgReceived.Content}");
}
/* var msg = new Message { Content = "Hello World2!" };
Console.WriteLine($"Sending msg with content: {msg.Content}");
MemoryStream stream = Serializer.ToStream(msg);
var bytesSent = socket.Send(stream.GetBuffer());*/
Console.WriteLine("Trying again");
Thread.Sleep(500);
}
}
client code:
var host = Dns.GetHostEntry("localhost");
var ipAddress = host.AddressList.First();
var serverEndpoint = new IPEndPoint(ipAddress, 9000);
Socket serverSocket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Connect(serverEndpoint);
Console.WriteLine($"Successfully connected to server on: {serverSocket.RemoteEndPoint}");
while (true)
{
var msg = new Message { Content = "Hello World!" };
Console.WriteLine($"Sending msg with content: {msg.Content}");
MemoryStream stream = Serializer.ToStream(msg);
var bytesSent = serverSocket.Send(stream.GetBuffer());
Console.WriteLine("Waiting to receive");
var buffer = new byte[2048];
int bytesReceived = serverSocket.Receive(buffer);
if (bytesReceived != 0)
{
var receivedMessage = (Message)Serializer.FromStream(new MemoryStream(buffer));
Console.WriteLine($"Received message: {receivedMessage.Content}");
}
Console.WriteLine("Received done");
}
server code :
var host = Dns.GetHostEntry("localhost");
var ipAddress = host.AddressList.First();
var localEndPoint = new IPEndPoint(ipAddress, 9000);
var serverSocket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(localEndPoint);
serverSocket.Listen(1);
while (true)
{
Console.WriteLine("Waiting for client");
Socket clientSocket = serverSocket.Accept();
var connection = new Connection(clientSocket);
}
I also checked the byteCount and they are arriving to the server, also the buffer is not empty, I don't understand why deserialize does nothing..

You call Deserialize twice, I think problem here:
object rez = formatter.Deserialize(stream); //NEVER GOES OVER THIS
Console.WriteLine("Starting deserialization" + rez);
return formatter.Deserialize(stream);
I think you can use methods like that:
private byte[] SerializeMessage(Message msg)
{
var formatter = new BinaryFormatter();
byte[] buf;
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, msg);
buf = new byte[stream.Length];
return stream.ToArray();
}
}
private Message DeserializeMessage(byte[] buff)
{
var formatter = new BinaryFormatter();
ConnectingMessage msg;
using (Stream stream = new MemoryStream(buff))
{
msg = formatter.Deserialize(stream) as Message;
}
return msg;
}
Also methods Send/Receive are synchronous, they block thread execution.
The description of the asynchronous option is here https://learn.microsoft.com/en-us/dotnet/framework/network-programming/using-an-asynchronous-client-socket

Only one piece of code can run at the same time. While that infinute loop while (true) runs, no other code will ever be able to run.
You will need to add some Multitasking to this project. The minimum amount, that is required for every word processor. However you also seem to be programming in console. And from my experience, console and Multitasking do not mix that well. You need to keep the programm alive, without blocking input.
My advice for learning Multitasking, is a BackgroundWorker in Windows Forms. The BGW is dated, usese Threads wich would be unessary here and should not be used in productive code. But it is perhaps the best "Training Wheels" for multitasking and -threading I know off.

Related

Very basic web server in C#

I'm wanting to run a little socket server in C# to be accessed by a browser. I have a socket listener up and running on a specific port, and am trying to access it via the browser:
class WebSocketServer
{
private static string output = string.Empty;
public void CreateListener()
{
TcpListener tcpListener = null;
var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try
{
tcpListener = new TcpListener(ipAddress, 1313);
tcpListener.Start();
output = "Waiting for a connection";
}
catch (Exception e)
{
throw;
}
var socketHelper = new SocketHelper();
while (true)
{
Thread.Sleep(10);
TcpClient tcpClient = tcpListener.AcceptTcpClient();
byte[] bytes = new byte[256];
var stream = tcpClient.GetStream();
stream.Read(bytes, 0, bytes.Length);
socketHelper.ProcessMessage(tcpClient, stream, bytes);
}
}
}
class SocketHelper
{
private static int counter = 0;
public void ProcessMessage(TcpClient tcpClient, NetworkStream stream, byte[] bytesReceived)
{
// handle message received and send response to client
var msg = Encoding.ASCII.GetString(bytesReceived);
string response = string.Empty;
if (msg.Substring(0, 10) == "GET / HTTP")
{
response = "";// html page
}
byte[] bytesToSend = Encoding.ASCII.GetBytes(response);
stream.Write(bytesToSend, 0, bytesToSend.Length);
}
The browser appears to connect to it, but it never seems to display the html - what's wrong? I'm eventually wanting to be able to serve up JSON data via a REST interface. In addition, is there a much easier solution to (I assume) this common problem.

C# socket StreamReader.ReadToEnd wait forever

In an Universal Windows Platform (UWP) app, I'm trying to send an object to a Windows form program using socket:
public void CreateListener()
{
TcpListener listener = new TcpListener(IPAddress.Any, port);
listener.Start();
while (true)
{
if (listener.Pending())
{
var childSocketThread = new Thread(() =>
{
string data = null;
var Client = listener.AcceptTcpClient();
using (NetworkStream ns = Client.GetStream())
using (StreamReader sr = new StreamReader(ns))
{
data = sr.ReadToEnd();
var Items = JsonConvert.DeserializeObject<Models.Orders>(data);
Process(Items);
ns.Flush();
ns.Close();
}
});
childSocketThread.IsBackground = true;
childSocketThread.Start();
}
else
{
Thread.Sleep(50); //<--- timeout
}
}
}
But receiving object stuck in ReadToEnd and never exit.
What should I do?
Seems you have problem when you want to send data, after flushing your StreamWriter object you have to use StreamReader as a response.
Stream streamIn = socket.InputStream.AsStreamForRead();
StreamReader reader = new StreamReader(streamIn);
string response = await reader.ReadLineAsync();
Hope this would help you.

Respond to a client using a socket?

I have two basic console apps that communicate "over the network" even though all of the communication takes place on my local machine.
Client code:
public static void Main()
{
while (true)
{
try
{
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 500);
Console.WriteLine("Connected.");
byte[] data = ASCIIEncoding.ASCII.GetBytes(new FeederRequest("test", TableType.Event).GetXmlRequest().ToString());
Console.WriteLine("Sending data.....");
using (var stream = client.GetStream())
{
stream.Write(data, 0, data.Length);
stream.Flush();
Console.WriteLine("Data sent.");
}
client.Close();
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
}
Server code:
public static void Main()
{
try
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
Console.WriteLine("Starting TCP listener...");
TcpListener listener = new TcpListener(ipAddress, 500);
listener.Start();
Console.WriteLine("Server is listening on " + listener.LocalEndpoint);
while (true)
{
Socket client = listener.AcceptSocket();
Console.WriteLine("\nConnection accepted.");
var childSocketThread = new Thread(() =>
{
Console.WriteLine("Reading data...\n");
byte[] data = new byte[100];
int size = client.Receive(data);
Console.WriteLine("Recieved data: ");
for (int i = 0; i < size; i++)
Console.Write(Convert.ToChar(data[i]));
//respond to client
Console.WriteLine("\n");
client.Close();
Console.WriteLine("Waiting for a connection...");
});
childSocketThread.Start();
}
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
How can I alter both of these applications so that when the Server has received the data, it responds to the Client with some kind of confirmation?
Thanks in advance!
Here a short example how I would do it:
Server:
class Server
{
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 1500);
listener.Start();
TcpClient client = listener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
// Create BinaryWriter for writing to stream
BinaryWriter binaryWriter = new BinaryWriter(stream);
// Creating BinaryReader for reading the stream
BinaryReader binaryReader = new BinaryReader(stream);
while (true)
{
// Read incoming information
byte[] data = new byte[16];
int receivedDataLength = binaryReader.Read(data, 0, data.Length);
string stringData = Encoding.ASCII.GetString(data, 0, receivedDataLength);
// Write incoming information to console
Console.WriteLine("Client: " + stringData);
// Respond to client
byte[] respondData = Encoding.ASCII.GetBytes("respond");
Array.Resize(ref respondData, 16); // Resizing to 16 byte, because in this example all messages have 16 byte to make it easier to understand.
binaryWriter.Write(respondData, 0, 16);
}
}
}
Client:
class Client
{
private static void Main(string[] args)
{
Console.WriteLine("Press any key to start Client");
while (! Console.KeyAvailable)
{
}
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 1500);
NetworkStream networkStream = client.GetStream();
// Create BinaryWriter for writing to stream
BinaryWriter binaryWriter = new BinaryWriter(networkStream);
// Creating BinaryReader for reading the stream
BinaryReader binaryReader = new BinaryReader(networkStream);
// Writing "test" to stream
byte[] writeData = Encoding.ASCII.GetBytes("test");
Array.Resize(ref writeData, 16); // Resizing to 16 byte, because in this example all messages have 16 byte to make it easier to understand.
binaryWriter.Write(writeData, 0, 16);
// Reading response and writing it to console
byte[] responeBytes = new byte[16];
binaryReader.Read(responeBytes, 0, 16);
string response = Encoding.ASCII.GetString(responeBytes);
Console.WriteLine("Server: " + response);
while (true)
{
}
}
}
I hope this helps! ;)
You can perform both Read and Write on the same stream.
After you send all the data over, just call stream.Read as in
using (var stream = client.GetStream())
{
stream.Write(data, 0, data.Length);
stream.Flush();
Console.WriteLine("Data sent.");
stream.Read(....); //added sync read here
}
MSDN documentation on TcpClient has an example as well http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx
If you want feed back such as reporting # of bytes received so far, you'll have to use async methods.
Here's an example of what (I think) you want to do:
static void Main(string[] args) {
var server = new Task(Server);
server.Start();
System.Threading.Thread.Sleep(10); // give server thread a chance to setup
try {
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 1500);
Console.WriteLine("Connected.");
var data = new byte[100];
var hello = ASCIIEncoding.ASCII.GetBytes("Hello");
Console.WriteLine("Sending data.....");
using (var stream = client.GetStream()) {
stream.Write(hello, 0, hello.Length);
stream.Flush();
Console.WriteLine("Data sent.");
// You could then read data from server here:
var returned = stream.Read(data, 0, data.Length);
var rec = new String(ASCIIEncoding.ASCII.GetChars(data, 0, data.Length));
rec = rec.TrimEnd('\0');
if (rec == "How are you?") {
var fine = ASCIIEncoding.ASCII.GetBytes("fine and you?");
stream.Write(fine, 0, fine.Length);
}
}
client.Close();
Console.ReadLine();
}
catch (Exception e) {
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
public static void Server() {
try {
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
Console.WriteLine("*Starting TCP listener...");
TcpListener listener = new TcpListener(ipAddress, 1500); // generally use ports > 1024
listener.Start();
Console.WriteLine("*Server is listening on " + listener.LocalEndpoint);
Console.WriteLine("*Waiting for a connection...");
while (true) {
Socket client = listener.AcceptSocket();
while (client.Connected) {
Console.WriteLine("*Connection accepted.");
Console.WriteLine("*Reading data...");
byte[] data = new byte[100];
int size = client.Receive(data);
Console.WriteLine("*Recieved data: ");
var rec = new String(ASCIIEncoding.ASCII.GetChars(data, 0, size));
rec = rec.TrimEnd('\0');
Console.WriteLine(rec);
if (client.Connected == false) {
client.Close();
break;
}
// you would write something back to the client here
if (rec == "Hello") {
client.Send(ASCIIEncoding.ASCII.GetBytes("How are you?"));
}
if (rec == "fine and you?") {
client.Disconnect(false);
}
}
}
listener.Stop();
}
catch (Exception e) {
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
}
Keep in mind that data sent via sockets can arrive fragmented (in different packets). This doesn't usually happen with the packets are small.

Socket Programming: Server/Clients and Thread Usage

static void Main(string[] args)
{
Console.Title = "Socket Server";
Console.WriteLine("Listening for client messages");
Socket serverSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPAddress serverIp = IPAddress.Any;
IPEndPoint serverEP = new IPEndPoint(serverIp, 8000);
SocketPermission socketPermission = new SocketPermission(NetworkAccess.Accept,
TransportType.Tcp,
"127.0.0.1", 8000);
serverSocket.Bind(serverEP);
serverSocket.Listen(2);
while(true)
{
//Socket connection = serverSocket.Accept();
connection = serverSocket.Accept();
Thread clientThread = new Thread(new ParameterizedThreadStart(MultiUser));
clientThread.Start(connection);
}
}
public static void MultiUser(object connection)
{
byte[] serverBuffer = new byte[10025];
string message = string.Empty;
int bytes = ((Socket)connection).Receive(serverBuffer, serverBuffer.Length, 0);
message += Encoding.ASCII.GetString(serverBuffer, 0, bytes);
Console.WriteLine(message);
TcpClient client = new TcpClient();
client.Client = ((Socket)connection);
IntPtr handle = client.Client.Handle;
}
I want to write a chat program which has one server and 2 clients. The problem is that, I can not direct the message sent from the client1 to client2 via the server. How can the server distinguish threads so that it can send the received message from client1 to client2?
Each client has their own handle. You can access this via the Handle property. For example:
TcpClient client = tcpListener.AcceptTcpClient();
IntPtr handle = client.Client.Handle; //returns a handle to the connection
Then all you need to do is store this in a hashtable, and iterate through it, looking for available data. When you detect data on the wire for one of the connections, then save it and retransmit it to the other clients in the table.
Remember to make sure that you make this multithreaded so a listen request on one client does not block any send or receive functions on other clients!
I've added some code here you should be able to work with (tested it out on my system)
private void HandleClients(object newClient)
{
//check to see if we are adding a new client, or just iterating through existing clients
if (newClient != null)
{
TcpClient newTcpClient = (TcpClient)newClient;
//add this client to our list
clientList.Add(newTcpClient.Client.Handle, newTcpClient);
Console.WriteLine("Adding handle: " + newTcpClient.Client.Handle); //for debugging
}
//iterate through existing clients to see if there is any data on the wire
foreach (TcpClient tc in clientList.Values)
{
if (tc.Available > 0)
{
int dataSize = tc.Available;
Console.WriteLine("Received data from: " + tc.Client.Handle); //for debugging
string text = GetNetworkString(tc.GetStream());
//and transmit it to everyone else
foreach (TcpClient otherClient in clientList.Values)
{
if (tc.Client.Handle != otherClient.Client.Handle)
{
Send(otherClient.GetStream(), text);
}
}
}
}
}
public void Send(NetworkStream ns, string data)
{
try
{
byte[] bdata = GetBytes(data, Encoding.ASCII);
ns.Write(bdata, 0, bdata.Length);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
protected string GetNetworkString(NetworkStream ns)
{
if (ns.CanRead)
{
string receivedString;
byte[] b = GetNetworkData(ns);
receivedString = System.Text.Encoding.UTF8.GetString(b);
log.Info("Received string: " + receivedString);
return receivedString;
}
else
return null;
}
protected byte[] GetNetworkData(NetworkStream ns)
{
if (ns.CanRead)
{
log.Debug("Data detected on wire...");
byte[] b;
byte[] myReadBuffer = new byte[1024];
MemoryStream ms = new MemoryStream();
int numberOfBytesRead = 0;
// Incoming message may be larger than the buffer size.
do
{
numberOfBytesRead = ns.Read(myReadBuffer, 0, myReadBuffer.Length);
ms.Write(myReadBuffer, 0, numberOfBytesRead);
}
while (ns.DataAvailable);
//and get the full message
b = new byte[(int)ms.Length];
ms.Seek(0, SeekOrigin.Begin);
ms.Read(b, 0, (int)ms.Length);
ms.Close();
return b;
}
else
return null;
}
You will want to call HandleClients from a main thread that checks to see if there are any pending requests or not, and runs on a loop.

Client/Server both give up after 1 connection

I'm writing a client/server (as many of you probably already know!). The server is going to be sending data to the client. However, the client can connect once and after that it never attempts to connect again once the connection has been terminated. Similarly, once the server has sent it's message it will ignore future attempts to connect.
Server:
public Server(String p)
{
path = p;
listener = new TcpListener(IPAddress.Any, 1337);
listener.Start();
Thread t = new Thread(new ThreadStart(ListenForClients));
t.IsBackground = true;
t.Start();
}
private void ListenForClients()
{
TcpClient client = listener.AcceptTcpClient();
new Thread(new ParameterizedThreadStart(HandleClientCom)).Start(client);
}
private void HandleClientCom(object TcpClient)
{
new Dialog("Connection", "Connection established.");
TcpClient client = (TcpClient)TcpClient;
NetworkStream stream = client.GetStream();
//SslStream stream = new SslStream(client.GetStream());
//stream.AuthenticateAsServer(new X509Certificate(path + "\\ServerCert.cer"));
ASCIIEncoding encoder = new ASCIIEncoding();
String str = "This is a long piece of text to send to the client.";
byte[] bytes = encoder.GetBytes(str);
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
}
Client:
public TCP(BackgroundWorker b)
{
try
{
bw = b;
client = new TcpClient();
IPEndPoint server = new IPEndPoint(IPAddress.Parse(srv), 1337);
client.Connect(server); //Connect to the server
bw.ReportProgress(0); //Update the GUI with the connection status
Thread t = new Thread(new ParameterizedThreadStart(HandleComms));
t.IsBackground = true;
t.Start(client);
}
catch (Exception ex)
{
lastException = ex;
}
}
public void HandleComms(object c)
{
Boolean keepListening = true;
TcpClient client = (TcpClient)c;
NetworkStream stream = client.GetStream();
//stream = new SslStream(client.GetStream());
//stream.AuthenticateAsClient(srv);
byte[] msg = new byte[4096]; ;
int bytesRead = 0;
while (keepListening)
{
try
{
bytesRead = stream.Read(msg, 0, 4096);
}
catch (Exception ex)
{
lastException = ex;
}
if (bytesRead > 0)
{
StreamWriter writer = new StreamWriter("C:\\Users\\Chris\\Desktop\\ClientLog.txt");
ASCIIEncoding encoder = new ASCIIEncoding();
rx = encoder.GetString(msg);
writer.WriteLine(rx);
keepListening = false;
writer.Close();
}
}
}
Sorry for huge amounts of code. Can anyway point out where I've gone wrong?
Once you've accepted the connection, you'll need to begin listening again.
Try just making this change:
private void ListenForClients()
{
while(true)
{
TcpClient client = listener.AcceptTcpClient();
new Thread(new ParameterizedThreadStart(HandleClientCom)).Start(client);
}
}

Categories

Resources