1. 程式人生 > >6.TCP/IP流協議(處理粘包):包尾\n(recv/send)

6.TCP/IP流協議(處理粘包):包尾\n(recv/send)

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                                                      
  }                                                                                                                              
}