I'm having a hard time getting something done.
I am building an mailclient using asp.net MVC 4.
I am at the point that i have to download an image related to a message ( NOT an attachment ) to the client browser.
Now i have this setup :
Client browser -> Controller/backend -> Mail server
to clarify : i have a client request containing the content ID of the image, the right mailbox, message etc. With that information i can download the image from the Mail server and upload it to the client.
Now comes the hard part: I want to do this asynchronous. I want to be able to download a chunk of 512 KB from the mailserver, decode that part, and send it to the client.. fetch - decode - send.. So long that the browser got all the data of the image.
I just dont want to first download ALL the data first to the server and then create a new memorystream with all that data and return that as a fileresult. I am just too afraid of getting too large files in my memory and block other processes etc.
I am planning to use this method too of uploading real attachments ( which could be 100's of MBs ). So i am gonna need that method later on.
Now i just have no idea how to achieve this, because i have a connection to the mail server, and i have a connection to the client. and i have to pass data to a new stream or something to get this done..
Can someone please help me?
Edit: to clarify: no i cannot refer to the file on the mail server. i HAVE to download the file to the server through sockets.
Edit2: could http chuncked be the solution? If yes, could you give me a small example?
You just need to copy data from one stream (the tcp connection to the mail server) to another (the http connection to the browser), right? If you want to scale, you'll need to use non-blocking IO as described in this article. So you'll want to call the code in that article from an IHttpAsyncHandler implementation. You'll end up with something like this:
class MyHandler : IHttpAsyncHandler
{
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
Stream src = null; // remote data source
Stream dst = context.Response.OutputStream;
// set content type, etc
var res = new MyResult();
AsynchCopy(src, dst, () =>
{
((ManualResetEvent)res.AsyncWaitHandle).Set();
cb(res);
src.Close();
dst.Flush();
});
return res;
}
public void EndProcessRequest(IAsyncResult result)
{
}
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
throw new NotImplementedException();
}
class MyResult : IAsyncResult
{
public MyResult()
{
AsyncWaitHandle = new ManualResetEvent(false);
}
public object AsyncState
{
get { return null; }
}
public WaitHandle AsyncWaitHandle
{
get;
private set;
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return AsyncWaitHandle.WaitOne(0); }
}
}
public static void AsynchCopy(Stream src, Stream dst, Action done)
{
byte[] buffer = new byte[2560];
AsyncCallback readCallback = null, writeCallback = null;
readCallback = (readResult) =>
{
int read = src.EndRead(readResult);
if (read > 0)
{
dst.BeginWrite(buffer, 0, read, writeCallback, null);
}
else
{
done();
}
};
writeCallback = (writeResult) =>
{
dst.EndWrite(writeResult);
src.BeginRead(buffer, 0, buffer.Length, readCallback, null);
};
src.BeginRead(buffer, 0, buffer.Length, readCallback, null);
}
}
The above code is untested and doesn't contain error handling, but it should get you started.
Related
So basically I want my server to raise an event (or a callback) when a connected client sends data. I can't come up with a solution to this problem and can't find anything online after days of searching.
What I've thought of was making an asynchronous foreach loop that looped through all the connected users, and check if there is any data to be read on each one (using TcpClient.Avaliable, but a network stream could also check this) but an infinite loop like this without any stop would be bad practice and use an insane amount of resources (from what I understand at least, I am new to threading and networking).
There is logic I need to be executed whenever the server gets data from a client (in this case a message, because it's a chat application), basically broadcast it to every other user, but I just can't find out how to detect if any user has sent data so that it raises an event to broadcast the message, log the message, etc...
Please be "soft" with the explanations as I am new to threading/networking and ty in advance.
As per request here is my code, take note that it is prototype-y and a bit unfinished, but I'm sure it gets the point across:
//Properties
public List<User> ConnectedUsers { get; private set; } = new List<User>();
public TcpListener listener { get; set; }
public bool IsListeningForConnections { get; set; }
public int DisconnectionCheckInterval { get; set; } //in seconds
//Events
public event EventHandler<ServerEventArgs> UserConnected;
public event EventHandler<ServerEventArgs> MessageReceived;
public NetworkManager()
{
listener = new TcpListener(IPAddress.Parse("192.168.1.86"), 6000); //binds // TODO: Change to: user input / prop file
DisconnectionCheckInterval = 10;
IsListeningForConnections = false;
}
public async void StartListeningForConnections()
{
IsListeningForConnections = true;
listener.Start();
while (IsListeningForConnections)
{
User newUser = new User();
newUser.TcpClient = await listener.AcceptTcpClientAsync();
OnUserConnected(newUser); // raises/triggers the event
}
}
public void StartListeningForDisconnections()
{
System.Timers.Timer disconnectionIntervalTimer = new System.Timers.Timer(DisconnectionCheckInterval * 1000);
//TODO: setup event
//disconnectionIntervalTimer.Elasped += ;
disconnectionIntervalTimer.AutoReset = true;
disconnectionIntervalTimer.Enabled = true;
//disconnectionIntervalTimer.Stop();
//disconnectionIntervalTimer.Dispose();
}
public async void StartListeningForData()
{
//??????????
}
public async void SendData(string data, TcpClient recipient)
{
try
{
byte[] buffer = Encoding.ASCII.GetBytes(data);
NetworkStream stream = recipient.GetStream();
await stream.WriteAsync(buffer, 0, buffer.Length); //await
Array.Clear(buffer, 0, buffer.Length);
}
catch { } //TODO: handle exception when message couldn't be sent (user disconnected)
}
public string ReceiveData(TcpClient sender)
{
try
{
NetworkStream stream = sender.GetStream();
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, buffer.Length);
return Encoding.ASCII.GetString(buffer).Trim('\0');
}
catch
{
return null; //TODO: handle exception when message couldn't be read (user disconnected)
}
}
protected virtual void OnUserConnected(User user)
{
ConnectedUsers.Add(user);
UserConnected?.Invoke(this, new ServerEventArgs() { User = user });
}
protected virtual void OnMessageReceived(User user, Message message) //needs trigger
{
MessageReceived?.Invoke(this, new ServerEventArgs() { User = user, Message = message });
}
basically a different class will call all the 3 classes that start with "StartListeningForX", then one of the 3 corresponding events are raised when one of the checks goes through (disconnection/connection/new message), and process that data, I just can't get my hands on how to call an event when a new message arrives for each user.
What I've thought of was making an asynchronous foreach loop that looped through all the connected users, and check if there is any data to be read on each one (using TcpClient.Avaliable, but a network stream could also check this) but an infinite loop like this without any stop would be bad practice and use an insane amount of resources
The standard practice is to have an "infinite" loop for each connected client, so that there is always a read going on every socket. I put "infinite" in quotes because it will actually eventually stop; either by reading 0 bytes (indicating end of stream) or by receiving an exception (indicating a broken connection).
I am new to threading/networking
It's funny how often I see developers trying to learn networking and threading at the same time. Let me be clear: threading and TCP/IP sockets are both extremely complicated and take quite a bit of time to learn all the sharp corners. Trying to learn both of these topics at once is insane. I strongly recommend choosing one of them to learn about (I'd recommend threading first), and only after that one is mastered, proceed to the other.
RabbitMQ
If you have access to the client side code, I'd consider using something like RabbitMQ, or a similar queue service. This allows to link the different apps together through a message broker or queue, and get messages/events real time.
There are functions you can call on event received.
So I'm currently learning about networking in terms of the relationship between a server and it's clients. And as far as I understand, the server starts listening for incoming connections and once a connection has been established, packets will be sent back and forth.
Here is my take on it, I like to visualize it in a way of how a game would do it.
So you have your server running and then you connect with your client, with the connection comes a Login packet, the server would then parse this packet and continue the login process and the client would eventually login to the game world.
Packets are structured in a certain way to easily keep track of what type of packet it is by using an OpCode, the length of the packet and the actual payload.
So something like this.. [OpCode(2bytes), Length(4bytes), Payload(xBytes)]
And the server would then expect this format.
Issue
What if there was a malicious user who were to send a packet that doesn't match that packet format? I would have to dump that entire packet that the malicious user sent, but I don't know how big it is so I don't know how much to dump, leaving me at a spot prone for server crashes.
Question
How do I dump/ignore a packet that doesn't have a valid OpCode.. A Valid OpCode is an OpCode that exists in the OpCode enum
enum OpCode : short
{
Connect = 0
}
The way I'm doing it now is that I start the server by initializing the packets
Packets = new Dictionary<OpCode, IPacket>();
Packets.Add(OpCode.Connect, new ConnectPacket());
and calling a method named Run
public void Run()
{
_listener = new TcpListener(IPAddress.Any, Constants.PORT);
_listener.Start(10);
_isRunning = true;
Console.WriteLine("Server has started..");
while (_isRunning)
{
_clients.Add(new Connection(_listener.AcceptTcpClient(), Packets));
}
}
When a TcpClient has been accepted, it enters the constructor
private TcpClient _socket;
private Dictionary<OpCode, IPacket> _packets;
public NetReader Reader;
public Connection(TcpClient client, Dictionary<OpCode, IPacket> packets)
{
_buffer = new byte[bufferSize];
_socket = client;
_packets = packets;
Reader = new NetReader(_socket.GetStream());
Console.WriteLine($"Client connected: {_socket.Client.RemoteEndPoint}");
ProcessPackets();
}
And as you can see I call the ProcessPackets function which checks if the first two bytes evaluates to a valid OpCode, if so, process the rest of the data that follows, if not I guess I want to dump the data and read the next packet.
Same goes for if the malicious packet somehow gets the OpCode right, if that's the case then dump the packet because the rest of the packet will probably be corrupt.
public void ProcessPackets()
{
Task.Run(() =>
{
IPacket packet;
while (true)
{
OpCode = Reader.ReadInt16();
if (_packets.TryGetValue((OpCode)OpCode, out packet))
{
_packets[(OpCode)OpCode].Process(this);
}
else
{
//Dump the packet
}
}
});
}
And here is an example of what a Process function could look like, but it doesn't matter that much since I want to solve dumping the packet if the OpCode isn't valid first.
public void Process(Connection connection)
{
var length = connection.Reader.ReadInt32();
var payload = connection.Reader.ReadBytes(length);
Console.WriteLine($"Received and processed Connection Packet");
}
NetReader is just a class that derives from BinaryReader
class NetReader : BinaryReader
{
private NetworkStream _ns;
private byte[] _tempBuffer;
public NetReader(NetworkStream ns) : base(ns)
{
_ns = ns;
_tempBuffer = new byte[8];
}
public override byte ReadByte()
{
byte val = (byte)_ns.ReadByte();
return val;
}
public override short ReadInt16()
{
int val = _ns.Read(_tempBuffer, 0, 2);
return BitConverter.ToInt16(_tempBuffer, 0)
}
public override int ReadInt32()
{
int val = _ns.Read(_tempBuffer, 0, 4);
return BitConverter.ToInt32(_tempBuffer, 0)
}
public override byte[] ReadBytes(int count)
{
byte[] bytes = new byte[count];
_ns.Read(bytes, 0, count);
return bytes;
}
}
When i send a request to my server or a reply to my client, the message i send is always divided into multiple parts.
So i need to call Receive multiple times to get to the last part/frame.
Why does this happen.. is there a better way of sending and receiving an xml encoded string?
This is the code of my client:
private void SendRequestAsyncTaskStart<T>(object contextObj, T request)
{
ZmqContext context = (ZmqContext)contextObj;
ZmqSocket requestSocket = CreateServerSocket(context);
SerializeAndSendRequest(request, requestSocket);
}
private ZmqSocket CreateServerSocket(ZmqContext context)
{
var client = context.CreateSocket(SocketType.REQ);
client.Connect(_requestReplyEndpoint);
client.Linger = TimeSpan.Zero;
client.ReceiveReady += PollInReplyHandler;
return client;
}
public static string Serialize(this object obj)
{
string result;
using (var memoryStream = new MemoryStream())
{
using (var reader = new StreamReader(memoryStream))
{
var serializer = new DataContractSerializer(obj.GetType());
serializer.WriteObject(memoryStream, obj);
memoryStream.Position = 0;
result = reader.ReadToEnd();
}
}
return result;
}
This is the code of my server:
private void ListenForRequestsThreadStart(object contextObj)
{
ZmqContext context = (ZmqContext)contextObj;
using (
ZmqSocket frontend = context.CreateSocket(SocketType.REP),
backend = context.CreateSocket(SocketType.DEALER))
{
string bindAddress = string.Format("tcp://*:{0}", _listenForRequetsPort);
frontend.Bind(bindAddress);
backend.Bind("inproc://backend");
frontend.ReceiveReady += HandleRequestReceived;
// polling
}
}
private void HandleRequestReceived(object sender, SocketEventArgs e)
{
string message;
bool hasNext;
do
{
message = socket.Receive(Encoding.ASCII);
hasNext = socket.ReceiveMore;
} while (hasNext);
// after calling Receive 3 times i get my actual message
}
Since you're sending via a socket you're at the mercy of the network. First, the network will have broken your message down in multiple packates each of which is received separately by your listener. Every now and then, the underlying socket on the listening machine will say to itself 'Got some incoming, but there's more to come. Wait a bit'. After a while it'll say, 'Oh well, give what I've got' and keep waiting'.
That's what's happening. In WCF, the WCF implementation gets its data via sockets which do exactly the same thing. But WCF waits till the whole message arrives before giving it to your waiting code. That's one of the advantages of using a Framework like WCF. It protects you from the metal.
Any message sent over TCP may be divided into several packets depending on its size. That's why you should never assume to get a message in one go, but read until you're sure you've received everything.
I'm getting a stream from HttpWebResponse.GetResponseStream() where I'm reading data from.
Now I want to implement a Timeout property. The easiest way to do it would be stream.ReadTimeout = timeout but this throws an InvalidOperationException -> Timeouts are not supported on this stream.
Given this, I'm trying to implement the timeout property myself but got stuck on a dispose. This is what I got so far:
public class MyStream : Stream {
private readonly Stream _src;
public override int ReadTimeout { get; set; }
public MyStream (Stream src, int timeout) {
ReadTimeout = timeout;
_src = src;
}
public override int Read(byte[] buffer, int offset, int count) {
var timer = new AutoResetEvent(false);
int read = 0;
ThreadPool.QueueUserWorkItem(
_ => {
read = _src.Read(buffer, offset, count);
timer.Set();
});
bool completed = timer.WaitOne(ReadTimeout);
if (completed) {
return read;
}
throw new TimeoutException(string.Format("waited {0} miliseconds", ReadTimeout));
}
The problem with this code is after is throws a TimeoutException that is being properly handled somewhere. It throws an Exception on _src.Read(buffer, offset, count) saying that the _src stream was disposed.
Is there a way to cancel the ThreadPool method or should I use a better approach and which one?
Thanks
EDIT
As asked by #JotaBe, were's the code where I get the stream from HttpWebResponse:
_httpRequest = WebRequest.CreateHttp(url);
_httpRequest.AllowReadStreamBuffering = false;
_httpRequest.BeginGetResponse(
result =>
{
try {
_httpResponse = (HttpWebResponse)_httpRequest.EndGetResponse(result);
stream = _httpResponse.GetResponseStream();
}
catch (WebException) {
downloadCompleted.Set();
Abort();
}
finally {
downloadCompleted.Set();
}
},
null);
bool completed = downloadCompleted.WaitOne(15 * 1000);
if (completed) {
return new MyStream(stream, 10000);
}
If you're trying to get a timeout if you don't receive and answer form a web server, you're trying to do it in the wrong place.
To get a Response, you usually make a Request:
HttpWebResponse response = (HttpWebResponse)request.GetResponse ();
This is the operation which can timeout. You have to call it in a differente way, using the Begin/End asynchronous pattern.
There is a full example of this in
MSDN doc for HttpWebRequest.BeginGetResponse Method
This example uses a callback function. However, there are many different ways to use Begin/End. For example, you can use a WaitHandle available in IAsyncResult like this:
IAsyncResult ar = req.BeginGetResponse(yourCallback, null);
bool completed = ar.AsyncWaitHandle.WaitOne(15000 /*your timeout in miliseconds*/);
This will wait 15 seconds. If the response arrives before this, completed will be true. If not, completed will be false. You can then use the HttpWebRequest.Abort() method to abort the request.
The Begin/End pattern takes charge of managing the neccesary threads.
I ended up using Nomad101 suggestion and surround the read with a try/catch.
I've written some code which is a mini simple imitation of messenger program.
In the program; when the user signs out, instance of my LogOutCommand class is prepared by client program, serialized, and sent to server. When the server receives the LogOutCommand, it deserializes and invokes Execute method of the class, which performs db operations, etc.
The problem is that, sometimes Server can deserialize very well, but sometimes fails.
As far as I understand, server sometimes starts deserialization before associated bytes are sent totally and accurately.
How can I make the server start deserialization in a way that it waits for all associated bytes are completed being sent?
Or do you think there is another problem?
Here is the code:
// Server listens to socket
private void ReadData(object obj)
{
Socket client = (Socket)obj;
while (true)
{
if (client.Available > 0)
{
byte[] buffer = new byte[client.Available];
client.Receive(buffer);
ServerCommandBase cmd = CommandReader.ReadSrvCommand(buffer);
cmd.Execute(context);
}
}
}
//CommandReader class
public class CommandReader
{
public static ServerCommandBase ReadSrvCommand(byte[] buffer)
{
return (ServerCommandBase)SerializationUtility.SerializationHelper.Deserialize(buffer);
}
public static ClientCommandBase ReadCliCommand(byte[] buffer)
{
return (ClientCommandBase)SerializationUtility.SerializationHelper.Deserialize(buffer);
}
}
// Serialization / Deserialization class
public class SerializationHelper
{
public static byte[] Serialize(object obj)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
try
{
formatter.Serialize(stream, obj);
}
catch (Exception)
{
MessageBox.Show("Serialize Edilemiyor");
}
stream.Position = 0;
return stream.ToArray();
}
public static object Deserialize(byte[] byteArr)
{
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream ms = new MemoryStream(byteArr);
ms.Position = 0;
object retObj = null;
try
{
retObj = formatter.Deserialize(ms);
}
catch (Exception)
{
MessageBox.Show("Cannot Be Deserialized!");
}
return retObj;
}
}
The problem as I see it is that you are attempting to deserialize data as soon as it comes down the pipe. This may or may not be possible due to how the packets are sent across the network.
You should send a header with your message that instructs how long (in bytes) the data will be. You then take in the bytes until that number has been hit and deserialize then and only then.
Your header should be of a specific format and have a specific length so that it is easy to take it off at the beginning.
First of all you shouldn't use BinaryFormatter. It's much better to use e.g. XmlSerializer.
Secondly, please include exception details that you get.