socket编程---fgets和fputs函数使用理解
来源:互联网 发布:杨春秋软件俱乐部 编辑:程序博客网 时间:2024/05/19 17:58
这一节是继续上一节socket05的讨论,来探讨在使用socket进行通信中遇到的一些函数使用理解误区
1.fgets的使用注意点
在写socket通信(代码见上一篇中,只是将sendbuf和recvbuf的容量改变了其余不变)的时候遇到的问题,这个现象是:
在fgets(sendbuf,sizeof(sendbuf),stdin)的时候,假设我的sendbuf容量是n,也就是char sendbuf[n]
1.当我的输入小于n-1时,并且以换行为结尾的时候,fgets会在最后那个字符的后面加上一个\n字符,最后还要补上一个'\0',然后发送过去2.但是当我输入的字符串达到了n-1或大于n-1的时候,会截断到n-1处,然后在最后面加上一个\0字符(作为字符串结束)
更形象地说明这个现象,做一个假设,设定n=10,也就是buf均为10,之后再来进行通信
//在client.c中修改这两行char sendbuf[10] = {0};char recvbuf[10] = {0};
//在server.c中修改这一行char recvbuf[10] = {0};
之后编译运行,通信情况如下图所示:
可以看出来,我在发送小于9的字符数时,都是正常进行通信的,但是第一个9个字符的helloworl就让程序卡死了,之后在client端再输入什么,server端都没再答应了。
这里我们先记住这个现象,接下来我们来了解一下fgets和fputs函数的用法,再联合程序来分析到底是代码的哪个步骤出了bug。
查了一下具体fgets和fputs的用法,稍微找到了一些能解释的说法:
fgets( ):会自动在字符数组最后加上一个'\0'(字符串以\0为识别,也是结束),如果字符数组长度不够(没到达缓冲区的限制值),则截断前面部分,没有'\0',如果行尾有换行符(我们这里发送数据以换行符为标识一行发送),换行符也被赋值进入数组,在'\0'的前面。
也就是说,无论什么时候,fgets都会在后面加上一个’\0’,只不过阀值比较特殊,甚至在我们这个程序中引发了一些错误。
当我输入: hello\nsendbuf中: hello\n\0 这时候的有效字符为6个,除去\0无效当达到阀值: helloworl\n 换行符是第10位sendbuf中: helloworl\0 这时候因为末尾一位必须是\0,所以截断,换行符也被截断了,不算入有效字符
所以使用fgets时,只能录入有效数据9位最多,并且需要注意的是在这里的代码中(socket通信),由于我们自己封装的一个readline函数规定,client发送数据时需要将一个\n发送给对等段,才能使得server端的readn函数真正把数据读取出去,而不是卡死在缓冲区。顺而执行到下面的代码,包含了writen,回射client端。
2.server端和client端各个函数之间通信的顺序流程图:
结合图中,我们可以知道,为什么会出现如上的结果,是阻塞在了server端的readline函数中。
把源码拿过来看一下:
ssize_t readline(int sockfd,void *buf,size_t maxline){ int ret; int nread; char* bufp = buf; //指针指向buf缓冲区 int nleft = maxline; while(1) { ret = recv_peek(sockfd,bufp,nleft); if(ret < 0) return ret; else if(ret == 0) return ret; nread = ret; int i; for(i = 0;i<nread;i++) { if(bufp[i] == '\n') //对等端必须将\n发送过来,不发送过来会导致程序卡死在这里 { ret = readn(sockfd,bufp,i+1); if(ret != i+1) exit(EXIT_FAILURE); return ret; } } if(nread > nleft) exit(EXIT_FAILURE); nleft -= nread; ret = readn(sockfd,bufp,nread); if(ret != nread) exit(EXIT_FAILURE); bufp += nread; } return -1;}
1.从代码中看,我们封装好一个sendbuf,假设client端是helloworl\n输入,这时候的helloworl\n被裁剪成了helloworl\0,这里上面详细解释过的
2.那么这样一个字符串作为sendbuf传递过来了,server进入readline函数,看以上代码,调用完了recv_peek,直接进入for循环
3.可以看出来,这个字符串是没有’\n’的,所以跳出for循环,进入下面代码,可是下面的代码一般是不执行的,因为正常遇到’\n’就直接返回退出函数。那么我们就是卡死在了这里。
得出一个结论:我们可以输入的有效字符数是容量capacity-2,留两位给\n和\0.
3.fputs函数
这个函数没对我们的程序造成什么大的影响,但是总是和fgets配对出现,将字符串打印到标准输出(屏幕…..)
#include<stdlib.h>#include<stdio.h>#include<string.h>int main(){ char ch[10] = "hello\n"; printf("strlen = %d\n",(int)strlen(ch)); printf("sizeof = %d\n",(int)sizeof(ch)); char get[10]; int count = 0; fputs("hello,this is fputs\n",stdout); while(1) { fgets(get,sizeof(get),stdin); for(int i = 0;i < strlen(get);i++) { printf("%c",get[i]); count = i; } printf("\ncount = %d\n",count); printf("strlen(get) = %d\n",(int)strlen(get)); } return 0;}
大家可以把这段代码粘过去编译执行一下,是输入一段字符,求字符的有效字符数。
fgets和fputs都在里面,fputs显得相对简单地多了,只是将一段字符打印到标准输出,fgets会把’\n’作为有效字符存入字符串中。
4.总结
我们找到了问题的所在,是因为fgets对字符串的切割使得传输有效字符串有了限制,这里我还也没能找到一个好的办法来解决这个问题,但是好在只要我们的sendbuf和recvbuf足够大,一般的信息传送不会使得程序崩溃。
如果遇到数据量比较大的时候,我们应该对边界作一个切割,把大块数据切割成多个小块,在后面加上’\n’和’\0’两个预留字符。
- socket编程---fgets和fputs函数使用理解
- fgets() - fputs()函数使用
- fgets函数 和 fputs
- fgets 和fputs函数
- fgets()和fputs()函数
- 使用fgets和fputs函数读写文件
- fgets()函数和fputs函数
- fgets()和fputs()的使用
- 字符串读写函数 fgets和fputs 函数
- fgets函数和fputs函数的区别
- 字符串读写函数fgets和fputs
- 字符串读写函数fgets和fputs
- 字符串读写函数fgets和fputs
- 字符串读写函数fgets和fputs
- 字符串读写函数fgets和fputs
- 字符串读写函数fgets和fputs
- 字符串读写函数fgets和fputs
- 字符串读写函数fgets和fputs
- 高仿QQ空间项目实战开发(带服务器端程序)
- 并查集
- Struts2之异常处理机制
- 《剑指offer》最小的K个数
- 视频格式与视频编码压缩标准 之间的关系
- socket编程---fgets和fputs函数使用理解
- XML解析 PULL
- hdoj1084What Is Your Grade?(结构体+sort)
- 运算符.强制类型转换等
- 拷贝构造函数
- mssql中的数据转存到Mysql中
- HDU 5733 tetrahedron (2016 Multi-University Training Contest 1 计算几何)
- mysql的索引
- 类设计原则