客户端-服务器聊天中令牌传递同步的C#问题

客户端-服务器聊天中令牌传递同步的C#问题,c#,synchronization,network-programming,client-server,token,C#,Synchronization,Network Programming,Client Server,Token,我在C#客户机-服务器应用程序中传递令牌时遇到问题。你能帮我一下吗?首先我描述了情况,其次我粘贴了一些源代码,第三我将提供一个指向VisualStudio解决方案的链接 所以情况是这样的:我创建了多线程客户机-服务器tcp聊天。一切正常,所有用户都可以一次编写消息,所有用户都可以看到一切 问题是,我需要服务器一次将令牌传递给一个用户,这样一次只有一个用户可以发送消息,而所有其他用户都只能监听。令牌应按加入服务器的顺序传递给用户10秒 例如: 用户A加入服务器,用户B加入服务器,用户C加入服务器。

我在C#客户机-服务器应用程序中传递令牌时遇到问题。你能帮我一下吗?首先我描述了情况,其次我粘贴了一些源代码,第三我将提供一个指向VisualStudio解决方案的链接

所以情况是这样的:我创建了多线程客户机-服务器tcp聊天。一切正常,所有用户都可以一次编写消息,所有用户都可以看到一切

问题是,我需要服务器一次将令牌传递给一个用户,这样一次只有一个用户可以发送消息,而所有其他用户都只能监听。令牌应按加入服务器的顺序传递给用户10秒

例如: 用户A加入服务器,用户B加入服务器,用户C加入服务器。服务器将令牌传递给用户A 10秒,用户A可以写入消息10秒(例如,发送按钮默认为禁用,服务器将令牌传递给客户端为true。如果令牌为true,发送按钮将启用10秒,然后令牌再次为false)。10秒后,服务器将令牌传递给用户B,用户B可以写消息10秒,以此类推。。如何做到这一点

以下是服务器的源代码:

namespace Serverchat
{
class Serwer
{
    public static Hashtable klienci = new Hashtable();

    static void Main(string[] args)
    {
        IPAddress IP = IPAddress.Parse("127.0.0.1");
        int port = 8888;

        TcpListener serwer = new TcpListener(IP, port);
        TcpClient gniazdo = default(TcpClient);

        serwer.Start();
        Console.WriteLine("Token passing simulation\r\nAddress: "+IP+":"+port+"\r\n");

        while (true)
        {
            gniazdo = serwer.AcceptTcpClient();
            byte[] odczyt = new byte[10024];
            string odczytsub = "";

            gniazdo.GetStream().Read(odczyt, 0, gniazdo.ReceiveBufferSize);
            odczytsub = (Encoding.ASCII.GetString(odczyt)).Substring(0, (Encoding.ASCII.GetString(odczyt)).IndexOf("~"));
            klienci.Add(odczytsub, gniazdo);
            rozglos("", odczytsub);
            Console.WriteLine(odczytsub + " joined server.");
            obslugaKlienta klient = new obslugaKlienta();
            klient.startObslugiKlienta(gniazdo, odczytsub);
        }
    }

    public static void rozglos(string wiadomosc, string nazwaUzytkownika)
    {
        foreach (DictionaryEntry klient in klienci)
        {
            TcpClient gniazdo = (TcpClient)klient.Value;
            Byte[] zapis = null;

            if (wiadomosc != "")
            {
                zapis = Encoding.ASCII.GetBytes(nazwaUzytkownika + ":" + wiadomosc + "`");
            }
            else
            {
                zapis = Encoding.ASCII.GetBytes(nazwaUzytkownika + " joined server:");
            }
            gniazdo.GetStream().Write(zapis, 0, zapis.Length);
            gniazdo.GetStream().Flush();
        }
    }
}

public class obslugaKlienta
{
    TcpClient gniazdo;
    string klient;

    public void startObslugiKlienta(TcpClient gniazdo, string klient)
    {
        this.gniazdo = gniazdo;
        this.klient = klient;
        Thread klientWatek = new Thread(komunikacja);
        klientWatek.Start();
    }

    private void komunikacja()
    {
        byte[] odczyt = new byte[10024];
        string odczytsub = "";

        while (true)
        {
            gniazdo.GetStream().Read(odczyt, 0, gniazdo.ReceiveBufferSize);
            odczytsub = Encoding.ASCII.GetString(odczyt).Substring(0, Encoding.ASCII.GetString(odczyt).IndexOf("~"));
            Console.WriteLine(klient + ": " + odczytsub);
            Serwer.rozglos(Convert.ToString(odczytsub), klient);
        }
    }
}
}
记录在案,rozglos是一个函数,它向每个人广播消息

以下是客户端的源代码:

namespace TRKlient
{
public partial class Klient : Form
{
    TcpClient gniazdo = new TcpClient();
    byte[] zapis;
    string dane = null;

    private void buttonWyslij_Click(object sender, EventArgs e) // Sending message
    {
        zapis = Encoding.ASCII.GetBytes(tbWiadomosc.Text + "~");
        gniazdo.GetStream().Write(zapis, 0, zapis.Length);
        gniazdo.GetStream().Flush();
    }

    private void buttonPolacz_Click(object sender, EventArgs e) // Connecting with server
    {
        dane = "Connected with Token Ring.";
        wyswietlWiadomosc();
        gniazdo.Connect(tbIP.Text, 8888);
        zapis = Encoding.ASCII.GetBytes(tbUser.Text + "~");
        gniazdo.GetStream().Write(zapis, 0, zapis.Length);
        gniazdo.GetStream().Flush();
        Thread klientWatek = new Thread(odbierzWiadomosc);
        klientWatek.Start();
        buttonPolacz.Enabled = false;
    }

    private void odbierzWiadomosc() // Reading data from stream
    {
        while (true)
        {
            byte[] odczyt = new byte[10024];
            gniazdo.GetStream().Read(odczyt, 0, gniazdo.ReceiveBufferSize);
            dane = Encoding.ASCII.GetString(odczyt);
            wyswietlWiadomosc();
        }
    }

    private void wyswietlWiadomosc() // Shows received messages in chat textbox
    {
        if (this.InvokeRequired)
            this.Invoke(new MethodInvoker(wyswietlWiadomosc));
        else
        tbChat.Text += "\r\n # " + dane;
    }

    public Klient() 
    {
        InitializeComponent();
    }
}
}
以下是指向Visual Studio 2010中两种解决方案的链接:

伙计们,请帮帮我,这对我很重要,我已经没有主意了

你帮了我很多次,所以提前谢谢你,彼得


编辑:客户端使用令牌发送消息可以简单到自动发送其昵称的第一个字母。一切尽可能简单,我只需要工作令牌传递。感谢您的回复。

让我们看看新旧需求之间的差异:

以前,您希望将消息从客户机发送到服务器,然后从服务器发送到所有(其他)客户机,如果您将消息作为字符串传递,而不使用任何其他协议,则可以正常工作。。。如果客户端收到某个消息,您可以确定该消息字符串应该显示在您的聊天文本框中

现在情况有点不同了:您必须区分要显示的消息和通知令牌的控制消息。。。你需要的是某种协议

告诉侦听器消息是否包含聊天消息或控制消息的内容

控制消息通知客户端“嘿,客户端……您得到了令牌……允许发送10秒……”或“您的发送权限已被撤销”等信息

根据这些消息,您可以启用/禁用客户端的发送按钮


另一方面,您还必须实现服务器部分:管理令牌并向客户端发送适当的控制消息。

谢谢您的回答,我明白您的意思。不幸的是,我仍然不知道如何在实践中做到这一点:(首先,您必须为这些消息定义一个协议。您可以定义自己的协议,或实现类似IRC协议()的内容,但IRC对于您的应用程序来说似乎有点过大。也许只需在每条聊天消息前面加上MSG,就可以使用令牌的控制消息“令牌”。只需查看第一个单词,即可将聊天信息与令牌区分开来,然后将字符串赋予相应的处理功能(聊天信息?->输出到用户/控制信息?->执行其他操作)