1

我正在用 C# 创建一个聊天客户端,以在 localhost 上进行演示。

以下是相关代码:

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;
    }
 }
}

现在的问题是第一个客户端可以轻松地与程序连接并发送该程序可以轻松读取的消息。但是,每个后续客户端都无法连接。

我知道我不应该创建一个 TCPListener,但问题是我必须在 localhost 上演示程序,端口号是区分客户端的唯一真正方法。

所以请告诉我代码有什么问题,我已经把头撞在墙上好几个小时了。

编辑

当英语不是第一语言时会发生这种情况:) 此代码(目前不完整)将是一个聊天客户端。此代码的每个实例都将能够与此相同代码的其他实例连接以进行通信。任意数量的实例应该能够与任意数量的实例连接(例如,如果双击程序 5 次,现在将有 5 个实例准备好相互通信)。

现在的问题是每个实例都将具有相同的 IP 地址(因为它们都在同一台机器上运行)。问题是如何说实例 1 假设连接到实例 4,此处不能使用 ip,因为实例 2,3 和 5 也将具有相同的 IP 地址。所以我想做的是用IP地址和端口连接实例1和实例4,而不是像单个TCPListener那样只使用IP地址。

4

2 回答 2

5

尝试将这三行代码移到 start_listening 例程中的 while(true) 循环之外。

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

您只需要一个侦听器,您可以从中接受许多不同的连接。

于 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
    }
}

也就是说,一旦您创建了侦听器,它就会在循环中运行,接受来自客户端的传入连接。

编辑:您遇到的问题是因为您的模拟存在缺陷。在现实世界中,每个聊天服务器都运行在一个单一的 O/S 实例中,在一个已知的端口号上。因为您自己只有一个 O/S 实例,所以您不能在该实例上运行多个聊天服务器,它们都侦听同一个端口。但是这样的事情可能会起作用,即您需要两个循环,第一个循环来创建您的侦听器,第二个内部循环让每个侦听器接受多个客户端。注意:这些循环需要退出条件!

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 回答