-----------------------------------------------------------------------服務器
#include <unistd.h>網絡
ssize_t read(int fd, void *buf, size_t nbyte); socket
-----------------------------------------------------------------------函數
read()函數是負責從fd中讀取內容。當讀成功時,read()返回實際所讀的字節數,若是返回的值是0,表示已經讀到文件的結束了,小於0表示出現了錯誤。若是錯誤爲EINTR說明讀是由中斷引發的,若是是ECONNREST表示網絡鏈接出了問題。咱們寫一個本身的讀函數:spa
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); }
-----------------------------------------------------------------------code
#include <unistd.h>orm
ssize_t write(int fd, const void*buf,size_t nbytes);blog
-----------------------------------------------------------------------進程
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); }
recv和send函數提供了和read和write差很少的功能,不過它們提供了第四個參數來控制讀寫操做。
-----------------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
int recv(int sockfd,void *buf,int len,int flags);
int send(int sockfd,void *buf,int len,int flags);
-----------------------------------------------------------------------
前面的三個參數和同樣,第四個參數能夠是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)。
MSG_NOSIGNAL:is a flag used by send() in some implementations of the Berkeley sockets API.
This flag requests that the implementation does not to 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 option SO_NOSIGPIPE?.
對於服務器端,咱們可使用這個標誌。目的是不讓其發送SIG_PIPE信號,致使程序退出。
若是flags爲0,則和read、write同樣的操做。還有其它的幾個選項,不過咱們實際上用的不多。能夠查看 Linux Programmer's Manual獲得詳細解釋。