#c# #synchronization #network-programming #client-server #token
#c# #синхронизация #сетевое программирование #клиент-сервер #токен
Вопрос:
У меня проблема с передачей токенов в клиент-серверном приложении C #. Не могли бы вы помочь мне с этим, пожалуйста? Во-первых, я описываю ситуацию, во-вторых, вставляю некоторый исходный код, в-третьих, я дам ссылку на решения Visual studio.
Итак, ситуация такая: я создал многопоточный 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 simulationrnAddress: " IP ":" port "rn");
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 = "rn # " dane;
}
public Klient()
{
InitializeComponent();
}
}
}
Вот ссылка на оба решения в Visual Studio 2010: http://www.speedyshare.com/files/28562696/client-server.rar
Пожалуйста, помогите мне, ребята, это очень важно для меня, и у меня закончились идеи.
Ты помогал мне много раз, так что заранее спасибо, Питер.
РЕДАКТИРОВАТЬ: Отправка сообщения клиентом с токеном может быть такой же простой, как автоматическая отправка первой буквы его псевдонима. Все может быть максимально простым, мне нужна только передача рабочего токена. Спасибо за ваши ответы.
Ответ №1:
давайте посмотрим на различия между старыми и новыми требованиями:
ранее вы хотели отправлять сообщения с клиента на сервер, а оттуда всем (другим) клиентам, что отлично работает, если вы передаете сообщение в виде строки, без какого-либо другого протокола… если клиент что-то получает, вы можете быть уверены, что это строка сообщения, которая должна отображаться в текстовом поле вашего чата…
теперь все немного по-другому: вы должны различать сообщения, которые должны отображаться, и управляющие сообщения, которые информируют о токене … для этого вам нужен какой-то протокол…
что-то, что сообщает слушателю, содержит ли сообщение сообщение чата или управляющее сообщение.
управляющие сообщения информируют клиента о таких вещах, как «привет, клиент… вы получили токен… отправка разрешена в течение 10 секунд …», или «ваше разрешение на отправку отозвано» и т.д.
на основе этих сообщений вы можете включить / отключить кнопку отправки вашего клиента…
с другой стороны, вам также придется реализовать серверную часть: управлять токеном и отправлять соответствующие управляющие сообщения клиентам.
Комментарии:
1. Спасибо за ваш ответ, я понял вашу точку зрения. К сожалению, я до сих пор не знаю, как это сделать на практике: (
2. сначала вам нужно будет определить протокол для этих сообщений. вы можете определить свой собственный или реализовать что-то вроде протокола IRC ( faqs.org/rfcs/rfc1459.html ) но IRC кажется немного перегруженным для вашего приложения. возможно, просто добавляйте к каждому сообщению чата сообщение MSG, а управляющими сообщениями для токена могут быть «ТОКЕН <время в секундах>». вы можете отличить сообщение чата от токена, просто взглянув на первое слово, а затем передать строку соответствующей функции обработки (chat-message? -> вывод пользователю / управляющему сообщению? -> сделай что-нибудь еще)