字节流套接字上的read和write函数所表现的行为不同于通常的文件IO,字节流套接字上调用read和write输入或输出的可能比请求的数量少,然而这不是出错的状态,例如某个中端使read和write提前返回,这时就应该继续读和写而不是出错返回了,下面是unp中对read和write函数在socket中的使用的封装。

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
ssize_t readn(int fd,void* buff,size_t nbytes){
ssize_t nleft;
ssize_t nread;
char* ptr; nleft=(ssize_t)nbytes;
ptr=(char*)buff;
nread=0;
while(nleft>0){
if((nread=read(fd,ptr,nleft))<0){
if(errno==EINTR){
nread=0;
}
else{
return -1;
}
}
else if(nread==0){ //read返回0代表读到EOF
break;
}
else{
nleft-=nread;
ptr+=nread;
}
}
return (nbytes-nread);
} ssize_t writen(int fd,void* buff,size_t nbytes){
ssize_t nleft;
ssize_t nwrite;
char* ptr; nleft=(ssize_t)nbytes;
nwrite=0;
ptr=(char*)buff; while(nleft>0){
if((nwrite=write(fd,ptr,nleft))<=0){ //write返回0代表出错
if(nwrite<0&&errno==EINTR){
nwrite=0;
}
else{
return -1;
}
}
else{
nleft-=nwrite;
ptr+=nwrite;
}
}
return (nbytes);
}
//频繁使用read函数这个效率非常低
ssize_t readline(int fd,void* buff,size_t nbytes){
ssize_t n,rc;
char c,*ptr; ptr=(char*)buff;
for(n=1;n<nbytes;++n){
again:
if((rc=read(fd,&c,1))==1){
*ptr++=c;
if(c=='\n')
break;
}
else if(rc==0)
return(n-1);
else{
if(errno==EINTR){
goto again;
}
return -1;
} }
return (n);
} //下面是一个改进版的但是这个版本使用了static变量,它是线程不安全的
#define MAXLINE 4096
static int read_cnt;
static char* read_ptr;
static char read_buf[MAXLINE];
//先从内核读一些数据到用户空间,在每次都从用户空间中读数据
static ssize_t myread(int fd,char* ptr){
if(read_cnt<=0){
again:
if((read_cnt=read(fd,read_buf,sizeof(read_buf)))<0){
if(errno==EINTR)
goto again;
return -1;
}
else if(read_cnt==0)
return 0;
else
read_ptr=read_buf;
}
read_cnt--;
*ptr=*read_ptr++;
return 1;
} ssize_t readline(int fd,void* buff,size_t maxlen){
ssize_t n,rc;
char c,*ptr;
ptr=(char*)buff;
for(n=1;n<maxlen;++n){
if((rc=myread(fd,&c))==1){
*ptr++=c;
if(c=='\n')
break;
}
else if(rc==0){
*ptr='\0';
return (n-1);
}
else{
return -1;
} }
*ptr='\0';
return n;
} ssize_t readlinebuf(void **vptrtptr){
if(read_cnt)
*vptrvptr=read_ptr; return read_cnt;
}

Linux 网络编程中的read和write函数正确的使用方式的更多相关文章

  1. linux网络编程中的shutdown()与close()函数

    1.close()函数 int close(int sockfd); //返回成功为0,出错为-1 close 一个套接字的默认行为是把套接字标记为已关闭,然后立即返回到调用进程,该套接字不能再由cl ...

  2. linux网络编程中INADDR_ANY的含义

    INADDR_ANY选项 网络编程中常用到bind函数,需要绑定IP地址,这时可以设置INADDR_ANY INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或&q ...

  3. 网络编程中的read,write函数

    关于TCP/IP协议,建议参考Richard Stevens的<TCP/IP Illustrated,vol1>(TCP/IP详解卷1). 关于第二层面,依然建议Richard Steve ...

  4. linux网络编程中的超时设置

    1 下面是在网上找到的资料,先非常的感谢. 用setsockopt()来控制recv()与send()的超时 在send(),recv()过程中有时由于网络状况等原因,收发不能预期进行,而设置收发超时 ...

  5. linux网络编程中的基本概念

    int close(int fd)(假设是服务器端) close 关闭了自身数据传输的两个方向.close一个TCP套接字的默认行为是把该套接字标记成已关闭,然后立即返回到调用进程.该套接字描述符不能 ...

  6. linux网络编程中阻塞和非阻塞socket的区别

    读操作 对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返 回.当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数.当 ...

  7. linux网络编程中需要注意的信号SIGPIPE

    在调试cs时,s端循环收,c端循环发,s端意外崩溃后,c端自动退出,终端提示SIGPIPE导致c端退出.man 7 signal: SIGPIPE Term Broken pipe: write to ...

  8. Linux网络编程中tcp_server和tcp_client函数的封装

    本文的主要目的是将server套接字和client套接字的获取,做一个简易的封装,使用C语言完成.   tcp_server   服务器端fd的获取主要分为以下几步: 1.创建socket,这一步仅仅 ...

  9. Linux网络编程——I/O复用之poll函数

    一.回顾前面的select select优点: 目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点 select缺点: 1.每次调用 select(),都需要把 fd 集合从用户态拷贝到内核 ...

随机推荐

  1. VS2008 C++ 利用WinHttp API获取任意Http网址的源码

    最近一直在看有关Http的知识,对其基本的理论知识已经有所掌握,想通过一个C++具体的例子进行实际操作..于是上网查找了很多资料,发现在Windows系统上,可以通过WinHttp API接口开啊Ht ...

  2. Here We Go(relians) Again

    Here We Go(relians) Again Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/O ...

  3. Treasure of the Chimp Island

    Treasure of the Chimp Island Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav ...

  4. Python函数篇:dict函数和列表生成式

    1.dict函数语法:dict()dict(**kwarg) dict(mapping, **kwarg) dict(iterable, **kwarg) 第一种:dict()构造一个空字典 h=di ...

  5. L2-2. 链表去重

    L2-2. 链表去重 时间限制300 ms内存限制65536 kB代码长度限制8000 B判题程序Standard作者陈越给定一个带整数键值的单链表L,本题要求你编写程序,删除那些键值的绝对值有重复的 ...

  6. 用Nodejs+Express搭建web,nodejs路由和Ajax传数据并返回状态,nodejs+mysql通过ajax获取数据并写入数据库

    小编自学Nodejs,看了好多文章发现都不全,而且好多都是一模一样的 当然了,这只是基础的demo,经供参考,但是相信也会有收获 今天的内容是用Nodejs+Express搭建基本的web,然后呢no ...

  7. Linux系列教程(二十二)——Linux的bash变量

    上篇博客我们介绍了bash的一些基本功能,这是我们平时操作最频繁的.本篇博客我们介绍bash的变量,为后面编写shell脚本做铺垫. 1.什么是变量 变量是计算机内存的单元,其中存放的值可以改变. 当 ...

  8. linux操作系统基础篇(一)

    1.什么是linux? Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件.应用程序 ...

  9. 学习cordic算法所得(流水线结构、Verilog标准)

    最近学习cordic算法,并利用FPGA实现,在整个学习过程中,对cordic算法原理.FPGA中流水线设计.Verilog标准有了更加深刻的理解. 首先,cordic算法的基本思想是通过一系列固定的 ...

  10. jenkins~管道Pipeline的使用,再见jenkinsUI

    Pipeline在Jenkins里的作用 最近一直在使用jenkins进行自动化部署的工作,开始觉得很爽,省去了很多重复的工作,它帮助我自动拉服务器的代码,自动还原包包,自动编译项目,自动发布项目,自 ...