2014-10-28 3 views
1

Прежде всего, это домашнее задание, поэтому, пожалуйста, никаких прямых ответов. Я пишу чат-программу с обратной связью в C. Я очень новичок в C (только начал учиться для этого класса). На данный момент у меня есть три файла:Программа чата в C

server.c

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <stdlib.h> 
#include <strings.h> 
#include <string.h> 
#include "chat.h" 

#define SERVER_PORT 1725 
#define MAX_PENDING 5 
#define MAX_LINE 256 

int main() 
{ 
    struct sockaddr_in sin; 
    char buf[MAX_LINE]; 
    int len; 
    int s, new_s; 
    struct chat_packet packet; 

    /* build address data structure */ 
    bzero((char *)&sin, sizeof(sin)); 
    sin.sin_family = AF_INET; 
    sin.sin_addr.s_addr = INADDR_ANY; 
    sin.sin_port = htons(SERVER_PORT); 

    /* setup passive open */ 
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) 
    { 
     perror("simplex-talk: socket"); 
     exit(1); 
    } 
    if ((bind(s, (struct sockaddr *)&sin, sizeof(sin))) < 0) 
    { 
     perror("simplex-talk: bind"); 
     exit(1); 
    } 
    listen(s, MAX_PENDING); 

    /* wait for connection, then receive and print text */ 
    while(1) 
    { 
     if ((new_s = accept(s, (struct sockaddr *)&sin, &len)) < 0) 
     { 
      perror("simplex-talk: accept"); 
      exit(1); 
     } 

     /* Stay in the following loop until CTRL+C */ 
     while (len = recv(new_s, &packet, sizeof(packet), 0)) 
     { 
      fputs(packet.sender_name, stdout); 
      fputs(": ", stdout); 
      fputs(packet.data, stdout); 
      fputs("\nYou: ", stdout); 

      while (fgets(buf, sizeof(buf), stdin)) 
      { 
       if(strlen(buf) > 144) 
       { 
        printf("Your message is too long. Please enter a new message.\n"); 
        continue;         
       } 

       else 
       { 
        buf[MAX_LINE-1] = '\0'; 

        strncpy(packet.data,buf,144); 
        char sender[8] = "Mason"; /*should be argv[index of name]*/ 
        strncpy(packet.sender_name, sender, 8); 

        send(new_s, &packet, sizeof(packet),0); 
       } 
      } 
     } 

     close(new_s); 
    } 
} 

client.c

#include <stdio.h> 
#include <stdlib.h> 
#include <strings.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include "chat.h" 

#define SERVER_PORT 1725 
#define MAX_LINE 256 

int main(int argc, char * argv[]) 
{ 
    FILE *fp; 
    struct hostent *hp; 
    struct sockaddr_in sin; 
    char *host; 
    char buf[MAX_LINE]; 
    int s; 
    int len; 
    struct chat_packet packet; 

    if (argc==2) 
    { 
     host = argv[1]; 
    } 
    else 
    { 
     fprintf(stderr, "usage: simplex-talk host\n"); 
     exit(1); 
    } 

    /* translate host name into peer's IP address */ 
    hp = gethostbyname(host); 
    if (!hp) { 
     fprintf(stderr, "simplex-talk: unknown host: %s\n", host); 
     exit(1); 
    } 
    /* build address data structure */ 
    bzero((char *)&sin, sizeof(sin)); 
    sin.sin_family = AF_INET; 
    bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 
    sin.sin_port = htons(SERVER_PORT); 
    /* active open */ 
    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) 
    { 
     perror("simplex-talk: socket"); 
     exit(1); 
    } 
    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) 
    { 
     perror("simplex-talk: connect"); 
     close(s); 
     exit(1); 
    } 
    /* main loop: get and send lines of text */ 
    while (fgets(buf, sizeof(buf), stdin)) 
    { 
     if(strlen(buf) > 144) 
     { 
      printf("Your message is too long. Please enter a new message.\n"); 
      continue;         /*This allows the user to re-enter a message post-error*/ 
     } 
     else 
     { 
      buf[MAX_LINE-1] = '\0'; 

      strncpy(packet.data, buf, 144); 
      char sender[8] = "Abby"; /*should be argv[index of name]*/ 
      strncpy(packet.sender_name, sender, 8); 

      send(s, &packet, sizeof(packet), 0);  
      recv(s, &packet, sizeof(packet),0); 

      fputs(packet.sender_name, stdout); 
      fputs(": ", stdout); 
      fputs(packet.data, stdout); 
      fputs("\nYou: ", stdout); 
     } 
    } 
} 

chat.h

#include <stdint.h> /* Needed for unsigned types */ 

#define MAX_DATA_LEN 144 /* So we are on 16-bit boundary */ 
#define USER_NAME_LEN 8 

/* You must send this packet across the socket. Notice there are 
* no pointers inside this packet. Why?*/ 
struct chat_packet { 
    u_short version; /* 16 bits -- Set to version 2 in code */ 
    char sender_name[8]; /* 64 bits */ 
    char data[MAX_DATA_LEN]; /* Message goes in here */ 
}; 

Все, кроме того, что в клиентской и серверной время петли были даны мне моим инструктором. Базовая часть задания получает функциональность чата и обратно. Я запускаю все в PuTTY, используя командную строку. Я дублирую сеанс и запускаю клиент на одном и сервере в другом. Для запуска:

./client имя_сервера

./server

Я могу пойти туда и обратно один раз, а затем ничего не отправляет или получает. Я все еще могу печатать, но две сессии не могут видеть сообщения друг друга за первым назад и вперед. Я не уверен, где мой код ошибочен. Любые советы будут оценены, так как я очень новичок в этом языке. Заранее спасибо!

+2

<< Во-первых, это домашнее задание, поэтому, пожалуйста, не прямые ответы. >> Awesome! –

ответ

2

Хорошо, вот мой намек: подумайте о том, что произойдет, когда вы recv() нулевые символы. Также проверьте, что происходит, когда сервер вызывает accept() против того, когда клиент вызывает connect().

Вы также можете более разумно проверить возвращаемые значения ваших recv() звонков. (И send(), по этому вопросу, если вызов может потерпеть неудачу, проверить возвращаемое значение!) Вот подсказка с man recv страницы:

RETURN VALUES 
    These calls return the number of bytes received, or -1 if an error occurred. 

Кроме того, если вы не знакомы с отладчиком (например, gdb), Я бы рекомендовал изучить его. В крайнем случае вы можете подумать о добавлении к вашему коду инструкций, чтобы выяснить, что происходит.

Также подумайте, где ваши «блокирующие вызовы». Если вы не знакомы с тем, что означает «блокирующий вызов», мы называем его «блокировкой» при вызове функции, и эта функция не возвращает («блоки») до тех пор, пока не произойдет какая-то определенная вещь. Например, ваш accept() будет блокироваться до тех пор, пока соединение не будет принято. Ваш fgets() будет блокироваться до тех пор, пока не будет получена строка текста. send() блокирует, если вы уже отправили слишком много данных, и буфер заполнен. recv() будет блокироваться до тех пор, пока вы не получите указанное количество байтов. recv() также имеет поведение, которое вы могли бы не ожидать, что вам может понадобиться для учета:

If no messages are available at the socket, the receive call waits for a 
message to arrive, unless the socket is nonblocking (see fcntl(2)) in 
which case the value -1 is returned and the external variable errno set 
to EAGAIN. The receive calls normally return any data available, up to 
the requested amount, rather than waiting for receipt of the full amount 
requested; this behavior is affected by the socket-level options 
SO_RCVLOWAT and SO_RCVTIMEO described in getsockopt(2). 

В вашем случае, ваши пакеты могут быть достаточно малы, что не будет работать в тех случаях, когда вы должны собрать их самостоятельно , Но это не помешало проверить.

Я думаю, что дает некоторые пути для изучения ...

+0

Спасибо за советы!Поэтому, если recv() принимает нулевые символы и возвращает 0, я правильно понял, что это потому, что отправлено сообщение с 0-char или другая сторона отключена? Я думал, что что-то не в том месте, в петле, но теперь я не уверен. – AbigailB

+1

Проверьте страницу руководства: «Для сокетов TCP возвращаемое значение 0 означает, что сверстник закрыл свою половину соединения». (По умолчанию 'recv()' не будет возвращаться до тех пор, пока не будут получены некоторые байты, или возникнет ошибка). Если вы запустите программу в 'gdb', вы можете нажать' Control-C', чтобы прорваться в отладчик, а затем введите 'bt', чтобы увидеть, где он застрял. – mpontillo

+0

Хм ... мне нужно очищать буфер каждый раз? Извините, я не догоняю. – AbigailB

Смежные вопросы