6.TCP/IP流協議(處理粘包):包尾\n(recv/send)
阿新 • • 發佈:2018-12-16
recv
ssize_t recv(int socket, void *buffer, size_t length, int flags); 返回值 > 0 成功接收資料大小 = 0 另外一端關閉了套接字 = -1 錯誤,需要獲取錯誤碼errno 1.recv與read相比,只能用於socket流 2.多了一個輔助選項 MSG_OOB 帶外資料 緊急指標 MSG_PEEK 偷窺緩衝區中的資料(預先讀緩衝區,不將資料從緩衝區中讀走) MSG_PEEK:可以讀資料,不從緩衝區中讀走,利用次特點可以方便的實現按行讀取資料 1.使用read函式:一個字元一個字元讀,方法不好(會多次呼叫系統呼叫read方法) 2.使用recv函式+MSG_PEEK選項 提前偷窺下緩衝區,緩衝區裡邊有資料後,把緩衝區中的資料讀到記憶體中 然後在記憶體中一個位元組一個位元組判斷是否為\n
readline
//recv_peek:看一下緩衝區中有沒有資料,並不移除核心緩衝區中的資料 ssize_t recv_peek(int fd,void* buf,size_t len){ while(1){ int ret=recv(fd,buf,len,MSG_PEEK); if(ret==-1 && errno==EINTR) continue; return ret; } } ssize_t readline(int fd,void* buf,size_t maxLine){ int ret; int nread; char* bufp=(char*)buf; int nleft=maxLine; while(1){ ret=recv_peek(fd,bufp,nleft); if(ret<0) //失敗 return ret; else if(ret==0) //對方已關閉 return ret; //else if(ret>0) //recv_peekt偷窺到了ret個位元組的資料 nread=ret; int i; for(i=0;i<nread;i++){ //逐個判斷讀到的bufp中是否有\n if(bufp[i]=='\n'){ //如果緩衝區中有\n ret=readn(fd,bufp,i+1); //讀走資料 if(ret!=i+1) exit(EXIT_FAILURE); return ret; //有\n就返回,並返回讀走的資料 } }//for if(nread>nleft) //if 讀到的數 > 一行最大數 —> 異常處理 exit(EXIT_FAILURE); nleft-=nread; //若緩衝區沒有\n,把剩餘的資料讀走 ret=readn(fd,bufp,nread); if(ret!=nread) exit(EXIT_FAILURE); bufp+=nread; //bufp指標後移後,再接著偷看緩衝區資料recv_peek,直到遇到\n } }