字节流套接字上的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;
}
转载于:https://www.cnblogs.com/CodingUniversal/p/7597841.html