1

ローカルホストでデモを行うために、C# でチャット クライアントを作成しています。

関連するコードは次のとおりです。

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.Sockets;
using System.Net;
using System.IO;
using System.Threading;

namespace WindowsFormsApplication1
{
 public partial class Form1 : Form
 {
    static List<TcpListener> garabage_collection_preventor = new List<TcpListener>();
    static Dictionary<IPEndPoint, bool> address_dictionary = new Dictionary<IPEndPoint, bool>();
    static int port_increment = 9999;
    static int client_id = 0;

    void start_listening()
    {
        while (true)
        {
            TcpListener listen = new TcpListener(IPAddress.Any, port_increment);
            garabage_collection_preventor.Add(listen);
            listen.Start();
            TcpClient client = listen.AcceptTcpClient();
            IPEndPoint temp_end = ((IPEndPoint)listen.LocalEndpoint);
            address_dictionary.Add(temp_end, false);
            port_increment++;
            new Thread(new ParameterizedThreadStart(connection_stuff)).Start(client);
        }
    }

    void writer(object ob,int end_point)
    {
        StreamWriter write = ob as StreamWriter;
        while (true)
        {
            foreach (KeyValuePair<IPEndPoint, bool> value in address_dictionary)
            {
                IPEndPoint index = value.Key;
                int temp = value.Key.Port;
                if (temp == end_point)
                {
                    while (address_dictionary[index] == true)
                    {
                        write.WriteLine(msg_box.Text);
                    }
                }
            }
        }
    }

    void reader(StreamReader read)
    {
        while (true)
        {
            MessageBox.Show(read.ReadLine());
        }
    }

    void connection_stuff(object ob)
    {
        TcpClient client = ob as TcpClient;
        int writer_identification_endpoint = ((IPEndPoint)client.Client.LocalEndPoint).Port;

        NetworkStream stream = client.GetStream();
        StreamReader read = new StreamReader(stream);
        StreamWriter write = new StreamWriter(stream);

        ThreadStart port_passing = delegate { writer(write, writer_identification_endpoint); };
        Thread thread = new Thread(port_passing);

        reader(read);
        thread.Start();
    }

    public Form1()
    {
        InitializeComponent();
    }

    private void send_Click(object sender, EventArgs e)
    {
        int end_point = int.Parse(port.Text);
        foreach (KeyValuePair<IPEndPoint, bool> value in address_dictionary)
        {
            IPEndPoint index = value.Key;
            int temp = value.Key.Port;
            if (temp == end_point)
            {
                address_dictionary[index] = true;
            }
        }
    }

    private void listener_Click(object sender, EventArgs e)
    {
        new Thread(start_listening).Start();
        listener.Enabled = false;
    }
 }
}

ここでの問題は、最初のクライアントがプログラムに簡単に接続して、このプログラムが簡単に読み取れるメッセージを送信できることです。ただし、後続のすべてのクライアントは接続できません。

私は 1 つ以上の TCPListener を作成するべきではないことを知っていますが、問題は、ローカルホストでプログラムを実証する必要があり、ポート番号がクライアントを区別する唯一の真の方法であることです。

ですから、私が何時間も壁に頭をぶつけてきたコードの何が問題なのか教えてください。

編集

これは、英語が第一言語でない場合に起こることです:) このコード(現在は完全ではありません)はチャットクライアントになります。このコードの各インスタンスは、この同じコードの他のインスタンスと接続して通信できます。任意の数のインスタンスが任意の数のインスタンスと接続できる必要があります (たとえば、プログラムを 5 回ダブルクリックすると、5 つのインスタンスが相互に通信できるようになります)。

ここでの問題は、すべてのインスタンスが同じ IP アドレスを持つことです (それらはすべて同じマシンで実行されているため)。インスタンス 1 がインスタンス 4 に接続すると仮定すると、インスタンス 2、3、および 5 も同じ IP アドレスを持つため、ここでは ip を使用できません。したがって、私がやろうとしているのは、単一の TCPListener の場合のように IP アドレスだけを使用するのではなく、インスタンス 1 とインスタンス 4 を IP アドレスと PORT で接続することです。

4

2 に答える 2

5

これらの 3 行のコードを、start_listening ルーチンの while(true) ループの外に移動してみてください。

TcpListener listen = new TcpListener(IPAddress.Any, port_increment);
garabage_collection_preventor.Add(listen);
listen.Start();

必要なリスナーは 1 つだけで、そこからさまざまな接続を受け入れることができます。

于 2012-11-20T15:26:47.727 に答える
0

次のようにしてみてください。

void start_listening()
{
    TcpListener listen = new TcpListener(IPAddress.Any, port_increment);
    garabage_collection_preventor.Add(listen);
    listen.Start();
    while (true)
    {
        TcpClient client = listen.AcceptTcpClient();
        // etc
    }
}

つまり、リスナーを作成すると、クライアントからの着信接続を受け入れるループで実行されます。

編集:あなたが抱えている問題は、シミュレーションに欠陥があるためです。現実の世界では、各チャット サーバーは、1 つの既知のポート番号で、1 つの O/S インスタンスで実行されます。自分の O/S インスタンスは 1 つしかないため、そのインスタンスで複数のチャット サーバーを実行して、すべて同じポートでリッスンすることはできません。しかし、このようなものはうまくいくかもしれません。つまり、2 つのループが必要です。最初のループはリスナーを作成するためのもので、2 つ目の内部ループは各リスナーが複数のクライアントを受け入れるためのものです。注: これらのループには終了条件が必要です。

void start_listening()
{
    while (true)
    {
        TcpListener listen = new TcpListener(IPAddress.Any, port_increment);
        garabage_collection_preventor.Add(listen);
        listen.Start();
        while (true)
        {
            TcpClient client = listen.AcceptTcpClient();
            IPEndPoint temp_end = ((IPEndPoint)listen.LocalEndpoint);
            address_dictionary.Add(temp_end, false);
            new Thread(new ParameterizedThreadStart(connection_stuff)).Start(client);
        }
        port_increment++;
    }
}
于 2012-11-20T15:27:15.820 に答える