LINUX.ORG.RU

Многопользовательский чат


1

1

Не знаю как реализовать многопользовательский чат (один сервер- много клиентов). Вся переписка чтобы велась на сервере. Помогите пожалуйста советом или если можно примерами. Заранее спасибо!

В данных примерах(листинг ниже), нормально работает если к серверу подсоеденен один клиент, при подсоединении второго сообщения от него сервером не принимаются. Как сделать, чтобы сообщения принимались от обоих клиентов одновременно

Клиент:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
extern int h_errno;
 
int main(int argC, char** argV)
{
    if(argC < 2)
    {
    printf("Enter %s port", argV[0]);
    exit(-1);
    }
    
     int port;
    if((port = atoi(argV[1])) < 0)
    {
    perror("atoi");
    //exit(-1);
    }
    
    struct hostent *gethost;
    gethost = gethostbyname("192.168.1.3");
        if(gethost==NULL)
    {
    perror("gethostbyname");
    exit(-1);
    }
    int st = socket(AF_INET,SOCK_STREAM,0);
    if (st<0)
    {
    perror("socket");
    exit(-1);
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = ((struct in_addr*)(gethost->h_addr))->s_addr;
    int cnct = connect(st,(struct sockaddr*)&addr,sizeof(addr));
    if(cnct<0)
    {
    perror("connect");
    exit(-1);
    }
    
  
    int snd; 
    //int stlen1=sizeof(addr1);
    int stlen1;
    //int st1 = accept(st,(struct sockaddr*)&addr1,&stlen1);
    char str[80];
    while(1)
    {
     gets(str);
     printf("Message: %s\n", str);
     //int from_len = sizeof(addr1);
      //s_new = accept (s, &from_sin, &from_len);
     //st1 = accept(st,(struct sockaddr*)&addr1,&stlen1);
      //(st, str,80);
     //int from_len = read (st, str, 90);
     //write (1, str, 80);
     snd=send(st, str, 80, 0);
     if(snd<0)
     {
       perror("send");
       exit(-1);
     }
     
    sleep(4);
    }
    shutdown(st,2);
    //shutdown(st1,2);
    close(st);
    //close(st1);
    //}
    exit(0);
}

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
 
int main(int argC, char** argV)
{
   if(argC < 2)
    {
    printf("Enter %s port", argV[0]);
    exit(-1);
    }
 
    int port;
    if((port = atoi(argV[1])) < 0)
    {
    perror("atoi");
    //exit(-1);
    }
    
    int st = socket(AF_INET,SOCK_STREAM,0);
    if (st<0)
    {
    perror("socket");
    exit(-1);
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(12345);
    addr.sin_addr.s_addr = INADDR_ANY;
    int bnd = bind(st,(struct sockaddr*)&addr,sizeof(addr));
    if(bnd<0)
    {
    perror("bind");
    exit(-1);
    }
    
    int lst;
    lst = listen(st,10);
    if(lst<0)
    {
      perror("listen");
    exit(-1);
    }
 
     
    
    struct sockaddr_in *addr1;
    int st1, stlen1;
    int peer_addr_size = sizeof(struct sockaddr_in);
    //st1 = accept(st,(struct sockaddr*)addr1,&stlen1);
    st1 = accept(st,(struct sockaddr*)addr1,&peer_addr_size);
    if(st1<0)
    {
      perror("st1");
      exit(-1);
    }
    int snd;
    int from_len=0;
    char str[80];
    printf("Message0: %s \n", str);
    while(1)
    {
        from_len = recv (st1, str, 80, 0);
        if(from_len<0)
        {
           perror("recv");
           exit(-1);
        }
        printf("From_len: %d\n", from_len); 
        write (1, str, 80);
        printf("Message: %s \n", str);
        snd=send (st1, str, 80, 0);  
        sleep(4);
    }
    shutdown(st,2);
    //shutdown(st1,2);
    close(st);
    //close(st1);
    exit(0);
} 

Поддерживаю направление в исходники IRC.

А вообще, такие вещи замечательно пишутся на Эрланге.

unfo ★★★★★
()
Ответ на: комментарий от unfo

А вообще, такие вещи замечательно пишутся на Эрланге.

Вот за что я люблю ЛОР: человек про С спрашивает, а ему какую-то маргинальщину предлагают.

drull ★☆☆☆
()

При подключении нового клиента выноси обработку его сообщений в новый поток, а в главном дальше дергай accept

anonymous
()
Ответ на: комментарий от no-such-file

Для

постигаю основы

ящитаю лучше использовать всё-таки epoll или select (раз уж озаботились доступностью).

Reinar
()
Ответ на: комментарий от cdshines

Я бы даже сказал, что попса :) Еще можно посоветовать node.js.

drakmail ★★★★
()
Ответ на: комментарий от cdshines

но если человек не знаком ни с протоколами, ни с клиент-серверной архитектурой, с ерланга лучше не начинать. На си он нагородит чего-то да хоть научится на ошибках — а в ерланге даже не сможет ошибку понять.

nokachi
()
Ответ на: комментарий от no-such-file

Человек постигает основы, лучше пусть поработает с epoll, чем с красивенькой обёрткой, где всё делают за тебя.

Ведь судя по всему, этот проект не ориентирован на реальное использование.

Chaser_Andrey ★★★★★
()

Тебе нужно использовать неблокирующий режим и в цикле ждать событий на группе сокетов (select, группа: сервеврный сокет, подключившихся сокеты клиентов)

vasily_pupkin ★★★★★
()
Ответ на: комментарий от Chaser_Andrey

чем с красивенькой обёрткой, где всё делают за тебя

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

no-such-file ★★★★★
()

Если задачка учебная, то самый простой способ имхо:

1) В основном потоке принимаем подключения, accept()

2) На каждое подключение создаём поток, который принимает/отправляет сообщение этому клиенту. Да, большое количество клиентов такая архитектура не потянет, но пара сотен - не проблема.

3) При получении сообщения от клиента, отправляем его остальным клиентам - хоть в цикле проходишь по подключённым клиентам и пишешь им.

roy ★★★★★
()
Последнее исправление: roy (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.