0
votes

On my server side I have set up a single thread code that creates a new Socket object every time a client connects. Then I pass whatever I get from the client along with the socket that is connected to a packet handler and do the calculations there. In my main form I have a listview that I populate via entity framework, and whenever a packet from a registered computer connects I update the listview. So my question is can I from the packet handler class pass the socket object to the tag property of my listview when I update it?

My server side code:

private void ReceivedCallback(IAsyncResult result)
    {
        Socket clientSocket = result.AsyncState as Socket;
        SocketError ER;
        try
        {
            int bufferSize = clientSocket.EndReceive(result, out ER);
            if (ER == SocketError.Success)
            {
                byte[] packet = new byte[bufferSize];
                Array.Copy(_buffer, packet, packet.Length);
                Console.WriteLine("Handling packet from IP:" + clientSocket.RemoteEndPoint.ToString());
                //Handle packet stuff here.
                PacketHandler.Handle(packet, clientSocket);
                _buffer = new byte[61144];
                clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceivedCallback, clientSocket);
                //clientSocket.BeginReceive(new byte[] { 0 }, 0, 0, 0, ReceivedCallback, clientSocket);
            }
            else
            {
                Console.WriteLine("No bytes received, we're closing the connection.");
                clientSocket.Close();
            }
        }catch(SocketException ex)
        {
            Console.WriteLine("We caught a socket exception:" + ex.Message);
            clientSocket.Close();
        }
    }

And my packet handler class:

public static void Handle(byte[] packet, Socket clientSocket)
    {
        if (clientSocket.Connected)
        {
            if (packet.Length > 0)
            {
                IPEndPoint RemoteIP = (IPEndPoint)clientSocket.RemoteEndPoint;
                ushort packetLength = BitConverter.ToUInt16(packet, 0);
                ushort packetType = BitConverter.ToUInt16(packet, 2);
                ushort packetID = BitConverter.ToUInt16(packet, 4);
                Console.WriteLine("We received a packet of Type: {0}, ID: {1} FROM {2}", packetType, packetID, RemoteIP.ToString());

                if (packetType == 1)
                {
                    switch (packetID)
                    {
                        case 1://Check if computer is registered in the database
                            CheckRegisteredRequest request1 = new CheckRegisteredRequest(packet);
                            Console.WriteLine("We received (Case 1): " + request1.Text);
                            string Response = "";
                            bool found = false;
                            ServerDbContext database = new ServerDbContext();
                            foreach (computers pcs in database.computers)
                            {
                                if (pcs.name == request1.Text.Split(',')[0])
                                {
                                    found = true;
                                    if (pcs.computer_ip == request1.Text.Split(',')[1])
                                    {
                                        //We found a computer with that name and ip address
                                        Response = "true";
                                        CheckRegisteredResponse resp1 = new CheckRegisteredResponse(Response);
                                        clientSocket.Send(resp1.Data);
                                        computers registeredPC;
                                        var name = request1.Text.Split(',')[0];
                                        using (var ctx = new ServerDbContext())
                                        {
                                            registeredPC = ctx.computers.Where(c => c.name == name).FirstOrDefault<computers>();
                                        }
                                        if (registeredPC != null)
                                        {
                                            registeredPC.networkStatus = "online";
                                        }
                                        using (var ctx = new ServerDbContext())
                                        {
                                            ctx.Entry(registeredPC).State = System.Data.Entity.EntityState.Modified;
                                            ctx.SaveChanges();
                                        }
                                        addNewLog("Computer: " + request1.Text.Split(',')[0] + " came online - IP: " + request1.Text.Split(',')[1]);
                                        RaiseFeedback("PC: " + request1.Text.Split(',')[0] + " came online - IP: " + request1.Text.Split(',')[1]);
                                        break;
                                    }
                                    else
                                    {
                                        //We found a computer with that name but a different ip address, update it
                                        var name = request1.Text.Split(',')[0];
                                        var registeredPC = new computers();
                                        using (var ctx = new ServerDbContext())
                                        {
                                            registeredPC = ctx.computers.Where(c => c.name == name).FirstOrDefault<computers>();
                                        }
                                        if (registeredPC != null)
                                        {
                                            var ip = request1.Text.Split(',')[1];
                                            registeredPC.computer_ip = ip;
                                            registeredPC.networkStatus = "online";
                                        }

                                        using (var ctx = new ServerDbContext())
                                        {
                                            ctx.Entry(registeredPC).State = System.Data.Entity.EntityState.Modified;
                                            ctx.SaveChanges();
                                        }
                                        Response = "true";
                                        CheckRegisteredResponse resp1 = new CheckRegisteredResponse(Response);
                                        clientSocket.Send(resp1.Data);
                                        addNewLog("Computer: " + request1.Text.Split(',')[0] + " came online - IP: " + request1.Text.Split(',')[1]);
                                        RaiseFeedback("PC: " + request1.Text.Split(',')[0] + " came online - IP: " + request1.Text.Split(',')[1]);
                                        break;
                                    }
                                }
                            }
                            if (!found)
                            {
                                //There is no computer with that name in the database so send false
                                Response = "false";
                                CheckRegisteredResponse resp1 = new CheckRegisteredResponse(Response);
                                clientSocket.Send(resp1.Data);
                            }
                            break;... and so on....

So I've tried via a handler:

this is my custom event handler Args:

public class TextArgs : EventArgs
{
    #region Fields
    private string szMessage;
    private Socket _sockets123;
    #endregion Fields

    #region ConstructorsH
    public TextArgs(string TextMessage,Socket sock)
    {
        if (sock != null)
        {
            _sockets123 = sock;
            szMessage = TextMessage;
        }
        else
        {
            szMessage = TextMessage;
        }
    }
    #endregion Constructors

    #region Properties
    public string Message
    {
        get { return szMessage; }
        set { szMessage = value; }
    }

    public Socket _socket
    {
        get { return _sockets123; }
        set { _sockets123 = value; }
    }
    #endregion Properties
}

This is how i define that handler at the PacketHandler class: public static event LogsEventHandler Feedback;

    private static void RaiseFeedback(string p, Socket sock)
    {
        LogsEventHandler handler = Feedback;
        if (handler != null)
        {
            handler(null,new TextArgs(p,sock));
        }
    }

And whenever a computer registers or connects I do the following:

RaiseFeedback("PC: " + request1.Text.Split(',')[0] + " came online - IP: " + request1.Text.Split(',')[1], clientSocket); 

or

RaiseFeedback("PC: " + request1.Text.Split(',')[0] + " came online - IP: " + request1.Text.Split(',')[1], null);

And the event fires of these two methods in my main form:

        private void OnFeedbackReceived(object sender, TextArgs e)
    {
        Invoke((MethodInvoker)delegate
            {
                UpdateComputers();
                UpdateGUI(e.Message,e._socket);
            }
        );            
    }

    public void UpdateGUI(string s, Socket sock)
    {
        LogBox.Text += s;
        LogBox.AppendText(Environment.NewLine);
        using (var context = new ServerDbContext())
        {
            var PCInfo = context.viewUsersInfo;
            dataGridView1.DataSource = PCInfo.ToList();
        }
        if (sock != null)
        {
            ListViewItem item = ComputersList.FindItemWithText(s.Split(':')[1].ToString());
            item.Tag = sock;
        }
    }
1
Tag is object. What happend when you tried? - TaW
I've tried like this: ListViewItem item = ComputersList.FindItemWithText(s.Split(':')[1].ToString()); item.Tag = sock; But for some reason it's not working getting that object, and I am passing the object properly to it via the EventHandler. - ProToCooL
it's not working getting that object Can you explain? also show the code you use? You are casting it back to socket, right? Also: Please don't add code in comments; instead edit the question, where it will look nice and is easy to find&read.. Socket theSocket = null; if (lvi.Tag != null) theSocket = lvi.Tag as Socket; if (theSocket != null) ... - TaW
Ok I've changed the question and I've added what's going on. - ProToCooL
I see how you set the Tag but I don't see where you pull it out. Also: Is this private Socket _socekt; a typo? also: Is the set { _socket = value; } //I get a system stack overflow exception here the real problem? Obviously you can't set the property directly; usually it would be called Socket or TheSocket. The setter is an endless loop.. Replace setter and getter by automatic ones whenever you can: public Socket MySocket { get; set;}; - TaW

1 Answers

1
votes

The Question: Yes, you can. Control.Tag is of type object and can hold pretty much anything you choose.

So you can write

Socket socket = someSocket;
ListViewItem item = listView1.FindItemWithText(someText);
if (item != null) item.Tag = socket; else Console.WriteLine(someText + " not found!);

And retrieve it as:

if (item.Tag != null) someSocket = item.Tag AS socket;
if (someSocket  != null) ..

It is up to you to watch out for the success of the cast when retrieving it but also if the Socket still is alive and well..

The problem: The stackoverflow in your code is due to an erreanous, short-circuited property, which you have fixed by now. In general, you only need to write explicit getter and setters if they actually do more than just gettin and setting.

They could log out out test data, update other, dependent properties, do checks or conversiones or do other stuff.

But if none of it is needed, simply don't create the private fields and write the automatic getter and setters:

public Socket MySocket {get; set;}

Also note that the naming convention asks you to capitalize proprety names!