socket函数read write send和recv 收集整理

1.send   recv   是面向套接口的文件描述符
read   write   需要的是文件描述符 

read和write也可以对socket的fd进行处理,因为Linux把socket也当作一种特殊文件描述符。
二者在BSD4.4上是一致的,最终会调到统一的内核处理函数,只是recv和send多些选项(flag)

What   is   the   difference   between   read()   and   recv()? 
From   Andrew   Gierth   (andrew@erlenstar.demon.co.uk): 

read()   is   equivalent   to   recv()   with   a   flags   parameter   of   0.   Other   values   for   the   flags   parameter   change   the   behaviour   of   recv().   Similarly,   write()   is   equivalent   to   send()   with   flags   ==   0. 

It   is   unlikely   that   send()/recv()   would   be   dropped;   perhaps   someone   with   a   copy   of   the   POSIX   drafts   for   socket   calls   can   check... 

Portability   note:   non-unix   systems   may   not   allow   read()/write()   on   sockets,   but   recv()/send()   are   usually   ok.   This   is   true   on   Windows   and   OS/2,   for   example.

=================================================================================================================

一旦,我们建立好了tcp连接之后,我们就可以把得到的fd当作文件描述符来使用。

由此网络程序里最基本的函数就是read和write函数了。
ssize_t write(int fd, const void*buf,size_t nbytes);
write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量. 在网络程序中,当我们向套接字文件描述符写时有两可能. 
1)write的返回值大于0,表示写了部分或者是全部的数据. 这样我们用一个while循环来不停的写入,但是循环过程中的buf参数和nbyte参数得由我们来更新。也就是说,网络写函数是不负责将全部数据写完之后在返回的。
2)返回的值小于0,此时出现了错误.我们要根据错误类型来处理. 

如果错误为EINTR表示在写的时候出现了中断错误. 
如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接). 
为了处理以上的情况,我们自己编写一个写函数来处理这几种情况. 


int my_write(int fd,void *buffer,int length) 

int bytes_left; 
int written_bytes; 
char *ptr; 

ptr=buffer; 
bytes_left=length; 
while(bytes_left>0) 

         /* 开始写*/ 
         written_bytes=write(fd,ptr,bytes_left); 
         if(written_bytes<=0) /* 出错了*/ 
         {        
                 if(errno==EINTR) /* 中断错误 我们继续写*/ 
                         written_bytes=0; 
                 else             /* 其他错误 没有办法,只好撤退了*/ 
                         return(-1); 
         } 
         bytes_left-=written_bytes; 
         ptr+=written_bytes;     /* 从剩下的地方继续写   */ 

return(0); 


读函数read 
ssize_t read(int fd,void *buf,size_t nbyte) 
read函数是负责从fd中读取内容.当读成功 时,read返回实际所读的字节数,如果返回的值是0 表示已经读到文件的结束了,小于0表示出现了错误.如果错误为EINTR说明读是由中断引起 的, 如果是ECONNREST表示网络连接出了问题. 和上面一样,我们也写一个自己的读函数. 

int my_read(int fd,void *buffer,int length) 

int bytes_left; 
int bytes_read; 
char *ptr; 
   
bytes_left=length; 
while(bytes_left>0) 

    bytes_read=read(fd,ptr,bytes_read); 
    if(bytes_read<0) 
    { 
      if(errno==EINTR) 
         bytes_read=0; 
      else 
         return(-1); 
    } 
    else if(bytes_read==0) 
        break; 
     bytes_left-=bytes_read; 
     ptr+=bytes_read; 

return(length-bytes_left); 
}

数据的传递 
有了上面的两个函数,我们就可以向客户端或者是服务端传递数据了.比如我们要传递一个结构.可以使用如下方式 

/*   客户端向服务端写 */ 

struct my_struct my_struct_client; 
write(fd,(void *)&my_struct_client,sizeof(struct my_struct); 

/* 服务端的读*/ 
char buffer[sizeof(struct my_struct)]; 
struct *my_struct_server; 
read(fd,(void *)buffer,sizeof(struct my_struct)); 
my_struct_server=(struct my_struct *)buffer;     

在网络上传递数据时我们一般都是把数据转化为char类型的数据传递.接收的时候也是一样的 注意的是我们没有必要在网络上传递指针(因为传递指针是没有任何意义的,我们必须传递指针所指向的内容)


6.1 recv和send 
recv和send函数提供了和read和write差不多的功能.不过它们提供 了第四个参数来控制读写操作. 

int recv(int sockfd,void *buf,int len,int flags) 
int send(int sockfd,void *buf,int len,int flags) 

前面的三个参数和read,write一样,第四个参数可以是0或者是以下的组合 
_______________________________________________________________ 
| MSG_DONTROUTE | 不查找表 | 
| MSG_OOB | 接受或者发送带外数据 | 
| MSG_PEEK | 查看数据,并不从系统缓冲区移走数据 | 
| MSG_WAITALL | 等待所有数据 | 
|--------------------------------------------------------------| 

MSG_DONTROUTE:是send函数使用的标志.这个标志告诉IP.目的主机在本地网络上面,没有必要查找表.这个标志一般用网络诊断和路由程序里面.
MSG_OOB:表示可以接收和发送带外的数据.关于带外数据我们以后会解释的. 

MSG_PEEK:是recv函数的使用标志,表示只是从系统缓冲区中读取内容,而不清除系统缓冲区的内容.这样下次读的时候,仍然是一样的内容.一般在有多个进程读写数据时可以使用这个标志. 

MSG_WAITALL是recv函数的使用标志,表示等到所有的信息到达时才返回.使用这个标志的时候recv回一直阻塞,直到指定的条件满足,或者 是发生了错误. 1)当读到了指定的字节时,函数正常返回.返回值等于len 2)当读到了文件的结尾时,函数正常返回.返回值小于len 3)当操作发生错误时,返回-1,且设置错误为相应的错误号(errno) 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值