Linux下C/Socket编程中的聊天室

Linux下C/Socket编程中的聊天室,c,linux,sockets,pthreads,chat,C,Linux,Sockets,Pthreads,Chat,我有一个简单的服务器和客户端C代码,可以使用线程(pthread库)为多客户端创建聊天室。我一直遇到的问题是,我无法想办法让服务器将客户机通过套接字发送的所有消息写入所有其他客户机。我在这里读过其他类似的帖子,这是无可奈何的。请帮助我,我需要为学校做这件事。我会马上发送两个代码 服务器c: #include<stdio.h> #include<string.h> //strlen #include<stdlib.h> //strlen #inclu

我有一个简单的服务器和客户端C代码,可以使用线程(pthread库)为多客户端创建聊天室。我一直遇到的问题是,我无法想办法让服务器将客户机通过套接字发送的所有消息写入所有其他客户机。我在这里读过其他类似的帖子,这是无可奈何的。请帮助我,我需要为学校做这件事。我会马上发送两个代码

服务器c:

#include<stdio.h>
#include<string.h>    //strlen
#include<stdlib.h>    //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h>    //write

#include<pthread.h> //for threading , link with lpthread

void *connection_handler(void *);


int main(int argc , char *argv[])
{
    int socket_desc , new_socket , c , *new_sock;
    struct sockaddr_in server , client;
    char *message;

    //Create socket
    socket_desc = socket(AF_INET , SOCK_STREAM , 0);
    if (socket_desc == -1)
    {
        printf("Could not create socket");
    }

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons( 8888 );

    //Bind
    if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
    {
        puts("bind failed");
        return 1;
    }
    puts("bind done");

    //Listen
    listen(socket_desc , 3);

    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof(struct sockaddr_in);
    while( (new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
    {
        puts("Connection accepted");

        pthread_t sniffer_thread;
        new_sock = malloc(1);
        *new_sock = new_socket;

        if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
        {
            perror("could not create thread");
            return 1;
        }

        //Now join the thread , so that we dont terminate before the thread
        //pthread_join( sniffer_thread , NULL);
        puts("Handler assigned");
    }

    if (new_socket<0)
    {
        perror("accept failed");
        return 1;
    }

    return 0;
}

/*
 * This will handle connection for each client
 * */
void *connection_handler(void *socket_desc)
{
    //Get the socket descriptor
    int sock = *(int*)socket_desc;
    int read_size;
    char *message , client_message[2000];


    //Receive a message from client
    while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
    {
        //Send the message back to client
        write(sock , client_message , strlen(client_message));
    }

    if(read_size == 0)
    {
        puts("Client disconnected");
        fflush(stdout);
    }
    else if(read_size == -1)
    {
        perror("recv failed");
    }

    //Free the socket pointer
    free(socket_desc);

    return 0;
}
#包括
#包括//strlen
#包括//strlen
#包括
#包括//inet\u addr
#包括//写入
#包括//对于线程,使用lpthread链接
void*连接处理程序(void*);
int main(int argc,char*argv[])
{
int插座描述,新插座,c,*新插座;
服务器、客户端中的结构sockaddr_;
字符*消息;
//创建套接字
socket\u desc=socket(AF\u INET,SOCK\u STREAM,0);
如果(套接字描述==-1)
{
printf(“无法创建套接字”);
}
//在结构中准备sockaddr_
server.sinu family=AF\u INET;
server.sin\u addr.s\u addr=INADDR\u ANY;
server.sin_port=htons(8888);
//束缚
if(绑定(socket_desc,(struct sockaddr*)&server,sizeof(server))<0
{
看跌期权(“绑定失败”);
返回1;
}
看跌期权(“绑定完成”);
//听
听(插座描述,3);
//接受和传入连接
puts(“等待传入连接…”);
c=sizeof(结构sockaddr_in);
而((新套接字=接受(套接字描述,(结构sockaddr*)和客户端,(socklen\u t*)和c)))
{
看跌期权(“已接受连接”);
pthread\u t sniffer\u线程;
新_sock=malloc(1);
*新_插座=新_插座;
if(pthread_create(&sniffer_thread,NULL,connection_handler,(void*)new_sock)<0)
{
perror(“无法创建线程”);
返回1;
}
//现在加入线程,这样我们就不会在线程之前终止
//pthread_join(嗅探器_线程,NULL);
看跌期权(“指定的处理人”);
}
如果(新的_插座0)
{
//将消息发送回客户端
写入(sock、client_消息、strlen(client_消息));
}
如果(读取大小==0)
{
出售(“客户断开连接”);
fflush(stdout);
}
else if(读取大小==-1)
{
perror(“recv失败”);
}
//释放套接字指针
自由(插座描述);
返回0;
}
客户c

#include<stdio.h> //printf
#include<string.h>    //strlen
#include<sys/socket.h>    //socket
#include<arpa/inet.h> //inet_addr

int main(int argc , char *argv[])
{
    int sock;
    struct sockaddr_in server;
    char message[1000] , server_reply[2000];

    //Create socket
    sock = socket(AF_INET , SOCK_STREAM , 0);
    if (sock == -1)
    {
        printf("Could not create socket");
    }
    puts("Socket created");

    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_family = AF_INET;
    server.sin_port = htons( 8888 );

    //Connect to remote server
    if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
    {
        perror("connect failed. Error");
        return 1;
    }

    puts("Connected\n");
    puts("Bienvenido al Chatroom, puedes empezar a escribir en la sala!");

    //keep communicating with server
    while(1)
    {

        printf("Enter message: ");
    fgets(message, sizeof(message),stdin);
        //scanf("%s" , message);

        //Send some data
        if( send(sock , message , strlen(message) , 0) < 0)
        {
            puts("Send failed");
            return 1;
        }

        //Receive a reply from the server
        if( recv(sock , server_reply , 2000 , 0) < 0)
        {
            puts("recv failed");
            break;
        }

    printf("Server Reply: %s\n", server_reply);
    server_reply[0]='\0'; 
    }

    close(sock);
    return 0;
}
#包括//printf
#包括//strlen
#包含//套接字
#包括//inet\u addr
int main(int argc,char*argv[])
{
int袜子;
服务器中的结构sockaddr_;
字符消息[1000],服务器回复[2000];
//创建套接字
sock=socket(AF\u INET,sock\u STREAM,0);
如果(sock==-1)
{
printf(“无法创建套接字”);
}
放置(“已创建套接字”);
server.sin_addr.s_addr=inet_addr(“127.0.0.1”);
server.sinu family=AF\u INET;
server.sin_port=htons(8888);
//连接到远程服务器
if(connect(sock,(struct sockaddr*)&server,sizeof(server))<0
{
perror(“连接失败。错误”);
返回1;
}
放置(“已连接”);
puts(“Bienvenido al聊天室,puedes empezar a describir en la sala!”);
//保持与服务器的通信
而(1)
{
printf(“输入消息:”);
fgets(消息、sizeof(消息)、stdin);
//scanf(“%s”,消息);
//发送一些数据
如果(发送(sock,message,strlen(message),0)<0)
{
看跌期权(“发送失败”);
返回1;
}
//从服务器接收回复
if(recv(sock,server_reply,2000,0)<0)
{
看跌期权(“recv失败”);
打破
}
printf(“服务器回复:%s\n”,服务器回复);
服务器_回复[0]='\0';
}
关闭(袜子);
返回0;
}
这些程序非常简单,客户端发送用户在控制台中编写的内容,服务器发送相同的消息。我只需要服务器向连接的每个线程(客户机)发送相同的消息(不仅仅是发送原始消息的线程)


我知道这对任何人来说都很重要,但如果可以的话,我很乐意得到一些帮助:)

您需要一个包含所有客户端的全局表,由互斥锁保护。当新客户端连接时,将它们添加到全局客户端表中。当客户端断开连接时,将其从全局表中删除

当客户端发送消息时,获取全局表上的锁并遍历它。将消息发送到所有客户端(发送消息的客户端除外,如果您不想将消息回显到其源)


这是对真正的服务器如何做的过分简化。但这应该足以让您开始使用。

您需要使用线程吗?更简单的设计是使用select()或poll()单线程和多路I/O操作。然后,可以使用简单的for-loop完成对所有客户端套接字的写入。噢,谢谢,这可能会更容易。不过,我不知道如何使用select()或poll()哈哈。我使用线程是因为最近我学会了如何使用它们,它们似乎是解决我问题的一个很好的方法哈哈。你能给我一点关于如何使用这些函数的细节吗?:)丝线是一种强效药——除非你非常小心,否则它们会咬你。我尽量不使用它们,除非没有其他方法来完成任务。至于select(),请参见以下链接:哦,非常感谢。。我想我找到了,或者我已经很接近了!