System.Net.Sockets.OverlappedAsyncResult

Started by
8 comments, last by WozNZ 9 years, 1 month ago

im working on a project that uses asynchronous socket connection between server and clients. i use sockets for login and register of clients the big problem is i just can send data once and it will happen successfuly but after that there is a exception on server that says

failObject reference not set to an instance of an object

in my receivecallback i added a breakpoint to first line mean this:


myClient c = (myClient)ar.AsyncState;

and i find from this line c will be null. and as i see value of ar its written: System.Net.Sockets.OverlappedAsyncResult

i dont know what really this is and how can i fix this. my whole receivecallback is like bellow:



public void receiveIDCallBack(IAsyncResult ar) 
{

try
{
myClient c = (myClient)ar.AsyncState;

Socket handler = c.socket;



c.sb.Clear();
c.sb.Append(Encoding.ASCII.GetString(c.buffer));

int bytesRead = handler.EndReceive(ar);

if (bytesRead > 0)
{
c.sb.Append(Encoding.ASCII.GetString(c.buffer, 0, bytesRead));

// c.content = c.sb.ToString();

if (c.sb.ToString().IndexOf("<EOF>") > -1)
{
c.content = c.sb.ToString();
int index = c.content.IndexOf("<EOF>");
if (index > 0)
c.content = c.content.Substring(0, index);
c = JsonConvert.DeserializeObject<myClient>(c.content);
if (c.ReqData == "register")
{
try
{
if (sqlc.State==ConnectionState.Closed)
sqlc.Open();
SqlCommand registercommand = new SqlCommand("INSERT INTO [dbo].[Table](username,password,mail,displayname) VALUES(@username,@password,@mail,@displayname)", sqlc);
registercommand.Parameters.AddWithValue("@username", c.username);
registercommand.Parameters.AddWithValue("@password", c.password);
registercommand.Parameters.AddWithValue("@mail", c.mail);
registercommand.Parameters.AddWithValue("@displayname", c.displayName);
registercommand.ExecuteNonQuery();
// richTextBox1.AppendText(Environment.NewLine+"register query succees");
richTextBox1.Invoke(new MethodInvoker(delegate { richTextBox1.Text += "register succeed"; }), null);
c.buffer = Encoding.ASCII.GetBytes("register success<EOF>");

if (sqlc.State==ConnectionState.Open)
sqlc.Close();
c.ReqData = "";
}
catch (SqlException ee)
{
// string dd = ee.Message + "aaaaaa" + ee.InnerException.Message;
// richTextBox1.AppendText(Environment.NewLine + "register query fail"+ee.Message);
richTextBox1.Invoke(new MethodInvoker(delegate { richTextBox1.Text += "register failed"; }), null);
c.buffer = Encoding.ASCII.GetBytes("register fail<EOF>");
if (sqlc.State==ConnectionState.Open)
sqlc.Close();
c.ReqData = "";
}
}

if (c.ReqData == "login")
{
try
{
SqlDataReader loginreader = null;

if (sqlc.State == ConnectionState.Closed)
sqlc.Open();
SqlCommand logincommand = new SqlCommand("select * from [dbo].[Table] where username=@username", sqlc);
logincommand.Parameters.AddWithValue("@username", c.username);
loginreader = logincommand.ExecuteReader();
while (loginreader.Read())
{
string username = (string)loginreader["username"].ToString();
string password = (string)loginreader["password"].ToString();

if (c.password == loginreader["password"].ToString() && c.username == loginreader["username"].ToString())
{
richTextBox1.Invoke(new MethodInvoker(delegate { richTextBox1.Text += "login success"; }), null);
c.buffer = Encoding.ASCII.GetBytes("login success<EOF>");

// if(sqlc.State==ConnectionState.Open)
// sqlc.Close();
c.ReqData = "";
}
else
{
richTextBox1.Invoke(new MethodInvoker(delegate { richTextBox1.Text += "login fail"; }), null);
c.buffer = Encoding.ASCII.GetBytes("login fail<EOF>");

// if (sqlc.State == ConnectionState.)
// sqlc.Close();
c.ReqData = "";
}
}

}
catch (SqlException ee)
{
// string dd = ee.Message + "aaaaaa" + ee.InnerException.Message;
// richTextBox1.AppendText(Environment.NewLine + "register query fail"+ee.Message);
richTextBox1.Invoke(new MethodInvoker(delegate { richTextBox1.Text += "login failed exception"; }), null);
c.buffer = Encoding.ASCII.GetBytes("login fail exception<EOF>");
if (sqlc.State == ConnectionState.Open)
sqlc.Close();
c.ReqData = "";
}
if(sqlc.State==ConnectionState.Open)
sqlc.Close();
}
handler.BeginReceive(c.buffer, 0, c.buffer.Length, 0, new AsyncCallback(receiveIDCallBack), c.socket);

}

else
{
handler.BeginReceive(c.buffer, 0, c.buffer.Length, 0, new AsyncCallback(receiveIDCallBack), c.socket);
}
}

// handler.BeginSend(c.buffer, 0, c.buffer.Length, 0, new AsyncCallback(sendCallBack), c);
//richTextBox1.Invoke(new MethodInvoker(delegate { richTextBox1.Text =c.sb.ToString(); }), null);
//c.socket.BeginReceive(c.buffer, 0, c.buffer.Length, SocketFlags.None, new AsyncCallback(receiveIDCallBack), c);
}
catch (Exception e)
{
richTextBox1.Invoke(new MethodInvoker(delegate { richTextBox1.Text +="receive fail"+e.Message; }), null);

}
}//end of receiveIDCallBack function
Advertisement
AsyncState is equal to whatever you called BeginReceive with:


var ar = handler.BeginReceive(..., thingy);

// ar.AsyncState == thingy from here on out, and this 'ar' is the same one that is passed to your callback.
Two observations:

- You probably have a function outside this method which does the initial BeginReceive. It's probably passing null. You should pass your myClient object at that point.

- Your two calls to BeginReceive in this method are passing c.socket as the state argument, which won't be castable to your myClient type - You'll get an InvalidCastException. I'm guessing you want to pass c instead?


As far as tangential recommendations go:

If you're using C# 5.0 or newer, you should take a look at the 'async' and 'await' keywords. If not, you may want to consider Invoking to your UI thread in one operation rather than doing it several times.

I highly recommend separating your receive code from your data handling code; your function is pretty large and lots of things can go wrong, which will be hard to debug later on.

I suggest being very careful when handling received data immediately inside the async callback itself. The callback will be called on a background thread, which means if you try accessing the same data that any of your other threads use, you could experience race conditions, inconsistent state, and other fun multithreading problems.

You don't need to put the "new MethodInvoker" or "new AsyncCallback" around your delegates; All new versions of C# will do that for you now.


richTextBox1.Invoke(new MethodInvoker(delegate { richTextBox1.Text +="receive fail"+e.Message; }), null);
// can be:
richTextBox1.Invoke(delegate { richTextBox1.Text +="receive fail"+e.Message; }, null);

// and
handler.BeginReceive(c.buffer, 0, c.buffer.Length, 0, new AsyncCallback(receiveIDCallBack), c.socket);
// can be
handler.BeginReceive(c.buffer, 0, c.buffer.Length, 0, receiveIDCallBack, c.socket);

thank you @Nypyren. i would upvote your post ten times. you told many things in single post. im working on it. i will tell you the result. but i have to tell some thing. i have to say know all receiveasync functions refere to a myclient class object and i dont see any null here. next answer is certainly i have a receive function in this receive callback and all callback functions receive the result of these function. i tried to change the code with suggestion you said but it still has same problem. im still working on it. as i think you are a much more exprienced c# programmer can i send you the solution and you just take a general look and see what is the problem? thank you

I can take a quick look, but I probably won't have time for a more thorough code review.

You could post the other functions in your class here, or put them on Dropbox or some other file sharing service.

@NYPYREN thank you for answering. i rewrote the socket layer of my code and now it works very well but i dont know its right. as some friend had decompiled clash of clans game. he saw that socket is not working always. its just used for checking and sending special data at some events. now i made my code that every time creates a socket, sends data and receives servers data and after that server destroys that socket and a socket doesnt work for long term send and receive data. i dont know what you think about this way but im working on it and hope it workes good.

That's something you're free to decide on for yourself. Sometimes it makes sense to leave sockets connected, and sometimes it doesn't. Use whichever way works best for you.

Mobile games like Clash of Clans might only use connections for a short while to try to minimize battery drain and data plan consumption. Being disconnected most of the time also reduces the risk of problems if the device goes to sleep.

Hi.

Are you holding onto the data you send untill its completed, same for recieving. sounds like its gone out of scope.

@ankhd. no the topic is not out of scope. my mo game uses many diffrent scenarios. i just should test best data connection that supports them all.

Hi.
Are you holding onto the data you send untill its completed, same for recieving. sounds like its gone out of scope.


The IAsyncResult object will keep a reference to the state object in its AsyncState member. The IAsyncResult object will be referenced by the processing thread. This prevents it from being garbage collected.

The other technology to investigate for this sort of work is RX (A downloadable .NET Library) that in essence is Linq for events with all sorts of buffering, filtering etc available. Takes the pain out of async as event/message etc streams are reduced to "over time" based enumerations that push instead of pull like a normal enumerable.

I have not used in anger yet but plan to use for all the message passing in a Roguelike I am working built immutability instead of the more normal mutable grid that most use.

RX looks really clean, the code to use is concise and you get nice separation of concerns etc

This topic is closed to new replies.

Advertisement