Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C套接字编程写/读脏内存_C_Sockets_Client_Server_Read Write - Fatal编程技术网

C套接字编程写/读脏内存

C套接字编程写/读脏内存,c,sockets,client,server,read-write,C,Sockets,Client,Server,Read Write,我在我的C程序上编写了两个自定义函数,供我的大学老师建议使用: ssize_t FullRead(int fd, void *buff, size_t count) { size_t nleft; ssize_t nread; nleft = count; while(nleft > 0) { nread = read(fd, buff, nleft); if(errno == EINTR) { con

我在我的C程序上编写了两个自定义函数,供我的大学老师建议使用:

ssize_t FullRead(int fd, void *buff, size_t count) {
    size_t nleft;
    ssize_t nread;
    nleft = count;
    while(nleft > 0) {
        nread = read(fd, buff, nleft);
        if(errno == EINTR) {
            continue;
        }
        else {
            return nread;
        }
        if(nread == 0) {
            break;
        }
        nleft -= nread;
        buff += nread;
    }
    buff = 0;
    return nleft;
}

这在客户端上:

FullRead(connfd, buff, strlen(buff));
printf("Buff: %s\n", buff);
FullRead(connfd, buff, strlen(buff));
printf("Buff: %s", buff);
memset((void *)buff, 0, sizeof(char)*1000);
scanf("%s", buff);
fflush(stdin);
FullWrite(sockfd, buff, strlen(buff));

memset((void *)buff, 0, sizeof(char)*1000);
scanf("%s", buff);
fflush(stdin);
FullWrite(sockfd, buff, strlen(buff));
如果我在linux终端上从服务器写入类似“001”的内容,那么在客户机上会看到“001”�或类似的事情。。诸如此类的事情。无法摆脱这种局面


我尝试更改代码,从FullWrite()和FullRead()中删除buff=0,删除了fflush()和memset,调用如下函数:

客户

scanf("%s", buff);
FullWrite(sockfd, buff, sizeof(buff));
服务器

length = FullRead(connfd, buff, strlen(buff));
printf("Buffer: %.*s\n", length, buff);
服务器仍然会读取和打印垃圾邮件。

有两个问题:

  • 您正在将strlen(buff)传递到
    FullRead()
    -您可能想要
    sizeof(buff)
    (如果不知道如何声明/初始化此缓冲区,很难说)

  • 您没有终止从
    FullRead()
    返回的字符串-您需要在收到数据后立即使用
    '\0'
    ,否则后续的
    printf()
    很可能会在字符串结尾之外发出垃圾字符


另外,正如您已经知道的,您不应该调用
fflush(stdin)

Paul R和EJP发现了直接的问题:实际上,您假设缓冲区最初包含一个与您要读取的长度相同的C字符串。只有在这种情况下,
strlen(buff)
才指定正确的字节数,并且结果可靠地以null结尾

但这只是冰山一角。接下来,我注意到您的
FullWrite()
FullRead()
实现存在缺陷。以后者为代表,考虑阅读循环中的摘录:

        if(errno == EINTR) {
            continue;
        }
        else {
            return nread;
        }
观察(1)仅在读取被信号中断的情况下(可能在读取任何字节之前,也可能不在读取之前)循环循环,以及(2)在任何情况下都不会到达循环体末尾的代码。为什么
read()
调用传输的字节数比预期和期望的要少,原因远不止被信号中断。这种循环的通常实现是重复读取,直到传输了指定数量的字节,或者
read()
调用返回
-1
。您的循环包含实现该功能的位,但它从不使用它们

此外,如果实际读取的字节数少于请求的字节数,则函数将返回错误的值

还要注意的是,在
void*
上执行算术的语义不是由C定义的。一些编译器将其视为指针的类型
char*
,但这是不可移植的。如果要将该值视为
char*
,则应将其强制转换或分配给该类型

此外,函数在返回之前将
0
分配给缓冲区指针是没有用的(尽管不是有害的)

下面是
FullRead()
的改进实现:

ssize\u t FullRead(int-fd、void*buff、size\u t count){
大小\u t nleft=计数;
char*next=buff;
而(nleft>0){
ssize_t nread=读取(fd,next,nleft);
如果(nread<0){
如果(errno==EINTR){
/*被信号打断*/
/* 
*POSIX未指定此条件是否可以
*在GNU中成功传输任何字节时出现
*在这种情况下,它不会出现。
*/
持续
}否则{
/*其他错误*/
返回-1;
}
}如果(nread==0),则为else{
/*文件结束*/
打破
}否则{
/*“nread”字节已成功传输*/
nleft-=nread;
next+=nread;
}
}
返回(计数-nleft);
}
您的
FullWrite
函数也遇到类似的问题。我让你来解决这个问题

但我们还没有完成。即使(尤其是事实上)正确地实现了
FullWrite()
FullRead()
,您仍然需要解决一个关键问题:服务器实际(尝试)读取多少字节?只有两种方法可以知道:

  • 字节数可以在带外进行通信。最有可能实现这一点的是使其成为预先安排好的固定大小

  • 客户端必须提前告诉服务器需要多少字节


  • 预先安排好的大小对于可变长度的数据(如字符串)不是很合适,但是对于固定长度的数据(如二进制数值),它工作得很好。一种解决方案是将字符串作为(长度、内容)对传输。长度首先是网络字节顺序的
    uint16\t
    ,然后是字符串数据的指定字节数。接收方负责提供字符串终止。这类似于HTTP使用
    Content Length
    头来指定消息正文的大小。

    您忽略了
    FullRead(),
    返回的长度,因此您当然是在打印垃圾。您不需要ned
    memset()
    fflush()或
    buff=0
    。只能使用返回的长度,例如
    printf(“%.*s\n”,长度,buff)`我更新了我的问题。但它仍然不起作用。他不应该以null结束字符串。他应该停止假设缓冲区以null结尾。我这样声明缓冲区:“char buff[1025];”。你能解释一下什么时候使用“sizeof()”和“strlen()”吗?使用
    sizeof
    来获取变量的物理大小,即它占用了多少内存,在
    char buff[1025]的情况下总是1025。使用
    strlen
    获取(以null结尾)字符串的长度,例如,如果
    buff
    包含“Hello worl”
            if(errno == EINTR) {
                continue;
            }
            else {
                return nread;
            }
    
    ssize_t FullRead(int fd, void *buff, size_t count) {
        size_t nleft = count;
        char *next = buff;
    
        while (nleft > 0) {
            ssize_t nread = read(fd, next, nleft);
    
            if (nread < 0) {
                if (errno == EINTR) {
                    /* interrupted by a signal */
                    /* 
                     * It is not specified by POSIX whether this condition can
                     * arise if any bytes are successfully transerred.  In the GNU
                     * implementation, it does not arise in that case.
                     */
                    continue;
                } else {
                    /* other error */
                    return -1;
                }
            } else if (nread == 0) {
                /* end of file */
                break;
            } else {
                /* 'nread' bytes successfully transferred */
                nleft -= nread;
                next += nread;
            }
        }
    
        return (count - nleft);
    }