2014-10-28 86 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

<<首先,這是家庭作業,所以請不徹底的答案>>真棒! – 2014-10-28 23:09:49

回答

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 ),我會推薦學習它。在少數情況下,您可能會考慮在您的代碼中添加printf()語句,以確定發生了什麼。

另外,想想你的「阻塞呼叫」在哪裏。如果你不熟悉「阻塞調用」是什麼意思,那麼當你調用一個函數時,我們稱之爲「阻塞」,並且該函數在某些指定的事情發生之前不會返回(「阻塞」)。例如,您的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 2014-10-28 22:45:37

+1

檢查手冊頁:'對於TCP套接字,返回值0意味着對等體關閉了其連接的一半.'(默認情況下,只有接收到一些字節時,'recv()'纔會返回,或者發生錯誤)。如果你在'gdb'運行程序,你可以按下'Control-C'打入調試器,然後輸入'bt'來查看它被卡住的位置。 – mpontillo 2014-10-28 22:49:21

+0

嗯......我需要每次清除緩衝區嗎?我很抱歉,我沒有趕上。 – AbigailB 2014-10-29 02:08:01