Потоки в клиент-серверной программе - PullRequest
5 голосов
/ 22 мая 2010

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

Часть FIFO У меня нет проблем, часть потоков - это та,это вызывает у меня некоторые головные боли.

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

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

Итак, в идеале я хотел бы иметь такие данные, как:

-псевдоним
-имя
-email
-etc ...

для каждого клиентаэто связано.Тем не менее, я не знаю, как это сделать.

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

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

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

Ответы [ 2 ]

3 голосов
/ 23 мая 2010

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

  • Запустите ваш сервер в потоке (возможно, в главном потоке).
  • Цикл 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 #, если вы создаете new Thread, не забудьте установить для его свойства 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/forums/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 Chat Клиент / Сервер: 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];
};

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

1 голос
/ 24 мая 2010

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

Следует помнить одну вещь: указатель на функцию для потоков задает аргумент 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;
}

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

...