Потоки в клиент-серверной программе

Для колледжа я разрабатываю локальный релейный чат. Я должен программировать сервер чата и клиент, который будет только работать над отправкой сообщений на различных окнах терминала на том же компьютере с потоками и FIFOs.

Первая часть FIFOs не испытывает затруднений, часть потоков является той, которая дает мне некоторые головные боли.

Сервер имеет один поток для получения команд от FIFO (используемый всеми клиентами) и другой поток для каждого клиента, который соединен.

Для каждого клиента, который соединен, я должен знать определенную информацию. Во-первых, я использовал глобальные переменные, которые работали longs, поскольку был только один соединенный клиент, который является большой частью чата, для обсуждения один.

Так, идеально у меня были бы некоторые данные как:

- псевдоним
имя:
- электронная почта
- и т.д...

на клиент, который соединен. Однако я не знаю, как сделать это.

Я мог создать client_data [MAX_NUMBER_OF_THREADS], где client_data был структурой со всем, к чему у меня должен был быть доступ, но это потребует к в каждой коммуникации между сервером и клиентом просить идентификатор клиента в массиве client_data, и это не кажется очень практичным

Я мог также сразу инстанцировать client_data после создания потока, но это только будет доступно в том блоке, и это не очень практично также.

Поскольку Вы видите, что я нуждаюсь в небольшом руководстве здесь. Любой комментарий, часть кода или ссылки на любую релевантную информацию значительно ценится.

5
задан Bill the Lizard 16 December 2012 в 16:03
поделиться

2 ответа

Вот некоторые псевдо-код, который на самом деле может почти запуститься. Обратите внимание: я не освобождаю то, что выделяю, я не проверяю ошибки, я просто пытаюсь продемонстрировать, как передать структуру потоку и использовать простой мьютекс.

Есть одна вещь, о которой следует позаботиться. Указатель функции для потоков указывает аргумент void * , который может быть буквально любым типом. В потоке мы предполагаем , что безопасно привести аргумент потока к типу, который мы определили для использования. Если вы передаете несколько возможных типов, вы должны быть осторожны :)

Я не совсем уверен в структуре вашей программы или в том, как вы обрабатываете потоки, но вот короткий независимый от подхода пример того, как передавать данные им:

typedef struct client {
    char *firstname;
    char *lastname;
    char *email;
    char *nickname
} client_t;


pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER;

void *client_thread(void *threadarg)
{
    client_t *client = (client_t *) threadarg;

    pthread_mutex_lock(&client_lock);
    /* read and write to client structure */
    pthread_mutex_unlock(&client_lock);

    /* do some other stuff */
    pthread_exit(NULL);
}

int main(void)
{
    client_t *client;
    pthread_t cthread;

    client = (client_t *)malloc(sizeof(struct client));
    if (client == NULL)
      return 1;

    client->firstname = strdup("Joe Public");
    /* set the rest of the data */

    pthread_create(&cthread, NULL, (void *)client_thread, (void *)client);
    /* join / detach / etc */

    /* Free all the structure members and the structure itself */

   return 0;
}

Я почти уверен, что это то, о чем вы спрашивали?

1
ответ дан 15 December 2019 в 00:52
поделиться

Я не знаю, какой язык вы используете, но вот несколько основных идей:

  • Запустите сервер в потоке (возможно, в основном потоке).
  • Серверный цикл while блокируется при принятии соединения через сокет.
  • Когда соединение с сокетом принято, он должен порождать новый поток для обработки соединения.
  • Начать общение с клиентом в новой цепочке.

Простой цикл сокет-сервера выглядит следующим образом (в Java):

while(true){
    ClientWorker w;
    try{
      //server.accept returns a client connection
      w = new ClientWorker(server.accept(), textArea);
      Thread t = new Thread(w);
      t.start();
    } catch (IOException e) {
      // log the exception or something...  
    }
  }

Если вам интересно, что он делает - ClientWorker доступен здесь . В C #, если вы создаете новый поток , не забудьте установить для его свойства IsBackground значение true , чтобы поток закрывался при завершении работы вашего приложения, т. Е. никаких свисающих ниток.

Помните: принятие соединения с сокетом или получение данных от сокета обычно является вызовом блокировки , что означает, что ваш поток будет блокироваться до тех пор, пока кто-нибудь не подключится к сокету или данные не поступят через сокет.

В C #:

  1. Клиент чата: http://www.geekpedia.com/tutorial239_Csharp-Chat-Part-1---Building-the-Chat-Client.html
  2. Чат Сервер: http://www.geekpedia.com/tutorial240_Csharp-Chat-Part-2---Building-the-Chat-Server.html
  3. Базовый клиент / сервер: http: // www.dreamincode.net / forum / topic / 33396-basic-clientserver-chat-application-in-c% 23 /

В Java:

  1. Клиент / сервер чата: http://pirate.shu.edu/~ wachsmut / Teaching / CSAS2214 / Virtual / Lectures / chat-client-server.html
  2. Клиент / сервер чата Nakov: http://inetjava.sourceforge.net/lectures/part1_sockets/InetJava-1.9-Chat-Client -Server-Example.html

В C ++

  1. В проекте кода: http://www.codeproject.com/KB/cpp/chat_client_server.aspx
  2. Другой клиент чата TCP / IP проекта кода / сервер: http://www.codeproject.com/KB/IP/ipchat.aspx

Обновление

Вместо того, чтобы делать глобальные переменные, просто определите struct для учетной записи клиента и объявить переменную учетной записи для каждого пользователя ... вот как вы можете определить информацию учетной записи:

struct account {
   char nickname[32];
   char first_name[32];
   char last_name[32];
   char e_mail[32];
   char password[32];
};

Когда клиент отправляет сообщение, оно должно иметь стандартный формат: FROM | TO | CONTENT

struct message{
   char nickname_from[32];
   char nickname_to[32]; // optional
   char msg_content[256];
};

Поместите каждый сообщение в FIFO [очереди], и у вас будет вся необходимая информация, чтобы определить, кто его отправил.

3
ответ дан 15 December 2019 в 00:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: