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

时间:2011-05-21 01:28:06

标签: c# synchronization network-programming client-server token

我在C#客户端 - 服务器应用程序中传递令牌时遇到问题。你可以帮帮我吗?首先我描述一下情况,然后我粘贴一些源代码,第三,我将提供一个Visual Studio解决方案的链接。

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

问题在于我需要服务器一次将令牌传递给一个用户,因此当所有其他用户只能收听时,只有一个用户可以发送消息。令牌应按照加入服务器的顺序传递给用户10秒。

实施例: 用户A加入服务器,用户B加入服务器,用户C加入服务器。服务器将令牌传递给用户A 10秒,用户A可以写消息10秒(例如,默认情况下禁用发送按钮,服务器将令牌= true传递给客户端。如果令牌为真,则启用发送按钮10秒,然后令牌再次为假)。 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中两个解决方案的链接:http://www.speedyshare.com/files/28562696/client-server.rar

请帮助我们,这对我来说非常重要,而且我的想法已经用完了。

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

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

1 个答案:

答案 0 :(得分:0)

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

以前你想要将客户端的消息发送到服务器,然后从那里发送到所有(其他)客户端,如果你将消息作为字符串传递,它可以正常工作,没有任何其他协议...如果客户端收到了什么,你可以确定这是一个应该在聊天文本框中显示的消息字符串......

现在事情有点不同了:您必须区分要显示的消息和控制消息,这些消息会告知令牌......您需要的是某种协议......

告诉听众该消息是否包含聊天消息或控制消息的内容。

控制消息通知客户有关“嘿客户......你得到令牌......允许发送10秒......”或“你的发送许可已被撤销”等事情。

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

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