Как работает более одного сокета в ListViewItem? - PullRequest
0 голосов
/ 06 ноября 2018

У меня есть 2 сокета на сервере и клиенте соответственно (где клиент подключается к серверу), на сервере у меня есть один класс, который содержит некоторую информацию о каждом клиенте, как IP , Сокет и ID .

Для каждого принятого соединения я добавляю последнего клиента, подключенного к этому List, таким образом, у меня есть список (то есть объект) клиентов. А также каждый клиент добавляется в один ListView, где назначается объект, относящийся к этому клиенту, в Tag свойство ListViewItem. Это один из способов, который может помочь позже, если вы хотите отправить сообщение определенному клиенту.

Как вы можете видеть, List клиентов ссылается только на 1 сокет, который прослушивает определенный номер порта. Теперь уже, когда у меня есть 2 сокета на каждой стороне (сервер и клиент), как я могу сделать, если я хочу отправить сообщение от второго Socket сервера ко второму Socket на клиенте? например, можно ли присвоить более 1 объекта Tag свойство ListViewItem (только идея)?

Ниже приведен мой код (сервер, совместимый только с 1 Socket и 1 объектом (List клиента)):

Форма:

namespace mainForm
{

public partial class frmMain : Form
{
Listener server;
Thread start;

public frmMain()
{
    InitializeComponent();
    server = new Listener();
}

private void startToolStripMenuItem_Click(object sender, EventArgs e)
{
    start = new Thread(listen);
    start.Start();
}

private void listen()
{
    server.BeginListen(101); // Select a port to listen
    server.Received += new Listener.ReceivedEventHandler(server_Received);
    server.Disconnected += new Listener.DisconnectedEventHandler(server_Disconnected);
}

private void server_Disconnected(Listener l, Info i)
{
    Invoke(new _Remove(Remove), i);
}

private void server_Received(Listener l, Info i, string received)
{

    string[] cmd = received.Split('|');
    int inc;

    for (inc = 0; inc < cmd.Length; inc++)
    {

        switch (cmd[inc].ToString())
        {
            case "CMD1":

                Invoke(new _Add(Add), i, cmd[2] + " - " + cmd[3]);

                break;

            case "CMD2":

                 // Other code here

                break;

        }
    }
}

private delegate void _Add(Info i, string computer);
    private void Add(Info i, string computer)
    {
        string[] splitIP = i.RemoteAddress.Split(':');

        ListViewItem item = new ListViewItem();
        item.Text = i.ID.ToString();
        item.SubItems.Add(splitIP[0]);
        item.SubItems.Add(computer);
        item.Tag = i;

        lvConnections.Items.Add(item);

    }

private delegate void _Remove(Info i);
    private void Remove(Info i)
    {
        foreach (ListViewItem item in lvConnections.Items)
        {
            if ((Info)item.Tag == i)
            {
                item.Remove();
                break;
            }
        }
    }

private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
{
    foreach (ListViewItem item in lvConnections.SelectedItems)
    {
        Info client = (Info)item.Tag;
        client.Send("DISCONNECT" + Environment.NewLine);
    }
}

Слушатель:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

class Listener
{
    Socket s;
    public List<Info> clients;

    public delegate void ReceivedEventHandler(Listener l, Info i, string received);
    public event ReceivedEventHandler Received;
    public delegate void DisconnectedEventHandler(Listener l, Info i);
    public event DisconnectedEventHandler Disconnected;

    bool listening = false;

    public Listener()
    {
        clients = new List<Info>();
        s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    }

    public bool Running
    {
        get { return listening; }
    }

    public void BeginListen(int port)
    {
        s.Bind(new IPEndPoint(IPAddress.Any, port));
        s.Listen(100);
        s.BeginAccept(new AsyncCallback(AcceptCallback), s);
        listening = true;
    }

    public void StopListen()
    {
        if (listening == true)
        {
            s.Close();
            listening = false;
        }
    }

    void AcceptCallback(IAsyncResult ar)
    {
        Socket handler = (Socket)ar.AsyncState;
        Socket sock = handler.EndAccept(ar);
        Info i = new Info(sock);
        clients.Add(i);

        sock.BeginReceive(i.buffer, 0, i.buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), i);
        handler.BeginAccept(new AsyncCallback(AcceptCallback), handler);
    }

    void ReadCallback(IAsyncResult ar)
    {
        Info i = (Info)ar.AsyncState;
        try
        {
            int rec = i.sock.EndReceive(ar);
            if (rec != 0)
            {
                string data = Encoding.UTF8.GetString(i.buffer, 0, rec);
                Received(this, i, data);
            }
            else
            {
                Disconnected(this, i);
                return;
            }

            i.sock.BeginReceive(i.buffer, 0, i.buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), i);
        }
        catch (Exception ex)
        {
            Disconnected(this, i);
            i.sock.Close();
            clients.Remove(i);
        }
    }
}

Информация:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

public class Info
{
    public Socket sock;
    public Guid ID;
    public string RemoteAddress;
    public byte[] buffer = new byte[8192];

    public Info(Socket sock)
    {
        this.sock = sock; 
        ID = Guid.NewGuid(); 
        RemoteAddress = sock.RemoteEndPoint.ToString(); 
    }

    public void Send(string data)
    {
        byte[] buffer = Encoding.UTF8.GetBytes(data);
        sock.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback((ar) =>
        {
            sock.EndSend(ar);
        }), buffer);
    }
}

EDITION:

Вот то, что код выше уже делает =>

enter image description here

А вот как я хочу сделать (также работать с Сокет 02 в выбранном клиенте) =>

enter image description here

...