C socket:recv并发送所有数据

时间:2012-11-20 18:29:37

标签: c sockets client-server send recv

我想获得类似的行为:

  1. 服务器运行
  2. 客户端运行
  3. 客户端键入“帮助”或其他
  4. 之类的命令
  5. 服务器响应正确
  6. 转到3
  7. 问题是,当我的函数excCommand(“help”)运行时,只接收并打印一个小文本。 我的文本文件是:

    COMMAND HELP:
    
    help - Display help
    quit - Shutdown client
    

    仅打印命令帮助。 另一个问题是,当我输入命令时,没有打印任何内容,并且在2命令客户端退出之后。 特别是这件作品:

    while (quit)
        {
            getLine("client> ", command, 10);
            if (strcmp(command, "quit") == 0)
                quit = 0;
            else
                excCommand(command);
        }
    

    这是服务器:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #include "common.h"
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
            ErrorWithUserMessage("Parameter(s)", "<Server Port>");
    
        char *service = argv[1];
    
        int servSock = SetupTCPServerSocket(service);
        if (servSock < 0)
            ErrorWithUserMessage("SetupTCPServerSocket() failed: ", "unable to establish");
    
        unsigned int childProcessCount = 0;
        while (1)
        {
            int clntSock = AcceptTCPConnection(servSock);
    
            pid_t processID = fork();
            if (processID < 0)
                ErrorWithSystemMessage("fork() failed");
            else if (processID == 0)
            {
                close(servSock);
                HandleTCPClient(clntSock);
                exit(EXIT_SUCCESS);
            }
    
            printf("with child process: %d\n", processID);
            close(clntSock);
            childProcessCount++;
    
            //clean up zombies
            while (childProcessCount)
            {
                processID = waitpid((pid_t) - 1, NULL, WNOHANG);
                if (processID < 0)
                    ErrorWithSystemMessage("waitpid() failed");
                else if (processID == 0)
                    break;
                else
                    childProcessCount--;
            }
    
        }
    
    }
    

    处理程序:

    void HandleTCPClient(int clntSock)
    {
        char buffer[BUFSIZE];
        ssize_t numBytesRcvd = recv(clntSock, buffer, BUFSIZE, 0);
        buffer[numBytesRcvd] = '\0';
        if (numBytesRcvd < 0)
            ErrorWithSystemMessage("recv() failed");
        if (strcmp(buffer, "help") == 0)
        {
            FILE *fp = fopen("help.txt", "r");
            if (fp)
            {
                char line[128];
                while (fgets(line, sizeof(line), fp) != NULL)
                {
                    if (send(clntSock, line, sizeof(line), 0) < 0)
                        ErrorWithSystemMessage("send() failed");
                }
                fclose(fp);
            }
        }
    
        close(clntSock);
    }
    

    这是我的客户:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    #include <sys/types.h>
    #include <sys/socket.h>
    
    #include "common.h"
    
    int sock;
    
    void getLine(char *message, char *buf, int maxLen)
    {
        printf("%s", message);
        fgets(buf, maxLen, stdin);
        buf[strlen(buf) - 1] = 0;
    }
    
    void excCommand(char *command)
    {
        if ( send(sock, command, strlen(command), 0) < 0)
            ErrorWithSystemMessage("send() failed");
    
        char replyMessage[BUFSIZE];
        ssize_t numBytesRecv = 0;
        do
        {
            numBytesRecv = recv(sock, replyMessage, BUFSIZE, 0);
            if ( numBytesRecv < 0)
                ErrorWithSystemMessage("recv() failed");
            printf("%s\n", replyMessage);
            memset(&replyMessage, 0, sizeof(replyMessage));
    
        }
        while (numBytesRecv > 0);
    }
    
    void PrintFile(const char *filename)
    {
        FILE *fp;
        fp = fopen(filename, "r");
        if (fp)
        {
            char line[128];
            while (fgets(line, sizeof(line), fp) != NULL)
                fputs(line, stdout);
            fputs("\n", stdout);
            fclose(fp);
        }
    }
    
    int main(int argc, char *argv[])
    {
        int quit = 1;
        char command[10];
    
        if (argc < 2 || argc > 3)
        {
            ErrorWithUserMessage("Parameter(s)", "<Server Address> <Server Port>");
        }
    
        char *server = argv[1];
        char *service = argv[2];
    
        sock = SetupTCPClientSocket(server, service);
        if (sock < 0)
            ErrorWithUserMessage("SetupTCPClientSocket() failed: ", "unable to connect");
    
        printf("Connection established!\n\n");
    
        PrintFile("menu.txt");
        excCommand("help");
    
        while (quit)
        {
            getLine("client> ", command, 10);
            if (strcmp(command, "quit") == 0)
                quit = 0;
            else
                excCommand(command);
        }
    
        fputs("\n", stdout);
        close(sock);
        exit(EXIT_SUCCESS);
    }
    
    很抱歉这么啰嗦

3 个答案:

答案 0 :(得分:16)

recv()send()函数无法保证发送/收回所有数据(请参阅man recvman send

您需要实现自己的send_all()recv_all(),例如

bool send_all(int socket, void *buffer, size_t length)
{
    char *ptr = (char*) buffer;
    while (length > 0)
    {
        int i = send(socket, ptr, length);
        if (i < 1) return false;
        ptr += i;
        length -= i;
    }
    return true;
}

以下指南可以帮助您Beej's Guide to Network Programming

答案 1 :(得分:2)

常见问题。

void excCommand(char *command)
{
    if ( send(sock, command, strlen(command), 0) < 0)
        ErrorWithSystemMessage("send() failed");

    char replyMessage[BUFSIZE];
    ssize_t numBytesRecv = 0;
    do
    {
        numBytesRecv = recv(sock, replyMessage, BUFSIZE, 0);
        if ( numBytesRecv < 0)
            ErrorWithSystemMessage("recv() failed");
        printf("%s\n", replyMessage);

无效。 numBytesRecv可能为零,在这种情况下根本没有消息,否则此时必须是正数,因为您已经测试了否定,并且它表示消息的实际长度,这不是'必须以空终止。改为:

    if (numBytesRecv == 0)
        break;
    printf("%.*s\n", numBytesRecv, replyMessage);

然后:

        memset(&replyMessage, 0, sizeof(replyMessage));

毫无意义的。删除。

    }
    while (numBytesRecv > 0);

此时,您应该检查numBytesRecv < 0并致电perror()或其中一位朋友。

答案 2 :(得分:0)

如果必须继续,我选择在每次发送()之前发送。

所以我首先要有3个定义

#define BUFFSIZE 1024
#define CONT "CONT"
#define DONE "DONE"

然后发送我的数据

int     send_to_socket(int sock, char *msg)
{
    size_t  len;
    int     ret[2];

    len = strlen(msg);
    ret[0] = send(sock, (len <= BUFFSIZE) ? DONE : CONT, 4, 0);
    ret[1] = send(sock, msg, BUFFSIZE, 0);
    if (ret[0] <= 0 || ret[1] <= 0)
    {
        perror("send_to_socket");
        return (-1);
    }
    if (len > BUFFSIZE)
        return (send_to_socket(sock, msg + BUFFSIZE));
    return (1);
}

接收它:

char    *recv_from_socket(int cs)
{
    char    state[5];
    char    buff[BUFFSIZE+1];
    char    *msg;
    int     ret[2];

    msg = NULL;
    while (42)
    {
        bzero(state, 5);
        bzero(buff, BUFFSIZE+1);
        ret[0] = recv(cs, state, 4, 0);
        ret[1] = recv(cs, buff, BUFFSIZE, 0);
        if (ret[0] <= 0 || ret[1] <= 0)
        {
            perror("recv_from_socket");
            return (NULL);
        }
        // strfljoin() is selfmade
        // join the string and free the left argument to prevent memory leaks.
        // return fresh new string
        msg = (msg) ? ft_strfljoin(msg, buff) : strdup(buff);
        if (strncmp(state, DONE, 4) == 0)
            break ;
        i++;
    }
    return (msg);
}