全球客户表C:聊天室

时间:2017-04-14 17:19:57

标签: c multithreading sockets tcp

我在C中创建了一个客户端/服务器聊天室。我需要在所有连接的客户端中放入一个全局表,这样我就可以将服务器收到的每条消息发送给所有连接的客户端。我无法弄清楚如何做到这一点。我假设我必须创建某种类型的结构,并为我生成的每个线程添加每个特定的套接字描述符。然后我必须将我的信息发送到该结构中的每个特定SD。

我不知道如何对此进行编码,并希望看看是否有人可以向我展示一些示例代码,说明在每次建立连接后我必须编写的内容以及我必须写入的内容然后将消息发送给每个人线。如果需要,我的服务器代码如下。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <errno.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
void *
client_session_thread(void * arg)
{
    int     SD;
    char    request[2048];
    char    message[2048] = "server receives input: ";
    int     chatfile;
    char    msgr[50000];

    SD = *(int *)arg;
    free (arg);
    pthread_detach(pthread_self());

    chatfile = open("chathistory.txt", O_RDWR|O_CREAT|O_EXCL,0666);
    close(chatfile);

    chatfile = open("chathistory.txt", O_RDWR | O_APPEND);
    read(chatfile,msgr,sizeof(msgr));
    write(SD, msgr, strlen(msgr));

    while (read(SD, request, sizeof(request)))
    {
        strcat(message, request);
        strcat(message,"\n");
        fprintf(stdout, message);
        write(SD,request,strlen(request));
        write(chatfile,request,strlen(request));
        strcpy(request,"");
        strcpy(message, "server receives input: ");
        bzero(request, sizeof(request));
        bzero(message,sizeof(message));
    }
    close(SD);
    close(chatfile);
    return 0;
}

int main(int argc, char *argv[]) 
{

//create a socket. SD is my socket. 
    struct addrinfo     addrinfo;
    struct addrinfo *   result;
    char message[256];
    int SD;
    int FD;
    pthread_t ignore;
    int * FDpntr;
    int on = 1;

    addrinfo.ai_flags = 0;
    addrinfo.ai_family = AF_INET;       // IPv4 only
    addrinfo.ai_socktype = SOCK_STREAM; // Want TCP/IP
    addrinfo.ai_protocol = 0;       // Any protocol
    addrinfo.ai_addrlen = 0;
    addrinfo.ai_addr = NULL;
    addrinfo.ai_canonname = NULL;
    addrinfo.ai_next = NULL;

    if (getaddrinfo("clamshell.rutgers.edu", "5700", &addrinfo, &result) !=0)
    {
        printf("\x1b[1;31mProblem with getaddrinfo\x1b[0m\n");  
    }
//Create socket
    SD = socket(AF_INET, SOCK_STREAM, 0);
    if (SD == -1)
    {
        printf("\x1b[1;31mProblem creating socket\x1b[0m\n");
    }
//Bind the socket to our specified IP and port
    if (setsockopt(SD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) ==-1)
    {
        printf("\x1b[1;31mProblem with sockopt\x1b[0m\n");
        freeaddrinfo(result);
    return -1;
    }
    if (bind(SD, result->ai_addr, result->ai_addrlen) != 0)
    {
        printf("\x1b[1;31mProblem binding socket\x1b[0m\n");
    }
    //first we bind our socket and then recast our address just like in client
//Listen function listens for connections
    if (listen(SD, 20) == -1)
        {
            printf("\x1b[1;31mProblem with listen\x1b[0m\n");
            close(SD);
            return 0;
        }
    else
        {
//Accept function for accepting incoming connection
        //sos = sizeof(struct sockaddr_in);
        //while (FD = accept(SD, (struct sockaddr *)&client, (socklen_t*)&sos))
        while ((FD = accept(SD,0,0)) != -1)
        {
            FDpntr = (int *)malloc(sizeof(int));
            *FDpntr = FD;
            if (pthread_create(&ignore, NULL, client_session_thread, FDpntr) != 0)
            {
                printf("\x1b[1;31mProblem creating thread\x1b[0m\n");
            }
            else
            {
                continue;
            }
        }
        close(SD);
        return 0;
    }
}

1 个答案:

答案 0 :(得分:0)

建议实施一个单独的文件。

该文件将有入口点:

initializeClientTable() 
destroyClientTable()
addClient()
deleteClient(),
getClient() 

getClient()函数将返回一个客户端。

它有一个参数(可能是枚举值),表示从ClientTable到get the first clientget the next client

在ClientTable结束时,返回此类事件的指示。

可以轻松地将ClientTable实现为链接列表。