|
Ok I fixed it but still have a little problem:
Agent Log:
Sent notification to server that we were about to send 20230 bytes
Transferred the following actions to server: SERVICES,
Server Log:
[12/2/2010 9:48:56 AM]: -- 192.168.1.163:21064 has connected to the server
[12/2/2010 9:48:56 AM]: 192.168.1.163:21064 is about to send 20230 bytes
[12/2/2010 9:48:56 AM]: Finished receiving 8760 bytes from 192.168.1.163:21064
[12/2/2010 9:48:56 AM]: Agent 192.168.1.163:21064 sent back null
[12/2/2010 9:48:56 AM]: Finished sending 118 bytes to 192.168.1.163:21064
So as you can see the agent is sending all the data, but the server is only getting 8760 bytes? Why is the server not reading all of the data?
State Object:
public Socket worker = null;
public int BufferSize = 4;
public byte[] buffer;
public MemoryStream ms = new MemoryStream();
Server:
int bytesRead = handler.EndReceive(iar);
if (bytesRead > 0)
{
if (state.BufferSize == 4)
{
state.BufferSize = BitConverter.ToInt32(state.buffer, 0);
state.buffer = new byte[state.BufferSize];
Logging.Log(handler.RemoteEndPoint.ToString() + " is about to send " + state.BufferSize.ToString() + " bytes", true);
handler.BeginReceive(state.buffer, 0, state.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
else
{
state.ms.Write(state.buffer, 0, bytesRead);
Logging.Log("Finished receiving " + state.ms.Length.ToString() + " bytes from " +
handler.RemoteEndPoint.ToString(), true);
state.ms.Seek(0, SeekOrigin.Begin);
IFormatter formatter = new BinaryFormatter();
object receivedObject = null;
try
{
receivedObject = formatter.Deserialize(state.ms);
}
catch (SerializationException se)
{
Logging.Log("Object passed was not capable of being deserialized. Error: " + se.ToString(), false);
}
Client:
MemoryStream ms = new MemoryStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, commons);
byte[] buffer = ms.ToArray();
int len = buffer.Length;
s.Send(BitConverter.GetBytes(len));
Logging.Log("Sent notification to server that we were about to send " + len.ToString() + " bytes", true);
s.Send(buffer);
Logging.Log("Transferred the following actions to server: "+ Tasks.GetActions(), true);
ms.Dispose();
I hope I took your suggestions and something like I should have.
|
|
|
|
|
your client code seems OK; I do have a few comments on the server side:
1.
you never have shown the code that launches the first read, i.e. the BeginReceive that sits outside any callback.
2.
I suggested you first receive the length (4 bytes), then one or more large amounts of data; my pseudo-code was using the same buffer for all of these, so it had to set length to 4 initially, and to the actual buffer size later on. I don't see your code do that.
3.
you could always (temporarily) add more logging to better grasp what is going on.
4.
I suggest your first test is with a very small data set, so it fits in one receive buffer. Only when that works you should test larger amounts of data.
|
|
|
|
|
Ahhhhh ok I see what you are doing now.. but if I'm calling BeginReceive again within the Callback then I don't think that will work. Because the first thing you are doing is checking if Length == 0. There are two times this will happen... for the first BeginReceive and also when we read all the bytes (because we know we are done reading when Length == 0).
I get the idea.. unless I'm missing smoething.. changing it now
|
|
|
|
|
you kick off the receiving actions outside the callback once, then continue the process by issuing another receive inside the callback until you had enough. And length holds the amount still to be received, so once you got it all, you don't issue a new beginreceive, so the callback isn't called any more, the only time it is called with length zero is at the start of a conversation.
|
|
|
|
|
Ah yeah I got it now. Luc I just want to thank you for your help. Here is what I have now and it seems to be working well:
int bytesRead = handler.EndReceive(iar);
if (bytesRead > 0)
{
if (state.Length == 0)
{
state.Length = BitConverter.ToInt32(state.buffer, 0);
Logging.Log(handler.RemoteEndPoint.ToString() + " is about to send " + state.Length.ToString() + " bytes", true);
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
else
{
state.Length -= bytesRead;
state.ms.Write(state.buffer, 0, bytesRead);
if (state.Length > 0)
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
else
{
Logging.Log("Finished receiving " + state.ms.Length.ToString() + " bytes from " +
handler.RemoteEndPoint.ToString(), true);
state.ms.Seek(0, SeekOrigin.Begin);
IFormatter formatter = new BinaryFormatter();
object receivedObject = null;
try
{
receivedObject = formatter.Deserialize(state.ms);
|
|
|
|
|
Hi Jacob,
you're welcome. Glad you got it working reliably.
BTW: You could still reduce your code by sharing the read-more stuff, look again at my pseudo-code[^].
|
|
|
|
|
I had posted a question a while ago that asked how I could destroy an object in a windows program (the Flash player) and recreate it because there's a memory leak in the player. It's not huge but if you leave it around long enough it eventually will kill the system.
I got a response that said to put the player in a different application domain. Could somebody explain that please? I've read up on application domains and don't see how I would be able to use it.
What about putting a window in a different process and then have it display the flash. When it's done, it could close the window and kill itself. (at least I think I could do that.) Would that solve the memory leak?
TIA - Jeff.
|
|
|
|
|
why didn't you ask in the thread where you got the advice, so that person (my bet is on Pete) could get a notification e-mail and reply right away?
|
|
|
|
|
I went searching for it and couldn't find it. I am not sure if I asked it here or in the Microsoft forums.
J.
|
|
|
|
|
|
jbradshaw wrote: So if you are going to respond ...
I won't, however I will try and learn from any replies you'll get.
|
|
|
|
|
Luc Pattyn wrote: so that person (my bet is on Pete)
How did you guess?
|
|
|
|
|
I have a memory problem, and it isn't the more common one. I did remember the original thread well, and was hoping for a rather detailed reply. I think an article is in order...
|
|
|
|
|
Luc Pattyn wrote: I did remember the original thread well, and was hoping for a rather detailed reply. I think an article is in order...
OK - I get the hint. I'll see what I can do for you.
|
|
|
|
|
Thanks. I'm looking forward already.
|
|
|
|
|
I'll be looking out for it too!
|
|
|
|
|
jbradshaw wrote: What about putting a window in a different process and then have it display the flash. When it's done, it could close the window and kill itself. (at least I think I could do that.) Would that solve the memory leak?
Exactly. That was what I was talking about. Basically you'd have a sentinel application that existed purely to create these app domains which host the application.
|
|
|
|
|
Jeff - Luc's persuaded me to write an article on this (it wouldn't be the first time), so I'll pull one together and post it here on CP. Hopefully this will demonstrate what I've been suggesting.
|
|
|
|
|
Wow! I feel so special!
Thanks for all of your help.
Jeff.
|
|
|
|
|
Hi All,
We have a web application that timesout when the user is in a textbox typing. If the user moves out of the text box however, the timeout period appears to be reset. Is there a way to prevent the web application timing out (reset the timeout period) when the is typing in a textbox?
Our users access the web application using IE.
Thank you,
Mel
|
|
|
|
|
What kind of timeout? Is it a session timeout? What is your code doing when the user moves out of the textbox?
|
|
|
|
|
Yes, this is a session timeout.
There is no code that states if the user moves from one field to another, restart the timeout session time.
If I understand correctly this is the default behaviour of a session. Please correct me if I'm wrong. Any advice/help would really be appreciated.
Thank you,
Mel
|
|
|
|
|
Maybe someone knows of a way to renew the session on keystroke within a textbox?
Thanks
|
|
|
|
|
That would take a roundtrip to the server and a refresh of the page. The default session timeout for IIS is, I believe, 20 minutes.
I think a better solution would be to create a very small frame in your page that refreshes itself every 15 minutes or just short of whatever your session timeout is.
|
|
|
|
|
Dave, thank you for your reply.
Are you suggesting I put a frame in the page and then within the frame put the textbox? Would I then be able to refresh the page through the frame when a character is entered in the textbox, therefore refreshing the session on keystroke?
The reason for this is that I want the session to expire if the user has no interaction for a period of time, but if there is activity including text entered in the textbox then I want the session renewed.
Thank you,
Mel
|
|
|
|