C中的聊天程序

时间:2014-10-28 22:20:32

标签: 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 serverName

./服务器

我可以来回一次,然后没有其他任何发送或接收。我仍然可以输入,但是两个会话不能看到彼此的来回传递的第一个消息。我不确定我的代码在哪里出错。任何建议都会受到赞赏,因为我对这门语言很陌生。提前致谢!

1 个答案:

答案 0 :(得分: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).

在您的情况下,您的数据包可能足够小,以至于您不会遇到必须自行重新组装的情况。但检查不会有什么坏处。

我认为这会为你提供一些探索的途径......