Valhalla Legends Forums Archive | .NET Platform | C# Events...

AuthorMessageTime
shout
I am trying to create an event that is triggerd by reciving a packet but it does not work.

[code]      #region Recive Packet Event Group

      protected virtual void OnRecivePacket(BnetPacketArgs e)
      {
         if (BnetSocket.Available != 0)
         {
            RecivePacket(this, e);
         }
      }

      public delegate void BnetPacketHandler(object sender, BnetPacketArgs e);

      public event BnetPacketHandler RecivePacket;

      private void bnetSocket_RecivePacket(object sender, BnetPacketArgs e)
      {
         PS.AddPacket(e.inBuffer);
      }
      #endregion
[/code]
And this is in the constructor:
[code]this.RecivePacket += new BnetPacketHandler(bnetSocket_RecivePacket);[/code]

Could someone tell me what I am doing wrong?
July 30, 2004, 5:24 PM
St0rm.iD
What's the error?

Try moving the delegate into the namespace and not the class
July 30, 2004, 8:02 PM
K
youre code as posted, should work.

one minor suggestion, though.

[code]
if (ReceivePacket != null)
ReceivePacket(this, e);
[/code]
July 30, 2004, 9:12 PM
Maddox
[quote author=K link=board=37;threadid=7969;start=0#msg73402 date=1091221958]
youre code as posted, should work.

one minor suggestion, though.

[code]
if (ReceivePacket != null)
ReceivePacket(this, e);
[/code]
[/quote]

That's more style than anything. Some people like all IF statements to have brackets to keep consistency.
July 30, 2004, 10:23 PM
K
My suggestion was not related to the style of his if statements. If no delegates are registered to ReceivePacket and you try to call it, it will crash with a System.NullReferenceException. That was my suggestion.
July 30, 2004, 10:28 PM
Myndfyr
[quote author=K link=board=37;threadid=7969;start=0#msg73407 date=1091226518]
My suggestion was not related to the style of his if statements. If no delegates are registered to ReceivePacket and you try to call it, it will crash with a System.NullReferenceException. That was my suggestion.
[/quote]

That is correct. I believe that this method is how the Microsoft best practices describe it, too.

Also, while try/catch handling is sometimes costly, if you're going to have an unknown set of untested methods hooking into events, you might want to isolate each call. My API uses a model like this:

[code]
public delegate void PacketEventHandler(byte ID, byte[] Packet);

internal event PacketEventHandler PacketReceived;

internal void OnPacketReceived(byte ID, byte[] Packet)
{
if (PacketReceived != null)
{
Delegate[] dels = PacketReceived.GetInvocationList();
object[] parms = new object[] { ID, Packet };
for (int i = 0; i < dels.Length; i++)
{
try
{
dels.DynamicInvoke(parms);
}
catch (Exception ex)
{
ErrorLog.WriteException(this, ex); // WriteException associates an exception with a specific connection manager instance.
ErrorLog.WriteDetails(this, ID, Packet); // WriteDetails adds parameter information to a logged exception.
}
}
}
}
[/code]

That prevents a faulty handler from keeping the other handlers on the invocation list.from being fired. Remember that an exception in the first called method will cause any subsequent methods from being called unless it is handled appropriately. :)
July 31, 2004, 12:30 AM
shout
I feel dumb for a couple of reasons.
1: I have managed to spell "receive" wrong every time I typed it in my code.
2: I hade the socket set to blocking.
3: I forgot to send the protocol byte.

Please kick me in the head until my noobness spills out.
July 31, 2004, 5:51 AM
K
But the code you posted was correct! ;)

Edit: Besides, I edited every single one of my posts above because I kept typing "recieve", clicking post, and then going "except after c!"
July 31, 2004, 3:31 PM
shout
I just found out I can have web pages open in VS.Net... that makes me alot happier. Please dont kick my head now.
August 3, 2004, 7:14 AM
shout
Alright. The event stuff above is basically the same except the delegate is not inside the class. When I packet log, the bot sends the two packets, but the event does not work. But this works:

[code]
      public void Sendp50()
      {
         BnetPacket p50 = new BnetPacket(0x50);
         p50.InsertDWORD(0);
         p50.InsertNonNTString("IX86");
         p50.InsertNonNTString("SEXP");
//         p50.InsertDWORD(0xC9);
//         p50.InsertNonNTString("enUS");
//         p50.InsertDWORD(180);
//         p50.InsertDWORD(0);
//         p50.InsertDWORD(0);
         byte[] bytethis = new byte[] {0xC9, 0x00, 0x00, 0x00, 0x53, 0x55, 0x6E, 0x65, 0xAC, 0x97, 0x5B, 0x48, 0x2C, 0x01, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00};
         p50.InsertBYTEArray(bytethis);
         p50.InsertNTString("USA");
         p50.InsertNTString("United States");
         socket.Send(p50.Data);
         System.Threading.Thread.Sleep(System.TimeSpan.FromMilliseconds(20000));
         byte[] b = new byte[socket.BnetSocket.Available];
         socket.BnetSocket.Receive(b);
      }
[/code]

Any less than 20000 milliseconds it does not receive the packet.

I know the byte thing is bad but at this point I don't give a flying fuck. But later I plan on fixing it.
August 3, 2004, 7:37 AM
St0rm.iD
[me=$t0rm]thinks your socket should be in blocking mode[/me]
August 3, 2004, 1:19 PM
Myndfyr
[quote author=shout link=board=37;threadid=7969;start=0#msg73849 date=1091518635]
Alright. The event stuff above is basically the same except the delegate is not inside the class. When I packet log, the bot sends the two packets, but the event does not work. But this works:

[code]
      public void Sendp50()
      {
         BnetPacket p50 = new BnetPacket(0x50);
         p50.InsertDWORD(0);
         p50.InsertNonNTString("IX86");
         p50.InsertNonNTString("SEXP");
//         p50.InsertDWORD(0xC9);
//         p50.InsertNonNTString("enUS");
//         p50.InsertDWORD(180);
//         p50.InsertDWORD(0);
//         p50.InsertDWORD(0);
         byte[] bytethis = new byte[] {0xC9, 0x00, 0x00, 0x00, 0x53, 0x55, 0x6E, 0x65, 0xAC, 0x97, 0x5B, 0x48, 0x2C, 0x01, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00};
         p50.InsertBYTEArray(bytethis);
         p50.InsertNTString("USA");
         p50.InsertNTString("United States");
         socket.Send(p50.Data);
         System.Threading.Thread.Sleep(System.TimeSpan.FromMilliseconds(20000));
         byte[] b = new byte[socket.BnetSocket.Available];
         socket.BnetSocket.Receive(b);
      }
[/code]

Any less than 20000 milliseconds it does not receive the packet.

I know the byte thing is bad but at this point I don't give a flying fuck. But later I plan on fixing it.
[/quote]

Why don't you start with Socket.BeginSend and Socket.BeginReceive like normal people, so that your socket is NOT in blocking mode, and so you don't have to poll it?

Here's the typical structure of a receiving class (note: this code is not tested and compiled for guarantees in accuracy, but I've done this so much that I'm relatively certain it's correct. Ask about design decisions if you want):

[code]
public class Connection {
public const int BUFFER_LENGTH = 512;
private Socket sock;
private EndPoint destination;
private byte[] buffer;
private AsyncCallback cb_Connected, cb_Received, cb_Sent; // delegate declarations

public event EventHandler Error;
protected virtual void OnError() {
if (Error != null)
Error(this, EventArgs.Empty);
}
public event EventHandler Connected;
protected virtual void OnConnected() {
if (Connected != null)
Connected(this, EventArgs.Empty);
}
public event EventHandler Disconnected;
protected virtual void OnDisconnected() {
if (Disconnected != null)
Disconnected(this, EventArgs.Empty);
}

public Connection(IPEndPoint dest) {
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
cb_Connected = new AsyncCallback(sock_Connected);
cb_Received = new AsyncCallback(sock_Received);
cb_Sent = new AsyncCallback(sock_Sent);
buffer = new byte[BUFFER_LENGTH];
destination = dest;
}

public void Connect() {
try {
sock.BeginConnect(
this.destination,
this.cb_Connected,
null); // MSDN recommends against using null here, but I don't think it matters
// much unless you really need another object to store state data.
} catch (SocketException se) {
OnError();
// do something with the exception, like tell the user why there was an error.
sock.Close();
OnDisconnected();
}
}

private void sock_Connected(IAsyncResult iar) {
try {
sock.EndConnect(iar);
OnConnected();
// set up receiving loop
sock.BeginReceive(
buffer,
0,
BUFFER_LENGTH,
SocketFlags.None,
cb_Received,
null); // again, MSDN recommends against using null here.
} catch (SocketException se) {
OnError();
// again, do something
sock.Close();
OnDisconnected();
}
}

private void sock_Received(IAsyncResult iar)
{
int dataLen = 0;
byte[] tempBuffer = new byte[0];
try {
dataLen = sock.EndReceive(iar);
// copy the buffer, recreate, and resume receiving.
tempBuffer = new byte[dataLen];
Array.Copy(buffer, 0, tempBuffer, 0, dataLen);
buffer = new byte[BUFFER_LENGTH];
sock.BeginReceive(
buffer,
0,
BUFFER_LENGTH,
SocketFlags.None,
cb_Received,
null);
} catch (SocketException ex) {
OnError();
// be informative
sock.Close();
OnDisconnected();
}
// work with data in tempBuffer here.
}

public void Send(byte[] data) {
try {
sock.BeginSend(
data,
0,
data.Length,
SocketFlags.None,
cb_Sent,
null);
} catch (SocketException se) {
OnError();
// yeah yeah
sock.Close();
OnDisconnected();
}
}

private void sock_Sent(IAsyncResult iar) {
try {
sock.EndSend(iar);
} catch (SocketException se) {
OnError();
// you know the drill
sock.Close();
OnDisconnected();
}
}
}
[/code]

That will effectively work in asynchronous mode. If you decompile my OpenConnectionManager class, you'll find that I have this set up doubly, one for BNLS, one for Bnet. I also have structure there for UDP, but it's not used at this time.

By the way, last I checked, System.Threading.Thread.Sleep took an integral parameter of milliseconds, so there's no reason to do TimeSpan.FromMilliseconds() in your code. :P
August 3, 2004, 5:41 PM
Myndfyr
I know you're thinking what a great guy I am for giving you this framework, so I'll just beat you to the punch and say that you're welcome.
August 4, 2004, 7:12 AM
shout
For the BeginConnect and EndConnect and related, would this not work?

[code]
public void Connect()
{
socket.BeginConnect(endPoint, new AsyncCallback(ConnectCallback), null);
}

private void ConnectCallback(IAsyncResult ar)
{
socket.EndConnect(ar);
}
[/code]

Also, if a socket had a BeginReceive call before the last one was complete, would that cause it to crash?
August 6, 2004, 5:38 AM
Myndfyr
[quote author=shout link=board=37;threadid=7969;start=0#msg74289 date=1091770707]
For the BeginConnect and EndConnect and related, would this not work?

[code]
public void Connect()
{
socket.BeginConnect(endPoint, new AsyncCallback(ConnectCallback), null);
}

private void ConnectCallback(IAsyncResult ar)
{
socket.EndConnect(ar);
}
[/code]

Also, if a socket had a BeginReceive call before the last one was complete, would that cause it to crash?
[/quote]

Sure, they'd work. However, you'd need to deal with Exceptions that can arise elsewhere in your code (specifically, where you call Connect). Note that if you have an Exception at EndConnect, since it's a callback, the Exception will bubble up to the top-level event handler, which will (if you're using Forms) will display an ugly "Unhandled Exception" dialog, or will cause a Console App to stop.
August 6, 2004, 8:10 PM
shout
Every time I connect, while receiving the 2nd packet, I get the error "An established connection was aborted by the software in your host machine" from the BeginReceive call.

I cant really figure out what the problem is... :(

By the way Myndfyre, this also happend with your socket class.

Im so glad Microsoft comes up with such detailed error messages. How do they do it?
August 6, 2004, 10:41 PM

Search