Linux网络编程(附1)——封装read、write
原打算实践简单的模型的时候,主要专注于基本的模型,先用UNIX I/O糊弄下,可是未封装的read和write用起来实在心累,还是直接用前辈们已经实现好的高级版本号read、write。
UNIX I/O read、write
#include<unistd.h>
ssize_t read(int fd, void* buf, size_t n);
若成功则为读的字节数,若EOF则为0,若出错则为-1。
ssize_t write(int fd, const void* buf, size_t n);
若成功则为写的字节数。若出错则为-1
buf被拷贝的位置,n最大拷贝的字节数,fd描写叙述符
在某些情况下,read和write因为各种原因会传送比预估要少的字节数(short count)。可是有些时候这个并非因为错误造成的,还可能因为下面几个原因。
1、读时遇到EOF: 如果我们准备读一个文件,该文件从当前文件位置開始仅仅含有30个字节,而我们以60个字节的片进行读取(普通情况下反复调用read、write传入的n固定)。
这样下来,返回值为30,此后再读的时候通过返回0来发出EOF信号。
2、从终端读,每一个read函数将以此传送一个文本行。(此时会不断的返回,然后不断再次调用,封装read后能够直接智能处理这样的情况)。
3、读和写网络套接字(socket)。
内部缓冲约束、和网络延时(上面红色部分提到)会影响read和write提前返回。
非网络情况下。直接读本地文件,read、和write基本上不会遇到非EOf的(short count)情况。
高级I/O
非缓冲版本号(并非没有内核缓冲、是没有内核缓冲之上的二级缓冲)
这些函数直接在存储器和文件之间传送数据,没有应用级缓冲。它们对将二进制数据读写到网络和从网路读写二进制数据尤事实上用。
readn
ssize_t readn(int fd,void *usrbuf,size_t n)
{
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf; while(nleft > 0){
if((nread = read(fd,bufp,nleft)) < 0){
if(errno == EINTR){/*interrupted by sig handler return*/
nread = 0;
}else{
return -1;/*error*/
}
}else if(nread == 0){
break; /*EOF*/
}else{/*read content*/
nleft -= nread;
bufp += nread;
}
}
return (n - nleft);
}
writen
ssize_t rio_writen(int fd,void *usrbuf,size_t n)
{
size_t nleft = n;
ssize_t nwritten;
char *bufp = usrbuf; while(nwritten = write(fd,bufp,nleft) <= 0){
if(errno == EINTR){
nwritten = 0;
}else{
return -1;
}
nleft -= nwritten;
bufp += nwritten;
}
return n;
}
作为工具函数、详细实践就临时不做了,反正以后会经经常使用到。
注意:writen的返回值事实上是固定的,每次为n。可是read不固定。
原因:简单理解 远端write --->远端计算机(内核缓冲) ----------(网络传输中)----------->本地计算机(内核缓冲)--------->read
上面能够看出,read是读远端的内容,所以不能确定究竟要读多少。可是write是往本地写的,应用程序知道要写多少数据。即便是一次没有写完。也能够通过重复调用写完心目中的数据。
带缓冲版本号(内核缓冲之上)
此类函数同意高效地从二进制文中读文本行和二进制数据,这些文件缓存在应用级缓存内。类似于像printf这种标准I/O函数提供的缓冲区。
缓冲区结构体(事实上就是一些信息加一个大的数组)
#define RIO_BUFSIZE 8192
typedef struct{
int rio_fd; /*To operate the file descriptor*/
int rio_cnt;/*unread bytes in internal buf*/
char *rio_bufptr;/*next unread byte int internal buf*/
char rio_buf[RIO_BUFSIZE];/*internal buf*/
}rio_t;
初始化缓冲区(事实上就是将缓冲区和网络描写叙述符fd联系起来)
rio_init
没打开一个文件描写叙述符都会调用一次rio_init
void rio_readinitb(rio_t *rp,int fd)
{
rp->rio_fd = fd;
rp->rio_cnt = 0;
rp->rio_bufptr = rp->rio_buf;
}
rio_read(带缓冲版本号的read, 和unix read(未封装的)具有一模一样的效果)
static ssize_t rio_read(rio_t *rp,char *usrbuf,size_t n)
{
int cnt;
while(rp->rio_cnt <= 0){/*Read the file content if buf is empty*/
rp->rio_cnt = read(rp->rio_fd, rp->rio_buf,sizeof(rp->rio_buf));
if(rp->rio_cnt < 0){
if(errno != EINTR){
return -1;
}
}else if(rp->rio_cnt == 0){/*EOF*/
return 0;
}else {/*reset buf ptr*/
rp->rio_bufptr = rp->rio_buf;
}
}
/*when n < rp->rio_cnt, need copy some times */
cnt = n;
if(rp->rio_cnt < n){/*one time copy end*/
cnt = rp->rio_cnt;
}
memcpy(usrbuf,rp->rio_bufptr,cnt);
rp->rio_bufptr += cnt;
rp->rio_cnt -= cnt;
return cnt;
}
rio_readlineb
每次第一行,最多读maxlen-1,最后一个字留给空字符,超过maxlen-1的话将被截断,并用空字符结束
ssize_t rio_readlineb(rio_t *rp, void *usrbuf,size_t maxlen)
{
int n,rc;
char c,*bufp = usrbuf;
for(n = 1; n < maxlen; n++){
if (( rc = rio_read(rp,&c,1)) == 1){
*bufp++ = c;
if(c == '\n'){
break;
}
}else if (rc == 0){
if(n == 1){/*EOF no data read*/
return 0;
}else{/*EOF some data read*/
break;
}
}else{/*ERROR*/
return -1;
}
}
*bufp = 0;/*string end sign :'\0'*/
return n;
}
rio_readnb(带缓冲版本号的readn)
ssize_t rio_readnb(rio_t *rp,void *usrbuf,size_t n)
{
size_t nleft = n;
ssize_t nread;
char *bufp = usrbuf; while(nleft > 0){
if((nread = rio_read(rp,bufp, nleft)) < 0){
if(errno == EINTR){/*interrupted by sig handler return*/
nread =0;
}else{/*errno set by read() */
return -1;
}
}else if(nread == 0){/*EOF*/
break;
}
nleft -= nread;
bufp += nread;
}
return (n-nleft);/*return >=0*/
}
Linux网络编程(附1)——封装read、write的更多相关文章
- Linux网络编程10——使用UDP实现五子棋对战
思路 1. 通信 为了同步双方的棋盘,每当一方在棋盘上落子之后,都需要发送给对方一个msg消息,让对方知道落子位置.msg结构体如下: /* 用于发给对方的信息 */ typedef struct t ...
- Linux网络编程(三)
Linux网络编程(三) wait()还是waitpid() Linux网络编程(二)存在客户端断开连接后,服务器端存在大量僵尸进程.这是由于服务器子进程终止后,发送SIGCHLD信号给父进程,而父进 ...
- Linux 高性能服务器编程——Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字(so ...
- 很全的linux网络编程技巧
本文转载自:http://www.cnblogs.com/jfyl1573/p/6476607.html 1. LINUX网络编程基础知识 1 1.1. TCP/IP协议概述 1 1.2. OSI参考 ...
- Linux网络编程基础
1. Linux网络模型 ① OSI七层模型和Linux四层模型 ② 各种协议之间的关系及在Linux模型中的位置 ③ 协议封装:各种协议处于一种层层封装的关系 (1)Ethernet (2)IP * ...
- Linux网络编程:原始套接字简介
Linux网络编程:原始套接字编程 一.原始套接字用途 通常情况下程序员接所接触到的套接字(Socket)为两类: 流式套接字(SOCK_STREAM):一种面向连接的Socket,针对于面向连接的T ...
- 【深入浅出Linux网络编程】 "开篇 -- 知其然,知其所以然"
[深入浅出Linux网络编程]是一个连载博客,内容源于本人的工作经验,旨在给读者提供靠谱高效的学习途径,不必在零散的互联网资源中浪费精力,快速的掌握Linux网络编程. 连载包含4篇,会陆续编写发出, ...
- 【linux草鞋应用编程系列】_5_ Linux网络编程
一.网络通信简介 第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章. 二.linux网络通信 在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...
- Linux 网络编程(IO模型)
针对linux 操作系统的5类IO模型,阻塞式.非阻塞式.多路复用.信号驱动和异步IO进行整理,参考<linux网络编程>及相关网络资料. 阻塞模式 在socket编程(如下图)中调用如下 ...
- linux网络编程 no route to host 解决方案
linux网络编程 no route to host 解决方案 [整合资料] (2013-05-13 21:38:12) 转载▼ 标签: net iptables it 分类: Linux 参考资料h ...
随机推荐
- Java学习之道:Java 导出EXCEL
1.Apache POI简单介绍 Apache POI是Apache软件基金会的开放源代码函式库.POI提供API给Java程式对Microsoft Office格式档案读和写的功能. .NET的开 ...
- DB-MySQL:MySQL 索引
ylbtech-DB-MySQL:MySQL 索引 1.返回顶部 1. MySQL 索引 MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 打个比方,如果 ...
- Java入门第一季
慕课网:http://www.imooc.com/learn/85 Java入门知识第一季 1.Java开发环境和IDE的使用: 2.变量和常量 3.常用的运算符 4.流程控制语句 5.数组:使用Ar ...
- docker初安装的血泪史
最近docker很火,不管是朋友圈内还是公司内聊天都离不开docker,于是对docker产生了极大的好奇心,凭着一颗程序猿的好奇心开始了docker的安装血泪史. 首先我有一台从公司退役的本本x22 ...
- Data type-数据类型
操作方式.含义.存储方式. In computer science and computer programming, a data type or simply type is a classifi ...
- 安装全局可执行的gulp
gulp需要作为项目的开发依赖(devDependencies)安装,全局安装了gulp是无法执行项目的,不单单需要全局安装 gulp:npm install gulp -g,也需要作为项目的开发依赖 ...
- ZBrush中标准几何体与Polymesh
通过对ZBrush的学习,相信您已经对这款软件有了一定的了解,文本我们主要学习ZBrush®的3D物体标准几何体的特性和使用方法.在ZBrush中只有Polymesh(多边形网格)物体才能使用雕刻笔刷 ...
- ZBrush中关于标记的特殊情况
在ZBrush®中使用Marker标记调控板来记忆物体属性,因此能在任何时间回到标记并使用它给其他物体或改变物体作为参考点,在使用Marker标记调控板时回出现很多特殊情况,本文小编就这些特殊情况做一 ...
- 脚本_使用expect自动交互远程主机安装软件
#!bin/bash#功能:使用expect工具自动交互密码,远程到其它主机,安装httpd软件#作者:liusingbon#删除~/.ssh/known-hosts后,ssh远程任何主机,系统都会询 ...
- Codeforces Round #493 (Div. 2) B. Cutting 前缀和优化_动归水题
不解释,题目过水 Code: #include<cstdio> #include<cmath> #include<algorithm> using namespac ...