0

私はクライアントサーバーアプリケーションを持っています。
サーバーは、複数のクライアント接続を処理できます。

クライアントのボタンをクリックするCloseと、それが切断され、サーバー フォームのクライアントのリストから削除されることが予想されます。

ただし、無限ループに入り、クライアントがフォームの から削除され、フォームのListViewに再度追加されListViewます。

これが私のコードです:

RemoteBatcherClientForm :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;

namespace RemoteBatcherClient
{
    public partial class RemoteBatcherClientForm : Form
    {
        Socket clientSock;

        public RemoteBatcherClientForm()
        {
            InitializeComponent();
            clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        private void connectBtn_Click(object sender, EventArgs e)
        {
            clientSock.Connect("127.0.0.1", 8);
            MessageBox.Show("Connected");
        }

        private void sendBtn_Click(object sender, EventArgs e)
        {
            if (clientSock.Send(Encoding.Default.GetBytes(txtMsg.Text)) > 0)
            {
                MessageBox.Show("Data Sent");
            }
        }

        private void closeBtn_Click(object sender, EventArgs e)
        {
            clientSock.Close();
            clientSock.Dispose();
            Close();
        }
    }
}

RemoteBatcherServer :

Client.cs:

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

namespace RemoteBatcherServer
{
    class Client
    {
        public string ID
        {
            get;
            private set;
        }

        public IPEndPoint EndPoint
        {
            get;
            private set;
        }

        Socket serverSock;

        public Client(Socket accepted)
        {
            serverSock = accepted;

            ID = Guid.NewGuid().ToString();
            EndPoint = (IPEndPoint)serverSock.RemoteEndPoint;
            serverSock.BeginReceive(new byte[] { 0 }, 0, 0, 0, callback, null);
        }

        void callback(IAsyncResult ar)
        {
            try
            {
                serverSock.EndReceive(ar);

                byte[] receiveBuffer = new byte[8192];

                int rec = serverSock.Receive(receiveBuffer, receiveBuffer.Length, 0);

                if (rec < receiveBuffer.Length)
                {
                    Array.Resize<byte>(ref receiveBuffer, rec);
                }

                 if (Receieved != null)
                {
                    Receieved(this, receiveBuffer);
                }

                serverSock.BeginReceive(new byte [] {0}, 0, 0, 0, callback, null);
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
                Close();

                if (Disconnected != null)
                {
                    Disconnected(this);
                }
            }
        }

        public void Close()
        {
            serverSock.Close();
            serverSock.Dispose();
        }

        public delegate void ClientReceievedHandler(Client sender, byte[] data);
        public delegate void ClientDisconnectedHandler(Client sender);

        public event ClientReceievedHandler Receieved;
        public event ClientDisconnectedHandler Disconnected;
    }
}

Listener.cs:

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

namespace RemoteBatcherServer
{
    class Listener
    {
        Socket sck;

        public bool Listening
        {
            get;
            private set;
        }

        public int Port
        {
            get;
            private set;
        }

        public Listener(int port)
        {
            Port = port;
            sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        public void Start()
        {
            if (Listening)
                return;

            sck.Bind(new IPEndPoint(0, Port));
            sck.Listen(0);

            sck.BeginAccept(callback, null);

            Listening = true;
        }

        public void Stop()
        {
            if (!Listening)
                return;

            sck.Close();
            sck.Dispose();
            sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        void callback(IAsyncResult ar)
        {
            try
            {
                Socket acceptSocket = sck.EndAccept(ar);

                if (SockeetAccepted != null)
                {
                    SockeetAccepted(acceptSocket);
                }

                sck.BeginAccept(callback, null);
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public delegate void SocketAcceptHandler(Socket acceptSocket);
        public event SocketAcceptHandler SockeetAccepted;
    }
}

RemoteBatcherServerForm.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;

namespace RemoteBatcherServer
{
    public partial class RemoteBatcherServerForm : Form
    {
        Listener listener;

        public RemoteBatcherServerForm()
        {
            InitializeComponent();
            listener = new Listener(8);
            listener.SockeetAccepted += new Listener.SocketAcceptHandler(listenerSocketAccepted);

            Load += new EventHandler(MainLoad);
        }

        void MainLoad(object sender, EventArgs e)
        {
            listener.Start();
        }

        void listenerSocketAccepted(Socket socket)
        {
            Client client = new Client(socket);
            client.Receieved += new Client.ClientReceievedHandler(clientReceived);
            client.Disconnected += new Client.ClientDisconnectedHandler(clientDisconnected);

            Invoke((MethodInvoker)delegate
            {
                ListViewItem item = new ListViewItem();
                item.Text = client.EndPoint.ToString();
                item.SubItems.Add(client.ID);
                item.SubItems.Add("XX");
                item.SubItems.Add("XX");
                item.Tag = client;
                lstClients.Items.Add(item);
            });
        }

        void clientReceived(Client sender, byte[] data)
        {
            Invoke((MethodInvoker)delegate
            {
                for (int i = 0; i < lstClients.Items.Count; i++)
                {
                    Client client = lstClients.Items[i].Tag as Client;

                    if (client.ID == sender.ID)
                    {
                        lstClients.Items[i].SubItems[2].Text = Encoding.Default.GetString(data);
                        lstClients.Items[i].SubItems[3].Text = DateTime.Now.ToString();
                        break;
                    }
                }
            });
        }

        void clientDisconnected(Client sender)
        {
            Invoke((MethodInvoker)delegate
            {
                for (int i = 0; i < lstClients.Items.Count; i++)
                {
                    Client client = lstClients.Items[i].Tag as Client;

                    if (client.ID == sender.ID)
                    {
                        lstClients.Items.RemoveAt(i);
                        break;
                    }
                }
            });
        }       
    }
}

何か案は?

4

2 に答える 2

0

コードを誤解していない限り、同期呼び出しと非同期呼び出しを混在させているようです。serverSock.Receive 呼び出しで無期限にブロックしていると思います。参照: http://msdn.microsoft.com/en-us/library/8s4y8aff.aspx - 「読み取りに使用できるデータがない場合、タイムアウト値が設定されていない限り、Receive メソッドはデータが使用可能になるまでブロックします。 Socket.ReceiveTimeout を使用する」

serverSock.EndReceive(ar);
byte[] receiveBuffer = new byte[8192];
int rec = serverSock.Receive(receiveBuffer, receiveBuffer.Length, 0);

0 バイトを受信したかどうかを確認してください。また、BeginReceive の受信呼び出しを交換することもできます。反対側が接続を閉じたことを示す 0 バイトを受信するまで、BeginReceive を効果的に再呼び出しし続ける必要があるため、おそらく少し混乱しているように思われます。

int i = serverSock.EndReceive(ar);
if (i > 0)
    {
        serverSock.BeginReceive(receiveBuffer, 0, receiveBuffer.Length, 0, 
                                 new AsyncCallback(callback), null);
    }
else
    {
        serverSock.Close();
    }

渡す状態オブジェクトの null パラメータを交換できることに注意してください。Client コンストラクターの最初の BeginReceive 呼び出しでこれを行うことができます。これは、ある種の State クラスでラップして、バッファーを渡すためのより良い方法かもしれません。

于 2013-01-30T15:50:39.103 に答える
0

簡単な答えは次のとおりです。Client.csvoid callback(IAsyncResult ar)メソッドを変更して、Socket.Available プロパティが 0 を返すかどうかを確認します (これは、クライアントが閉じているときに発生します)。

void callback(IAsyncResult ar)
{
    try
    {
        //add these lines
        if (serverSock.Available == 0)
        {
            Disconnected(this);
            return;
        }

        serverSock.EndReceive(ar);

        byte[] receiveBuffer = new byte[8192];

        int rec = serverSock.Receive(receiveBuffer, receiveBuffer.Length, 0);

        if (rec < receiveBuffer.Length)
        {
            Array.Resize<byte>(ref receiveBuffer, rec);
        }

        if (Receieved != null)
        {
            Receieved(this, receiveBuffer);
        }

        serverSock.BeginReceive(new byte[] { 0 }, 0, 0, 0, callback, null);
    }
    catch (System.Exception ex)
    {
        Console.WriteLine(ex.Message);
        Close();

        if (Disconnected != null)
        {
            Disconnected(this);
        }
    }
}
于 2013-01-30T15:52:18.690 に答える