图像检索服务器编写问题记录——用socket传输图片

来源:互联网 发布:投诉数据分析ppt 编辑:程序博客网 时间:2024/04/29 03:39

1.用readn代替read的原因

为避免频繁的调用read。read调用系统调用,系统调用需要在用户态和核心态转换,需要保存上下文,频繁调用read,会使系统性能下降,in指标上升。为避免频繁调用read,我们在用户空间创建用户缓冲区,将套接字的缓冲区的内容全部读入用户缓冲区后,一次性把用户缓冲区的内容用read写入内核缓冲区。这样可以提高效率。相同的writen也是这个原因。

ssize_t unpluo_readn(int fd,void* vptr,int n){size_t nleft=n;char *ptr=(char*)vptr;ssize_t nread;while(nleft>0){if(nread=read(fd,ptr,nleft)<0){if(errno==EINTR)nread=0;else return -1;}else if(nread==0)break;nleft-=nread;ptr+=nread;}return (n-nleft);}

2.标准IO与文件IO的区别

FILE的fopen等标准IO是库文件,标准IO将硬盘上的文件一次性读入内存中,使用文件指针加以操作,在fclose之后,将内存中的文件写回磁盘。所以通常说标准文件是流操作。标准IO的操作一直在用户态。

read、write等文件IO是系统调用(使用了系统调用),文件IO用于文件在用户态和核心态之间的传输。

通常的搭配。标准IO打开文件,fopen调用read从磁盘上将内容拷贝至内存,标准IO操作内存中的文件流,fclose调用write将文件从内存拷贝回硬盘。

3.服务器端

逻辑:先从客户端接收图片大小,创建图片大小的空文件,然后接收客户端发来的图片。

void servluo_match(int sockfd){char recv[MAXLINE];char flen[7];unpluo_readn(sockfd,flen,7);fprintf(stderr,"the size of image is %s\n",flen);int bytes=atoi(flen);FILE *dlf=NULL;if(bytes>0){char filename[100];strcpy(filename,"image/tmp.jpg");dlf=fopen(filename,"wb");if(dlf==NULL){fprintf(stderr,"failed open file\n");return;}fprintf(stderr,"start recv image %s\n",filename);while(bytes>MAXLINE){unpluo_readn(sockfd,recv,MAXLINE);bytes-=MAXLINE;fwrite(recv,MAXLINE,1,dlf);}if(bytes<=MAXLINE){unpluo_readn(sockfd,recv,bytes);char *tmp=recv;strcat(tmp,"\r\n");fwrite(recv,bytes,1,dlf);tmp=NULL;}fclose(dlf);fprintf(stderr,"write done");}}
此处的坑是:在读取图片最后的那点数据时,需要在文件结尾加上\r\n,不然图片传输过来都是打不开的。

其他考虑:

1.如果客户端放在windows下,就需要将每个接收到的\r\n替换成\n了。


4.客户端

逻辑:先发送图片大小,然后再发送图片

void str_cli(FILE *fp, int sockfd){char send[MAXLINE];//while(1)//{fprintf(stderr,"please input the name of retrieved image file:");fflush(stdin);fflush(stdout);fflush(stderr);char tmp[100];if(fgets(tmp,MAXLINE,fp)==NULL)continue;char *filename=strtok(tmp,"\n");//需要去除\n否则文件打开失败FILE *ulf=fopen(filename,"rb");if(ulf==NULL){fprintf(stderr,"failed open %s\n",filename);continue;}fprintf(stderr,"open file %s,",filename);long filelen;//计算文件长度fseek(ulf,0,SEEK_END);filelen=ftell(ulf);rewind(ulf);char flen[7];sprintf(flen,"%d\n",filelen);fprintf(stderr,"it's size is %s",flen);unpluo_writen(sockfd,flen,7);//至此发送文件大小long left=filelen;while(left>MAXLINE){fread(send,MAXLINE,1,ulf);unpluo_writen(sockfd,send,MAXLINE);left-=MAXLINE;}if(left<=MAXLINE){fread(send,left,1,ulf);unpluo_writen(sockfd,send,left);}fclose(ulf);fprintf(stderr,"send %s ok\n",filename);//}return;}
此处的坑是:客户端分两次发送文件大小和图片,但是于服务器而言可能是一次性接收的一堆内容,所以第一次发送文件大小的char[]大小一定要与服务器端一致,否则,服务器端【图片的字节】被【大小的字节】给占了。

0 0
原创粉丝点击