对UDP socket缓冲区的理解

来源:互联网 发布:淘宝卖蜂蜜要备案吗 编辑:程序博客网 时间:2024/04/29 19:25
对UDP socket缓冲区的理解

     UDP套接字的收发报文要用sendto 和 recvfrom,可以类比TCP套接字的connect和accept,参数里面会标识要发往的对端,或者要接收的对端的IP地址和端口;对UDP套接字connect的行为也只是告诉内核:“帮我做个过滤,我只关心这个对端的报文”,已连接的UDP套接字上可以利用read, write, recv, send函数,通常如果确定了该实体只与一个对端进行通信,那么就选择connect;更重要的是UDP套接字的缓冲区是以一个个报文为单位进行排队的,调用一次recvfrom表示提取一个报文,和TCP基于字节流的方式是不同的。基于这样的原因我们不能在UPD中先读取一定的应用层header,而后在根据头部中长度字段来优雅的读取具体的数据,这样会出错,发生混乱;而在TCP中经常会这么做。

     下面是个例子,客户端以一定长度的内容进行发送,客户端进行接收,先读取首部,而后是具体的数据块,如果用UDP是会出错的。利用TCP可以,代码如下(完整代码可以看这里file-transfer):
typedef struct{unsigned char fp[20];int chunk_id;short flags;short chunk_len;char data[0];}TransferUnit;  // some flags for this chunk transfered.enum{        UNIT_NEED_DEDU = 0x0001,   // need deduplication        UNIT_FILE_START = 0x0002,   // first gram , file metadata        UNIT_FILE_END = 0x0004,        CHUNK_OTHER = 0x0008,      // other for extension};void recvFile(char name[20],int sockfd){    int ret,fd;mode_t fdmode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);    unsigned char mesg[MAX];    fd_set rdset;    struct timeval tv;    int rlen, wlen, chunklen;    int i;TransferUnit *header = (TransferUnit *)malloc(sizeof(TransferUnit));    fd = open(name,O_RDWR|O_CREAT|O_APPEND,fdmode);    if(fd == -1)        {       printf("open file %s error:%s \n",name,strerror(errno));      exit(-1);    }while(1){    memset(mesg, 0, sizeof(mesg));// read the gram header first      rlen = read(sockfd, header, sizeof(TransferUnit));//printf("%d\n", rlen);       if(rlen != sizeof(TransferUnit) ){       printf("read sockfd error %s\n",strerror(errno));            exit(-1);       }// recv file end         if((header->flags ^ UNIT_FILE_END) == 0){        printf("recv end.\n");           break;        }// recv file metadata         if((header->flags ^ UNIT_FILE_START) == 0){        int len = header->chunk_len;  // metadata length...char metadata[100] = {0};printf("==== begin file recv ====,metadata len = %d\n", len);if((rlen = read(sockfd, mesg, len)) == len){mesg[len] = '\0';printf("File name : %s\n", mesg);}           continue;        }chunklen = header->chunk_len;// read the actual chunk data       rlen = read(sockfd, mesg, chunklen);//printf("chunk_id:%d,chunk_len:%d \n", header->chunk_id, header->chunk_len);       if(rlen != chunklen ){       printf("read chunk data error %s\n",strerror(errno));            exit(-1);       }// write the chunk data to this file        wlen = write(fd,mesg,rlen);        if(wlen != rlen ){        printf("write error %s\n",strerror(errno));            exit(-1);        }                                printf("The %d times write\n",i);}    close(fd);}


1 0