chatserv: Servidor de chat em C

Introdução

Recentemente verifiquei que existem problemas no script netchat que postei aqui há algum tempo. Outra coisa também é que ele utiliza o netcat padrão do slackware, a versão original do programa escrita por *Hobbit*. O Ubuntu e outras distribuições usam uma versão mais turbinada do netcat e ela não garante retrocompatibilidade com a versão usada no slackware.

Bem, pensando nisso, criei um programa em C que faz o papel do netchat: transportar mensagens para todo mundo conectado na mesma porta em um servidor. O bom é que esse programa em C tende a rodar em qualquer distribuição que tenha o gcc instalado.

Código do chatserv

Os comentários estão em inglês e foram escritos por mim a lá Joel Santana, por isso não repare muito na escrita. xD

/* charserv 1.0
 * by Daemonio (Marcos Paulo Ferreira)
 * undefinido gmail com
 *
 * chatserv
 * Handles incoming connections from (MAX_USERS)
 * users and redirect a message from an user
 * to all the others. I create this code
 * to play around on those boring classes on
 * college. Now they are more interesting.
 *
 * My first goal was to create a shell script
 * that would handle all connections using
 * netcat. I made the script but it seems that
 * every system I put my hands in has a
 * different version of nc.
 * So I code this simple server in C that will
 * run in all linux boxes with no problems,
 * and of course, to practice my select skills. :/
 *
 * How to use:
 * $ ./chatserv 2020
 *
 * Now the clients has to do:
 *
 * $ nc <server address> 2020
 *
 * To type in one terminal and see everything
 * you has received in another one:
 *
 * $ nc -lp 2021                                  (in console 1)
 * $ nc <server address> 2020 | nc localhost 2021 (in console 2)
 *
 * Now you will type your messages in console 2
 * and see what you got in console 1.
 *
 * If you a programmer you can easily create
 * a chat client that, for example, colorize
 * a message, transfer files, change nicks, etc ...
 * keep in mind that you have to create a
 * small protocol to facilitate the communication
 * between clients. (hey, isn't that the fun part??)
 *
 * Tue Oct 19 19:52:35 BRST 2010
 * Tue Oct 19 22:18:10 BRST 2010
 * Tue Oct 19 23:48:20 BRST 2010
 * Wed Oct 20 12:18:40 BRST 2010
 *
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/times.h>
#include <sys/select.h>
#include <unistd.h>

#define SERVER_BUSY "Sorry. The server is busy. bye\n"

#define MAX_USERS 20
#define MSG_LEN 4096

int socket_listening ;
/* for select() */
fd_set select_set ;

int  *list_of_sockets ;

int  max_users = MAX_USERS ;

/* grows up everytime an user
 * got a connection.
 * this variable stores the
 * current list size.*/
int  list_len = 0 ;

/* the user message */
char msg[MSG_LEN+1] ;

void show_help(char *name) {
printf("Chatserv 1.0\n") ;
printf("by Daemonio (undefinido gmail com)\n\n") ;
printf("[uso] %s <port> [<max_users>]\n", name) ;
}

/* if it's possible to insert a socket in
 * the list, this function returns 0 and
 * 1 otherwise.
 */
char insert_socket_into_list(int socket) {
    int i ;

    if ( list_len == max_users ) {
        return 1 ;
    }

    for ( i = 0; i < max_users; i++ ) {
        if ( list_of_sockets[i] == -1 ) {
            list_of_sockets[i] = socket ;
            list_len++ ;
            break ;
        }
    }
    return 0 ;
}

/* searches for a socket in the list
 * and closes it.
 */
void remove_socket_from_list(int _sock) {
    int i ;

    for ( i = 0; i < max_users; i++ ) {
        if ( list_of_sockets[i] == _sock ) {
            close(list_of_sockets[i]) ;
            list_of_sockets[i] = -1 ;
            list_len-- ;
            break ;
        }
    }
}

/* gets the message from an user.
 * this message will be in `msg'.
 * Returns 0 if the message was delivered
 * succesfully and 1 if the client
 * has finished the connection.
 */
char get_message_from_socket(int _sock) {
    int t ;

    memset(msg,0x0,MSG_LEN+1) ;
    t = recv(_sock, msg, MSG_LEN, 0 ) ;

    if ( t == 0 ) {
        remove_socket_from_list(_sock) ;
        return 1 ;
    }
    return 0 ;
}

/* after we got the message from the user,
 * we'll send it to all the others here.
 * note that an user cant send a message
 * to himself (list_of_sockets[i] != _sock).
 */
void send_message_to_all(int _sock) {
    int i ;

    for ( i = 0; i < max_users; i++ ) {
        if ( (list_of_sockets[i] != -1)    &&
             (list_of_sockets[i] != _sock) &&
             (list_of_sockets[i] != socket_listening) ) {

            send(list_of_sockets[i], msg, strlen(msg), 0) ;
        }
    }
}

int main(int argc, char **argv) {
    int port ;
    int t    ;

    struct sockaddr_in server ;
    struct timeval select_time ;

    if ( argc == 1 ) {
        show_help(argv[0]) ;
        return -1 ;
    }

    if ( argc > 2 ) {
        max_users = atoi(argv[2]) ;
    }

    port = atoi(argv[1]) ;

    socket_listening = socket(AF_INET, SOCK_STREAM, 0) ;

    if ( socket_listening < 0 ) {
        perror("socket") ;
        return -1 ;
    }

    server.sin_family = AF_INET ;
    server.sin_port = htons(port) ;
    server.sin_addr.s_addr = INADDR_ANY ;

    t = sizeof(struct sockaddr_in) ;
    if ( bind( socket_listening, (struct sockaddr *) &server, t ) < 0 ) {
        perror("bind") ;
        return -1 ;
    }

    if ( listen(socket_listening, 5) < 0 ) {
        perror("listen") ;
        return -1 ;
    }

    /* create the list of sockets.
     * for each client, there is a socket in this list.
     */
    list_of_sockets = (int *) malloc( max_users * sizeof(int) ) ;
    if ( list_of_sockets == NULL ) {
        perror("malloc") ;
        return -1 ;
    }

    /* "clean up" the list. */
    for ( t = 0; t < max_users; t++ )
        list_of_sockets[t] = -1 ;

    /* you'll need a ctrl+c to break this loop */
    while ( 1 ) {
        /* gets all the sockets and put in a
         * fd_set struct. */
        FD_ZERO(&select_set) ;
        FD_SET(socket_listening, &select_set) ;
        for ( t = 0; list_len > 0 && t < max_users; t++ ) {
            if ( list_of_sockets[t] != -1 ) {
                FD_SET(list_of_sockets[t], &select_set) ;
            }
        }

        printf("[+] Listening on %d [%d/%d] ...\n", port, list_len, max_users) ;

        /* select will wait 2 seconds before
         * returning. */
        select_time.tv_sec = 2 ;
        select_time.tv_usec = 0 ;

        /* select returns:
         * < 0 if error.
         * = 0 if nothing happened
         * > 0 number of sockets on the sets
         */
        if ( (t=select(FD_SETSIZE, &select_set, NULL, NULL, &select_time)) < 0 ) {
            perror("select") ;
            return -1 ;
        }

        /* wow, we have something ... */
        if ( t > 0 ) {
            /* if it's the listening socket, we have to
             * accept the incoming connection and add
             * the new socket in the list. */
            if ( FD_ISSET(socket_listening, &select_set) ) {
                int n ;

                if ( (n=accept(socket_listening, NULL, NULL)) < 0 ) {
                    perror("accept") ;
                } else if ( insert_socket_into_list(n) == 1 ) { /* server is busy */
                    send(n,SERVER_BUSY,strlen(SERVER_BUSY),0) ;
                    close(n) ;
                }
                continue ;
            } else {
                int i ;

                /* handle the incoming data. */
                for ( i = 0; i < max_users; i++ ) {
                    if ( FD_ISSET(list_of_sockets[i], &select_set) ) {
                        if ( get_message_from_socket(list_of_sockets[i]) == 0 ) {
                            send_message_to_all(list_of_sockets[i]) ;
                        }
                    }
                }
            }
        }
    } /* while */

    return 0 ;
} /* main */

Rodando o servidor

No caso do chat, alguém terá que rodar o servidor. Escolhido essa pessoa, ela deve compilar o chatserv:

$ gcc -o chatserv chatserv.c

Em seguida, rodar o programa. Escolha uma porta (ex: 31337) e a quantidade máxima de usuários (ex: 20):

$ ./chatserv 31337 20

O servidor está rodando. Agora só basta distribuir o IP do servidor e a porta. A porta é a 31337 como especificado, e o IP da máquina pode ser obtido pelo ifconfig:

$ ifconfig
....
eth0:
....
   inet addr: <seu ip está aqui>

….

Provavelmente aparecerá mais de uma interface, portanto mais de um ip. Geralmente o IP correto é o da interface eth0.

Os Clientes

Clientes são todos aqueles que conectarão no servidor. Mesmo se o chatserv estiver rodando em seu computador, você também terá que se conectar no servidor.

Para se conectar, digite:

$ nc <ip do servidor> 31337

O IP é aquele obtido pelo ifconfig. Se tudo estiver ok, as primeiras 20 pessoas que executarem o comando acima irão entrar no chat. De agora em diante todo mundo está ligado ao servidor e podem bater papo à vontade.

Dicas

1) Nick

O chatserv é um programa simples, pois ele só retransmite uma mensagem recebida para os outros usuários conectados nele. Logo, ele não é um programa de chat em si, pois não contém nem as funcionalidades básicas de um bate papo, como setar um nick. Usando ferramentas do linux, como o SED, podemos usar um nick no chat. Para isso, antes de se conectar no servidor, digite:

$ sed -u 's/.*/<seu nick>: &/' | nc localhost 31337

O SED deve ser chamado com a opção -u ativada (unbuffered) para que as mensagens não sejam bufferizadas antes de serem enviadas.

2) Descompartilhar terminal

Até então o mesmo terminal está sendo usado para digitar e receber as mensagens. Isso é muito ruim, pois pode acontecer de quando você estiver digitando uma mensagem, você receber outra, e tudo isso irá desvincular o que foi digitado com o restante da mensagem.

O ideal, então, é digitar as mensagens em um terminal e recebê-las em outro. Para fazer isso, só precisamos abrir dois terminais, um para compor e outro para receber as mensagens, e conectar a saída do chatserv com o terminal através de uma segunda porta.

Isto é:

  • 1) Abra dois terminais (Konsole, gnome-terminal, etc)
  • 2) No segundo, digite:
    $ nc -l 31338
  • 3) Volte para o primeiro terminal e se conecte no servidor, acrescentando agora um pipe para redirecionar as mensagens para o terminal 2:
    $ sed -u 's/.*/<nick>: &' | nc <ip servidor> | nc localhost 31338

Agora sim. As mensagens são digitadas no terminal 1 e recebidas no terminal 2.

Printscreens

Alguns print screens para você ver como que fica o esquema do chat. Na primeira foto é minha situação antes de conectar. Abri os 2 terminais e só falta estabelecer a conexão.

Chatserv antes conectar

Chatserv antes conectar

Esse screen é um exemplo de chat. No primeiro terminal é onde eu digito as mensagens. No terminal 2 eu as visualizo. Já o terminal 3, eu o abri somente para você ver como a situação completa do chat.

chatserv com o chat rolando

chatserv com o chat rolando

Conclusão

O chatserv funciona melhor do que o netchat e além disso é mais rápido, escrito em C, não usa fifos e arquivos temporários.

Então é isso.

t+

41 pensamentos sobre “chatserv: Servidor de chat em C

    • Hi alfa,

      I don’t have a client.c, instead, as mentioned in the post, I use the netcat program to connect to the server. You can code a client program calling the syscall connect to get the socket and using send/recv to control the I/O of messages. It’s not a difficult task and if you need help on it, you can post your doubts here.
      Bye.

  1. obrigado pela resposta

    eu preciso de uma aplicação de chat em c

    após algumas pesquisas na internet não consegui encontrar (só existem exemplos em java)

    encontrei o teu servidor e pensei que seria uma boa solução criar um cliente para ele e resolver parte do meu problema, pois quando tentei criar o servidor inicialmente por mim mesmo não consegui fazer com que a mensagem enviada por um cliente fosse enviada para os restantes clientes.

    através do teu servidor percebi que tinha de ser através de vários sockets

    o objecto ”base” pretendido é criar um cliente com a sintaxe:
    cliente
    ja o servidor deve ter a sintaxe:
    servidor que seria apenas juntar um if (argc !=2){ printf(servidor \n);
    e depois colocar no htons(atoi(argv[1]) e pronto

    com as seguintes regras:
    – comunicação entre clientes e servidor com ligações TCP
    – uma mensagem difundida deve sempre indicar o nome do utilizador que a criou (exemplo: maria: ”olá”)
    – o servidor deve difundir uma mensagem pelos vários clientes uma mensagem informativa sempre que um novo cliente se liga com indicação do endereço e porto do cliente
    – quando um mensagem com o conteudo ”quit” for escrita por um cliente deve ser permitido ao cliente terminar a ligação e após terminada a ligação o servidor deve informar os varios clientes desse facto.

    depois numa segunda fase tenho de criar um servidor com a sintaxe:
    servidor

    onde vou ter de ligar 2 servidores do tipo do teu com essa nova sintaxe onde já existe um servidor central para comunicar com eles com um endereço e um porto.
    o objectivo será fazer com que mensagens de clientes de um servidor A cheguem aos clientes de um servidor B e vise versa através desse servidor central.

    podes ajudar pelo menos na primeira etapa?

    vou continuar a tentar fazer o cliente que se ajuste ao teu servidor mas ai ainda será necessario fazer com que o servidor mande não só a mensagem para todos os clientes como tambem o username junto com a mensagem (username : mensagem)
    alfajeison@gmail.com

  2. a onde é que posso colocar o meu ficheiro cliente para veres o que se passa com ele para não comunicar com o teu servidor? se escrever aqui o codigo ele vai desformatar todo….

  3. ja me ajudaram, eu tenho desconhecimento de algumas coisas e por isso não consigo evoluir o cliente
    aqui esta o meu codigo cliente:
    http://pastebin.com/HqWH90qt

    o objectivo do trabalho é resolver estas 4 alineas:
    1- colocar a devolver na consola e na mesma linha o nome de utilizar e mensagem
    2- colocar o servidor a avisar cada cliente da chegado de um novo cliente indicando endereço e o porto dele tambem nessa linha
    3- colocar o cliente a terminar ligação atraves de mensagem quit
    4- colocar o servidor a informar os varios clientes da saida de um cliente do chat

    mas para tal eu teria de ter um chat clientes-servidor que já fize-se a difusão de mensagens entre vários clientes

    – abrindo o servidor num terminal e abrir várias vezes o ficheiro cliente em vários terminais

    eu penso que o teu servidor estava bom, só precisava de guardar tambem nome de utilizadores, enderecos e porto e não só as mensagens e depois fazer as devoluções das coisas conforme mandam as 4 alineas

  4. os do portugal a programar mostraram-se muito eguistas e está claro que não me vão ajudar a terminar este cliente. eu ate penso que ninguém sabe lá de facto fazer, apenas respondem com criticas e rodeios.

    fica ai o meu cliente novamente:
    http://pastebin.com/HqWH90qt

    tambem lhe deixei o meu email em cima!

    posso lhe pagar se quiser para me ensinar e terminar este chat e servidor com as 4 alineas completadas.

    abraço

  5. Olá alfa,

    o problema todo então está no servidor porque ele que irá tratar a atribuição de apelidos e entrega de mensagens. Eu modifiquei o código do chatserv para atender seus requisitos. Veja o novo código em:

    http://pastebin.com/FuJyG0p8

    Agora para se conectar faça assim:

    $ ./chatserv 31337

    em outro terminal:

    $ nc localhost 31337
    nick
    msg

    A primeira linha será seu apelido. Quando alguém se conectar, todo mundo receberá a mensagem “nick is on chat!”. Quando alguém mandar uma mensagem, todo mundo receberá: ” said: msg”.

    Só não fiz o problema do quit, mas ele segue a mesma linha de raciocínio. Entenda o código acima e depois vamos para o código do cliente, ok?

    t+

  6. voce demora sempre bastante a responder ás mensagens

    a sintaxe do servidor na consola deve ser: servidor porto
    a sintaxe do cliente na consola deve ser: cliente endereco porto nome

    então é suposto executar o ficheiro cliente várias vezes em diferentes janelas e enviar mensagens onde a mensagem leva junto o nome do cliente que foi colocado na sintaxe em cada janela de terminal que se destina a um cliente

    um cliente quando escreve a mensagem quit na consola a ligação termina (ele sai do chat)

    ai o servidor deve avisar que esse cliente saiu aos restantes clientes como também deve avisar que um cliente entrou quando este se liga ao servidor

    obrigado pela sua ajuda

    seria muito bom conseguir o cliente e o servidor

    não sabe construir um cliente? sempre utilizou o netcat como cliente?

  7. eu penso que o seu codigo servidor é demasiado complexo
    conhece alguma alternativa mais basica e simples de fazer um chat TCP que obdeça aos seguintes critérios?

    sintaxe do servidor: servidor porto
    sintaxe do cliente: cliente endereco porto nome

    1- devolver na consola e na mesma linha o nome de utilizar e mensagem
    2- colocar o servidor a avisar cada cliente da chegada de um novo cliente indicando endereço e o porto dele
    3- colocar o cliente a terminar ligação atraves de mensagem quit
    4- colocar o servidor a informar os varios clientes da saida de um cliente do chat

    • Olá,

      o chatserv segue a lógica mais simples na criação do chat. O último código que te mandei já implementa os passos 2) e 4) que você citou. O passo 3) é bem simples de acrescentar também.

      Só fica faltando o critério 1), que é a criação do cliente. Eu utilizo o netcat por ser simples e bem geral, mas criar um cliente não é nada difícil. Vi o seu código e alterei algumas coisas e testei aqui e ele está funcional. Veja:

      http://pastebin.com/2Ler5nAb

      Esse é um cliente inicial, ele ainda não está pronto, mas é o suficiente para você testar e dizer se mais ou menos isos que você quer.

      Execute-o assim:

      $ ./chatserv 31337
      $ gcc -o alfa alfa.c
      $ ./alfa localhost 31337 alfa
      > digite mensagem

      >
      ..
      etc
      ^C
      $

      Para finalizar o código, teremos que utilizar a função select() para multiplexar os dados a serem enviados e lidos.

      Por enquanto é isso. Alguma dúvida no código?

      Abraços

  8. eu testei o novo servidor e o novo cliente e ao abrir um segundo terminal com o cliente
    as mensagens não vao do cliente A para o cliente B e vise versa

    por sua vez o servidor fica a imprimir uma quantidade de listening on XXXXX [2/20]

  9. Ok,

    o novo servidor estava com um pequeno erro. Alterei também seu cliente e inseri mensagens de uso. Acesse os novos códigos agora, compile e rode:

    http://pastebin.com/0VKFKGhP (servidor)
    http://pastebin.com/wjySWQrq (cliente)

    $ ./chatserv 31337
    $ ./alfaclient localhost 31337 alfa
    ..
    ..

    agora basta você digitar as mensagens, mas você só receberá mensagens após enviar alguma.

    Podemos mudar isso usando select, mas faremos isso depois.

    Teste aí agora.
    Abraços

  10. ja tentei e ja parece existir alguma troca de mensagens
    mas aparentemente no terminal o servidor parace tratar a mensagem como o nome de utilizador, dizendo que o conteudo da mensagem está agora online e não o argv do cliente correspondente ao nome de utilizador

    executei o servidor e mais 2 clientes cada qual com o seu terminal e ao escrever quit no terminal de um cliente a ligação não fecha, o quit está ainda a ser tratado como uma mensagem qaulquer

    após a compilação dos ficheiros .c fiz assim:
    terminal 1: ./servidor 9000
    terminal 2: ./cliente localhost 9000 jose
    terminal 3: ./cliente localhost 9000 maria

    os objectivos ainda não estão todos compridos:
    1- colocar a devolver na consola e na mesma linha o nome de utilizar e mensagem
    2- colocar o servidor a avisar cada cliente da chegado de um novo cliente indicando endereço e o porto dele tambem nessa linha
    3- colocar o cliente a terminar ligação atraves de mensagem quit
    4- colocar o servidor a informar os varios clientes da saida de um cliente do chat

    espero que possa continuar a ajudar a concluir, muito obrigado pelo que já me ajudou :)

    • Ok, teste o seguinte e veja se funciona:

      terminal 1: ./servidor 9000
      terminal 2: ./cliente localhost 9000 jose
      terminal 3: ./cliente localhost 9000 maria

      1) Pressione ENTER no terminal 2. Você deve receber a mensagem “maria is now on chat!”. Logo o requisito “2” está completo.

      2) No terminal 2, envie uma mensagem

      3) No terminal 3, aperte ENTER, e você verá a mensagem de jose. Você sempre deve enviar uma mensagem ou teclar ENTER para receber uma mensagem (vamos mudar isso depois)

      4) Digite quit no terminal 3

      5) Você verá a mensagem “maria has quit.” no terminal 2. Logo os requisitos “3” e “4” estão completos.

      O requisito “1” é a sintaxe do cliente, logo ele também está completo.

      Parece que você não testou os códigos como devia. Você leu os códigos fontes? Deixei instruções lá também.

      Sim, não está tudo completo ainda, mas acho que o exigido já está funcionando.

      Confere?

  11. certo com as suas instruções correu tudo como você diz em cima
    vamos tirar o uso de ENTER certo?

    poderá comentar mais tarde o codigo servidor? principalmente coisas que digam respeito à função select?

    – qual é o próximo passo a dar agora para que as alienas fiquem todas compridas?

    em servidor coloquei o maximo de 4 utilizadores porque se forem muitos o servidor fica sempre a imprimir uma mensagem repetidamente e a ideia é a troca de mensagens entre 3 ou 4 clientes.

  12. verifiquei também que ao fazer ENTER em todos os clientes eles ficam todas em espera de mensagens e todos impossibilitados de enviar mensagens quanto uma mensagem não for recebida

    • Olá,

      veja o novo cliente em: http://pastebin.com/wjySWQrq

      Agora, basta apertar qualquer tecla para enviar uma mensagem. Assim que as mensagens dos outros usuários são recebidas, elas são mostradas na tela.

      Em relação à select aconselho você procurar material online. Essa função basicamente monitora o socket para ver se há dados nele. Assim, podemos relizar uma leitura de dados com a certeza que há dados lá, evitando que nossa aplicação trave.

      Estou aqui para demais dúvidas.

      Abraços

  13. uma gostaria de uma pequena composição sobre aquilo que você em curtas fases, (exemplo numa fase 1 fiz isto para fazer isto e depois isto…”atraves de palavras”) só para eu ter uma ideia dessa questão da necessidade de existir uma coisa para ser possivel para outra, (uma ideia global), obrigado

  14. Boa tarde amigo, ótima explicação sua, aprendi muito, tenho duas dúvidas, a primeira: O que deve ser feito caso eu queria criar um certo usuário e senha e verificar se o mesmo ja existe?
    a segunda: teria como conversar com uma determinada pessoa? como proceder caso tenha como? Aguardo sua resposta!

  15. Olá wendev,

    (verifique o código em: http://pastebin.com/0VKFKGhP)

    1) Para colocar autenticação por senha, você terá que criar uma rotina que deve ser chamada logo após o accept(). Isso é, assim que alguém se conectar no servidor, a sua rotina deve requisitar um usuário e senha. Se corretos, o usuário é logado. (obs: usuário e senha devem estar armazenados em algum lugar, por exemplo, num arquivo do servidor);

    Para verificar se o apelido já está em uso, é necessário percorrer o vetor de usuários:

    struct stclient *list_of_clients ;

    Basta percorrer cada elemento list_of_clients[i] e verificar se o apelido dado é diferente de list_of_clients[i].nick para ele ser válido.

    2) Nessa pergunta, entendi que você disse o caso em que um usuário queira conversar com outro no modo reservado. Isso pode ser feito com a criação de comandos: se o usuário digitar, por exemplo, /msg , então a mensagem irá exclusivamente para o usuário .

    Nesse caso, você terá que alterar o servidor de modo que a cada mensagem recebida você verifique se ela começa com /msg. Se sim, procure pelo socket de no vetor list_of_clients e envie a mensagem exclusivamente para ele.

    Acredito que você consiga realizar essas duas tarefas sem grandes modificações.

    Abraços

  16. Entendi perfeitamente, porém o 2) tentei de todo jeito, mas não consigo fazer com que funcione, estou aprendendo sockets recentemente, será que vc poderia me ajudar? :/

  17. Ok, wendev.

    Modifiquei o código e o coloquei em: http://pastebin.com/d7j3ERgx

    usando o comando diff dá pra você ver o que modifiquei. Basicamente, acrescentei a função send_message_to_user que envia a mensagem para um usuário específico.

    Para mandar uma mensagem privada, digite @apelido mensagem:

    exemplo:
    @wendev como esta?


    Abraços

  18. Olá Daemonio, muito agradecido pelo que foi feito, mas eu tentei rodar aqui e usando @apelido a mensagem não chega, fiz o seguinte, rodei o servidor e em seguida o cliente. Servidor rodei terminal 1: ./servidor 9000 – terminal 2: ./cliente localhost 9000 jose – terminal 3: ./cliente localhost 9000 maria. Mas ao usar no terminal 2 @maria ola tudo bem, a mensagem não chega no termial 3. Estou aqui me martelando desde as 20 hs e não acho solução, o que estou querendo fazer, vou descrever para você e peço sua ajuda, apesar de ja estar sendo chato de mais. Mas estou no panico total e peço um apoio. Estou aprendendo sockets ha menos de um mes e ja tenho esse fardo :(.
    O que estou TENTANDO fazer é:
    1) ao logar com o cliente tentar autenticar caso ja tenha user e password usando por exemplo a palavra “autenticar” seguido por wendev 12345 user e password respectivamente. Se não tiver na lista de users retornar mensagem de erro “user não existe”.
    2) inserir usuário por exemplo usar “insert” para dessa forma cadastrar user e password e verificar claro se o mesmo ja existe.

    3) enviar mensagem para todos ou para apenas um tipo: “@wendev ola tudo bem?” ou para todos “@all ola todos”
    4) sair da sessão com por exemplo “logout”

    Grato por tudo desde ja!

  19. Olá wendev,

    posso te ajudar a elaborar esse código, mas antes preciso saber qual cliente você está utilizando. É o alfaclient.c que postei aí pra cima?

    Porque se for, ele está funcionando perfeitamente aqui na minha máquina. Vamos testar com o nc:

    $./chatserv 31447 #inicia servidor
    $ nc localhost 31337
    maria # a primeira linha é sempe o apelido
    $ nc localhost 31337
    joao

    Aí no terminal do joao você escreve uma mensagem de teste:

    @maria ola maria

    No primeiro terminal deve aparecer:

    said exclusively to you: ola maria

    Faça o teste e certifique que está utilizando as novas versões dos programas.

    Abraços

    • Olá wendev,

      por enquanto notei que:

      1) o cliente só se conecta numa porta (34000) e ele só aceita IP’s como parâmetros (então no possou usar nomes como localhost). Usando o netcat consegui conectar no servidor, as threads foram iniciadas e a execução foi parar na função conversaSocket();

      2) em carrega_Arquivo() você usou scanf para ler o nome do arquivo. Em se tratando de servidor, o ideal é não ocorrer chamadas de entrada/saída. Com isso, aconselho você usar um nome de arquivo fixo, sem precisar de ler esse nome do usuário. A seguir começa a leitura do arquivo, mas pelo que notei a gravação é feita somente em uma variável. Ou seja, está acontecendo uma leitura no arquivo todo, mas os dados são sobrescritos uns em cima dos outros. Como você está usando lista encadeadas, você terá que ler/escrever cada nó separadamente, somente uma chamada à fread() e fwrite() não vai dá certo.

      3) O restante será o tratamento das mensagens enviadas/recebidas. Resolvendo 2) a gente prossegue nessa parte, ok?

      Abraços

  20. nao sei se ainda da suporte para esse codigo, gostaria de implementar a opçao de salvar historico da conversa, ate fiz o codigo por fora, mais nao consigo introduzir ele juntamente no codigo. poderia me dar uma força?

Deixe um comentário