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