利用recv和readn函数实现readline函数
在前面的文章中,我们为了避免粘包问题,实现了一个readn函数读取固定字节的数据。如果应用层协议的各字段长度固定,用readn来读是非常方便
的。例如设计一种客户端上传文件的协议,规定前12字节表示文件名,超过12字节的文件名截断,不足12字节的文件名用'\0'补齐,从第13字节开始是
文件内容,上传完所有文件内容后关闭连接,服务器可以先调用readn读12个字节,根据文件名创建文件,然后在一个循环中调用read读文件内容并存
盘,循环结束的条件是read返回0。
字段长度固定的协议往往不够灵活,难以适应新的变化。前面讲过的TFTP协议的各字段是可变长的,以'\0'为分隔符,文件名可以任意长,再看blksize
等几个选项字段,TFTP协议并没有规定从第m字节到第n字节是blksize的值,而是把选项的描述信息“blksize”与它的值“512”一起做成一个可变长的字
段。
因此,常见的应用层协议都是带有可变长字段的,字段之间的分隔符用换行'\n'的比用'\0'的更常见,如HTTP协议。可变长字段的协议用readn来读就很
不方便了,为此我们实现一个类似于fgets的readline函数。
首先来看一个跟read 相似的系统函数recv。
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
recv函数与read函数类似,但只能读取套接字描述符,而不能是一般的文件描述符,且多了一个标志参数。
flags参数比较重要的有两个,一个是MSG_OOB,即读取带外数据时候的选项,tcp头部有一个紧急指针16位的值。另一个是MSG_PEEK,即从缓冲区
返回数据但不清空缓冲区,这点与read是不同的。
下面使用封装后的recv函数实现readline函数:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
/* recv()只能读写套接字,而不能是一般的文件描述符 */
ssize_t recv_peek(int sockfd, void *buf, size_t len) { while (1) { int ret = recv(sockfd, buf, len, MSG_PEEK); // 设置标志位后读取后不清除缓冲区 /* 读到'\n'就返回,加上'\n' 一行最多为maxline个字符 */ while (1) nread = ret; return ret + count;
} } if (nread > nleft) exit(EXIT_FAILURE); nleft -= nread; ret = readn(sockfd, bufp, nread); if (ret != nread) exit(EXIT_FAILURE); bufp += nread; return -1; |
在readline函数中,我们先用recv_peek”偷窥“ 一下现在缓冲区有多少个字符并读取到bufp,然后查看是否存在换行符'\n'。如果存在,则使用readn连
通换行符一起读取(清空缓冲区);如果不存在,也清空一下缓冲区, 且移动bufp的位置,回到while循环开头,再次窥看。注意,当我们调用readn读
取数据时,那部分缓冲区是会被清空的,因为readn调用了read函数。还需注意一点是,如果第二次才读取到了'\n',则先用count保存了第一次读取的
字符个数,然后返回的ret需加上原先的数据大小。
使用 readline函数也可以认为是解决粘包问题的一个办法,即以'\n'为结尾当作一条消息。对于服务器端来说可以在前面的fork程序的基础上把do_service函数更改如下:
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void do_echoser(int conn)
{ char recvbuf[1024]; while (1) { memset(recvbuf, 0, sizeof(recvbuf)); int ret = readline(conn, recvbuf, 1024); if (ret == -1) ERR_EXIT("readline error"); else if (ret == 0) //客户端关闭 { printf("client close\n"); break; } fputs(recvbuf, stdout); |
客户端的更改也是类似的,不再赘述,测试输出也是正常的。
参考:
《Linux C 编程一站式学习》
《TCP/IP详解 卷一》
《UNP》
利用recv和readn函数实现readline函数的更多相关文章
- UNIX网络编程——利用recv和readn函数实现readline函数
在前面的文章中,我们为了避免粘包问题,实现了一个readn函数读取固定字节的数据.如果应用层协议的各字段长度固定,用readn来读是非常方便的.例如设计一种客户端上传文件的协议,规定前12字节表示文件 ...
- Linux网络编程-readn函数、writen函数、readline函数实现
readn函数功能:在网络编程的读取数据中,通常会需要用到一个读指定字节才返回的函数,linux系统调用中没有给出,需要自己封装. readn实现代码: int readn(int fd, void ...
- TCP粘包问题的解决方案02——利用readline函数解决粘包问题
主要内容: 1.read,write 与 recv,send函数. recv函数只能用于套接口IO ssize_t recv(int sockfd,void * buff,size_t len,i ...
- 网络编程readn、writen和readline函数的编写
readn 在Linux中,read的声明为: ssize_t read(int fd, void *buf, size_t count); 它的返回值有以下情形: 1.大于0,代表成功读取的字节 ...
- 自己封装一个readline函数实现服务器客户端回射
实现的功能:一次只能读取一行,客户端输入之后,一回车,马上字符串传到服务器端并显示在终端,然后服务器端将字符串又传回给客户端. 服务器端可以接收多个客户端的连接请求,并fork一个子进程来进行服务. ...
- Python中readline()函数 去除换行符
从Python中readline()函数读取的一行内容中含有换行符\n,很多时候我们需要处理不含有换行符的字符串,此时就要去掉换行符\n. 方法是使用strip()函数. 例子如下: f = open ...
- 利用闭包特性改写addEventListener的回调函数
var numClicks = 0; document.addEventListener("click",function(){ alert( ++numClicks); },fa ...
- 利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()方法
1.利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()方法 首先判断字符串的长度是否为0,如果是,直接返回字符串 第二,循环判断字符串的首部是否有空格,如 ...
- python练习题:利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()方法
方法一: # -*- coding: utf-8 -*- # 利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()方法: def trim(s): whil ...
随机推荐
- 第2章 排序 | 第10节 计数排序练习题 && 基数排序
对于一个int数组,请编写一个计数排序算法,对数组元素排序. 给定一个int数组A及数组的大小n,请返回排序后的数组. 测试样例: [1,2,3,5,2,3],6 [1,2,2,3,3,5] 计数排序 ...
- 泛型 Generic 类型擦除引起的问题及解决方法
参考:http://blog.csdn.net/lonelyroamer/article/details/7868820#comments 因为种种原因,Java不能实现真正的泛型,只能使用类型擦除来 ...
- DIV焦点事件详解 --【focus和tabIndex】
添加 tabindex='-1' 属性: 默认:获取不到焦点事件(blur) 1 <div class="wl-product" id="wl-product&qu ...
- HDOJ-3785 寻找大富翁(优先队列)
寻找大富翁 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- WordPress 无法使用the_content()方法输出内容
在使用WordPress里在一个页面里我使用the_content()方法来输出当前页面的内容,但却显示为空,而标题,url等都没有问题 在网络上好像遇到这种情况的人很少只找到了一个说是可能是func ...
- 【Canvas】动态正17边光阑 向高斯致敬
[背景知识] 公元前三世纪,欧几里得在<几何原本>中记载了正方形,正五边形,正六边形的做法,后来人们也掌握了正十五边形作图,但之后两千多年,人们没有在更高阶边形上取得突破. 1796年,1 ...
- 在Lotus Notes设置邮件转发
Notes里面设置邮件转发,一种是创建一个Agent代理,但这种方式有弊端,就是邮件标题缺失,这个比较别扭.这里就不推荐了. 另一种方法是创建Rule规则,这种方式完美.具体方法如下: 1.点Tool ...
- 【Javascript Demo】遮罩层和弹出层简单实现
最近纠结于遮罩层和弹出层的实现,终于搞定了个简单的版本.示例和代码如下,点击按钮可以看到效果: 1.示例: 2.代码: <!DOCTYPE html PUBLIC "-//W3C//D ...
- ZOJ 2319 Beautiful People
LIS.先按S降序升序再按B降序排序(如果B不按降序排序的话就会覆盖掉正解),然后再对B用O(nlog(n))的LIS求解就可以了.用d数组标记每个元素在上升序列中的位置,然后根据d倒着找id就可以了 ...
- Tomcat之安装篇- 1
1. 提供了下载页面 以及tomcat下载地址,点击即可下载 : Tomcat9.0(Windows64) 方便好用的录像机下载请点击: gif工具 即可下载. 2.下载好的压缩包进行解压 3.配置路 ...