C语言 C 套接字:接收并发送所有数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13479760/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:30:18  来源:igfitidea点击:

C socket: recv and send all data

csocketsclient-serversendrecv

提问by Lorenzo Cinque

I would like to obtain a behavior similar to this:

我想获得与此类似的行为:

  1. Server run
  2. Client run
  3. Client type a command like "help" or other
  4. Server responds appropriately
  5. go to 3
  1. 服务器运行
  2. 客户端运行
  3. 客户端输入一个命令,如“帮助”或其他
  4. 服务器适当响应
  5. 去 3

The problem is that when my function excCommand("help") run just a little text is received and printed. My text file is this:

问题是当我的函数 excCommand("help") 运行时,只接收并打印了一些文本。我的文本文件是这样的:

COMMAND HELP:

help - Display help
quit - Shutdown client

only COMMAND HELP is printed. Another problem is that when i type a command nothing is printed and after 2 command client exit. This is the piece in particular:

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

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

This is the server:

这是服务器:

#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--;
        }

    }

}

Handler:

处理程序:

void HandleTCPClient(int clntSock)
{
    char buffer[BUFSIZE];
    ssize_t numBytesRcvd = recv(clntSock, buffer, BUFSIZE, 0);
    buffer[numBytesRcvd] = '
#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);
}
'; 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); }

and this is my client:

这是我的客户:

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;
}

sorry for being so long-winded

抱歉啰嗦

回答by Jah

The recv()and send()functions do not guarantee to send/recv all data (see man recv, man send)

recv()send()功能不保证发送/ recv的所有数据(见男人的recv人送

You need to implement your own send_all()and recv_all(), something like

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

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);

The following guide may help you Beej's Guide to Network Programming

以下指南可能对您有所帮助Beej's Guide to Network Programming

回答by user207421

Usual problems.

常见问题。

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

Invalid. numBytesRecvcould have been zero, in which case there is no message at all, otherwise at this point must be positive, as you've already tested for negative, and it indicates the actual length of the message, which isn't necessarily null-terminated. Change to:

无效的。numBytesRecv可能为零,在这种情况下根本没有消息,否则此时必须为正,因为您已经测试为负,并且它表示消息的实际长度,不一定以空值结尾. 改成:

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

and then:

进而:

    }
    while (numBytesRecv > 0);

Pointless. Remove.

无意义。消除。

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

At this point you should check for numBytesRecv < 0and call perror()or one of its friends.

在这一点上,你应该检查numBytesRecv < 0并打电话给perror()它的朋友之一。

回答by albttx

I choose to send before each send() if i have to continue or not.

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

so i first have 3 define

所以我首先有 3 个定义

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);
}

Then to send my data

然后发送我的数据

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);
}

And to receive it :

并接收它:

##代码##