socket編程中write、read和send、recv之間的區別~轉載


socket編程中write、read和send、recv之間的區別

 

http://blog.csdn.net/petershina/article/details/7946615

 

一旦,我們建立好了tcp連接之后,我們就可以把得到的fd當作文件描述符來使用。
由此網絡程序里最基本的函數就是read和write(int fd, const void*buf,size_t nbytes);
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函數提供了和read和send(int sockfd,void *buf,int len,int flags)

前面的三個參數和read,send函數使用的標志.這個標志告訴IP.目的主機在本地網絡上面,沒有必要查找表.這個標志一般用網絡診斷和路由程序里面.
MSG_OOB:表示可以接收和發送帶外的數據.關於帶外數據我們以后會解釋的.

MSG_PEEK:是recv函數的使用標志,表示只是從系統緩沖區中讀取內容,而不清除系統緩沖區的內容.這樣下次讀的時候,仍然是一樣的內容.一般在有多個進程讀寫數據時可以使用這個標志.

MSG_WAITALL是recv函數的使用標志,表示等到所有的信息到達時才返回.使用這個 標志的時候recv回一直阻塞,直到指定的條件滿足,或者是發生了錯誤. 1)當讀到了指定的字節時,函數正常返回.返回值等於len 2)當讀到了文件的結尾時,函數正常返回.返回值小於len 3)當操作發生錯誤時,返回-1,且設置錯誤為相應的錯誤號(errno)


MSG_NOSIGNAL is a flag used by send a SIGPIPE signal on errors on stream oriented sockets when the other end breaks the connection. The EPIPE error is still returned as normal.

Though it is in some Berkely sockets APIs (notably Linux) it does not exist in what some refer to as the reference implementation, FreeBSD, which instead uses a socket optionSO_NOSIGPIPE?. 對於服務器端,我們可以使用這個標志。目的是不讓其發送SIG_PIPE信號,導致程序退出。

如果flags為0,則和read,write一樣的操作.還有其它的幾個選項,不過我們實際上用的很少,可以查看 Linux Programmer's Manual得到詳細解釋


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com