客户端/服务器程序中的线程

时间:2010-05-22 13:23:43

标签: c multithreading client-server

对于大学,我正在开发本地接力聊天。我必须编写一个聊天服务器和客户端,它只能在同一台带有线程和FIFO的计算机上的不同终端窗口上发送消息。

FIFO部分我没有遇到任何麻烦,线程部分是令我头疼的部分。

服务器有一个线程用于接收来自FIFO(由所有客户端使用)的命令,另一个线程用于连接的每个客户端。

对于每个连接的客户,我需要知道某些信息。首先,我使用的是全局变量,这个变量很长,因为只有一个客户端连接起来,这很像聊天,单独聊天。

所以,理想情况下我会得到一些数据:

-nickname
-name
-email
-etc ...

每个连接的客户端。但是,我不知道该怎么做。

我可以创建一个client_data [MAX_NUMBER_OF_THREADS],其中client_data是一个结构,包含我需要访问的所有内容,但是这需要在服务器和客户端之间的每次通信中请求数组client_data中的客户端的id这看起来不太实际

我也可以在创建线程后立即实例化一个client_data,但它只能在该块中使用,这也不是很实用。

如你所见,我需要一点指导。任何评论,一段代码或任何相关信息的链接都非常感谢。

2 个答案:

答案 0 :(得分:3)

我不知道你使用的语言是什么,但这里有一些基本的想法:

  • 在一个帖子中启动你的服务器(可能是你的主线程)。
  • 服务器的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可用here。在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/
  4. 在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
    3. 在C ++中

      1. 代码项目:http://www.codeproject.com/KB/cpp/chat_client_server.aspx
      2. 另一个代码项目TCP / IP聊天客户端/服务器:http://www.codeproject.com/KB/IP/ipchat.aspx
      3. 更新

        只需为客户帐户定义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 :(得分:1)

这是一些实际上几乎可以运行的伪代码。注意,我没有释放我分配的内容,我没有检查错误,我只是想演示如何将结构传递给线程并使用简单的互斥锁。

有一点需要注意,线程的函数指针指定了一个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;
}

我很确定这就是你问的问题?