C套接字编程写/读脏内存
我在我的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
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(),
返回的长度,因此您当然是在打印垃圾。您不需要nedmemset()
或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);
}