首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TCP/IP客户端发送

TCP/IP客户端发送
EN

Stack Overflow用户
提问于 2018-04-10 02:03:23
回答 1查看 581关注 0票数 0

下面是我的C/S代码和输出,只是为了测试。

我在这方面有困难。

很明显,我只是通过客户发送了两次。但是,服务器刚刚收到了3条消息。第二个似乎是空的。

代码语言:javascript
复制
#define MP_MAXLINE 4096    
/* client */
int main(int ac, char *av[])
{
    char buf[MP_MAXLINE];
    int clifd;
    struct sockaddr_in cliaddr;

    if((clifd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        perror("socket error");

    memset(&cliaddr, 0, sizeof(struct sockaddr_in));
    cliaddr.sin_family = AF_INET;
    cliaddr.sin_port = htons(atoi(av[2]));
    inet_pton(AF_INET, av[1], &cliaddr.sin_addr);

    if(connect(clifd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)))
        perror("can not connect to server");

    printf("enter data to send: ");
    while(fgets(buf, MP_MAXLINE, stdin) != NULL){
        write(clifd, buf, sizeof(buf));
        printf("enter data to send: ");
    }
}

/* server */
static void cli_service(int clifd){
    int lclifd, rcv_cnt = 0;
    char data[MP_MAXLINE];

    for(;;){
        if(read(clifd, data, sizeof(data)) == 0)
            exit(1);
        rcv_cnt++;
        printf("cnt: %d, data: %s", rcv_cnt, data);
    }
}

int main(int ac, char *av[])
{
    ...

    for(;;){
        clifd = accept(svrfd, (struct sockaddr *)&cliaddr, &clisocklen);

        if((clipid = fork()) < 0){
            printf("fork error\n");
            continue;
        }
        else if(clipid == 0){
            close(svrfd);
            cli_service(clifd);
        }
        close(clifd);
        continue;
    }
}

客户机的输出在这里:

输入数据以发送: 1111

输入数据发送: 2222

输入要发送的数据:

服务器的输出在这里:

cnt: 1,数据: 1111

cnt: 2,数据: cnt: 3,数据: 2222

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-10 03:04:49

正在发生的是,您即将发现TCP是一种面向流的协议,这意味着它保证您发送的字节将被正确、有序地传递,但是字节到单个write()/read()调用的映射是任意的--也就是说,每次调用read()写入接收方数组的字节数肯定不一定与以前通过发送程序传递给write()调用的字节数相同。

因此,在您的客户机中,每个对write()的调用都发送了4096字节,其中前几个字节将包含用户输入的以0结尾的文本字符串,其余的将是未初始化的数据(也就是说,它可能是任何东西,因为您从未写入数组的该部分)。

然后在您的服务器中调用read(),它以一定数量的字节读取,但是您不知道它读取了多少字节,因为您所做的就是检查read()是否返回0。因此,您不知道read()是否将4096字节的数据放置到您的data数组中;如果是较小的字节数,则接收代码现在与发送代码不同步,因为随后对read()的调用可能会将未初始化的数据写入data数组的开始,而用户的下一个字符串位于数组的中间位置。

当然,这是没有用的行为。要修复它,您需要做的是密切注意read()返回的值;如果它大于零,但小于sizeof(data),则需要以某种方式处理它。处理它的一种方法是统计data数组中当前有多少个有效字节,并且一直保持read(clifd, data+numValidBytes, sizeof(data)-numValidBytes),直到(numValidBytes == sizeof(data)).然后解析数据并将numValidBytes设置为零。另一个更简单的选择是调用recv()而不是read(),并在最后一个参数中设置MSG_WAITALL --在这种情况下,recv()将承诺在读取所有sizeof(data)字节之前不返回,然后您不必自己处理部分读取。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49744180

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档