以前针对goahead研究过如何使用cookie,如今在使用它进行上传文件时又出现了一点问题,首先,之前goahead在原来的板子跑的时候,上传文件一直正常,使用的mips交叉编译。现在使用arm交叉编译,虽然优化的比较厉害,但是其余功能一切正常,唯独这个上传文件会使webs崩溃。
对于文件上传需要找到webs.c中的void websReadEvent(webs_t wp),因为我们使用的是method="post" enctype="multipart/form-data",所以处理方式在 case WEBS_POST_CLEN这里,标志为wp->flags & WEBS_MULTIPART_FORM。 这些找到后,就可以通过这条分支来处理保持上传的文件。
在上面函数里面设置完调试语句后,将程序跑起来,然后看看问题具体产生在何处。发现,while ((rc = websGetInput(wp, &text, &nbytes)) == 0)这里在没有读取完整个文件时,竟然返回-1,返回-1表示读到EOF,或者error,导致下面执行了break,完成对文件的读取操作,接下来又会读出数据,然后整个程序挂掉。 若上传文件正常的话,会一直返回1直到读完整个文件,中途不会返回-1。 那肯定就是这里有问题了。下面就要进到websGetInput()函数里面设置调试语句,并分析。 nbytes = socketRead(wp->sid, buf, len);该处在接收文件时返回0,即没有读到数据,然后程序中对返回0的操作是return -1。ok,情况明朗了,也就是说,在上传文件过程中,有时会读取不到数据,那好,我读不到数据就继续读,怎样解决呢, return 0;返回0表示未读完继续读,这样问题解决。
这样解决只是治标不治本,还是有隐患的,最需要处理的就是为什么会没有读到数据。 关于文件上传这部分,只要多分析上述提到的两个函数,是最有帮助的了。
在说说webs.h中定义的一些SIZE吧。WEBS_SOCKET_BUFSIZ,非常重要,此为每次从socket读取数据的长度。为了提高访问速度和上传速度,还可以增大WEBS_HEADER_BUFINC,和WEBS_BUFSIZE的大小。
websParseRequest()函数中在提取"content-length"时,数据大小放到wp->clen里面,因此可以使用它来限制上传文件的大小。
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Goahead 文件上传速度过慢原因分析
一、Goahead WEB请求处理流程:
开启侦听websOpenListen()-> 建立socket连接socketOpenConnection(NULL, port, websAccept, 0);并注册连接之后的响应函数websAccept;
主函数里轮训检测socket连接状态,当有连接,则相应websAccept函数;
当WEB有请求发出:
websAccept()-》创建socket处理函数socketCreateHandler(sid, SOCKET_READABLE, websSocketEvent, wp);并将socket.flags置为SOCKET_READABLE --> 进入socket事件websSocketEvent();根据socket.flags进行相应 的操作:如果为SOCKET_READABLE则为读事件--> websReadEvent(wp); 根据不同的wp.flags 和wp.states进行数据的读取,读完之后进入请求解析websParseRequest(),将wp相应标志置位,继续接受请求的数据,请求数据接收完毕,进行请求处理函数 websUrlHandlerRequest();从所有处理函数中找到请求处理函数(asp, form, cgi ...)最后关闭socket描述符,请求处理完毕。
回到主函数继续循环等待。
二、具体过程。
Main():
初始化
initWebs()
开启GOAHEAD服务
websOpenServer(port, retries);
开启侦听
websOpenListen()
建立socket连接, 并注册连接之后的响应函数websAccept();
socketOpenConnection(NULL, port, websAccept, 0);
当侦听到有连接,运行websAccept();
websAccept();
创建socket处理,设置socket可读标志,并注册socket事件websSocketEvent()函数。
socketCreateHandler(sid, SOCKET_READABLE, websSocketEvent, wp);
socket 事件websSocketEvent()函数。
websSocketEvent();
检测socket可读标志SOCKET_READABLE触发读wp数据事件。
websReadEvent(wp);
for(; ;)
按wp.flag和wp.state轮训读取wp数据
websGetInput();
wp->state = 1或者2时,解析数据的格式.
wp->state = 8时,接受上传文件的数据,并将其存入wp.postData;
数据读完关闭socket.
if (fd != -1) {
gclose (fd);
fd = -1;
}
上传文件数据接收完之后,进行WEB请求处理。
websUrlHandlerRequest(wp);
设置环境变量。如若上二进制文件,将其进行格式处理。
websSetEnv(wp);
调用请求处理函数(asp或form或。。。);
(*sp->handler)(wp, sp->urlPrefix, sp->webDir, sp->arg,
wp->url, wp->path, wp->query)(即:form_updateSystemFirmware);
释放内存结束WEB读事件。
if (text) {
bfree(B_L, text);
}
结束SOCKET事件。
继续回到主循环等待下一个请求。
while (!finished) {
if (socketReady(-1) || socketSelect(-1, 1000)) {
socketProcess(-1);//处理socket事件
}
websCgiCleanup();
emfSchedProcess();
}
三、 实验数据:
说明:我在websGetInput();取完数据之后在进入switch之前,添加了一打印语言,将wp->state属性打印出来。
printf("\twp->state = %d\n",wp->state);
switch(wp->state) {
case WEBS_BEGIN:
.
.
.
}
wp->state = 1 进入case WEBS_BEGIN:
wp->state = 2进入case WEBS_HEADER:
wp->state = 8进入case WEBS_POST_CLEN: (上传文件数据读取)
1. 传送较小的Makefile文件:
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 8
wp->state = 8
wp->state = 8
Get in the update form
fn (null)
bn /tmp/Makefile
begin to open file
begin to open file2222
begin to fwrite data
fwrite over
File close success
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
2. 传送较大的texthw
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
Get in the update form
fn (null)
bn /tmp/Makefile
begin to open file
begin to open file2222
begin to fwrite data
fwrite over
File close success
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
数据分析:从两次数据中不难得出,其中数据部分是wp->state = 8的部分,开关和结尾都是一样的,所以时间的长短应该就是打印wp->state = 8的多少。因为在wp->state = 2 转wp->state = 8的时候是进行的websParesRequest();请求解析,并改变wp.state为8,所以在前面的转折点是不会出现太多的延时,在wp->state = 8 转Get in the update form时这里就是前面提到的请求处理,同样不会有太多延时。综上,上传文件的速度原因,不是因为其它延时所致的。从websReadEvent();代码中所以看出,每次读完一部分数据就要将其放进postData,还有进行一系列的处理,如果读取次数过多,这部分代码执行的频率也越高,从尔时间也越多,所以在传送同样多的数据的时候,我们要尽可能少的减少这读取次数。目前来看,貌似只有增加每次读取数据的长度才能达到这样的效果。
综上:文件上传速度的关键在于每次读取文件数据的buffer大小!
改变buffer之后的实验数据:( 256 –> 1024 )
1. 传送较小的文件Makefile
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 8
Get in the update form
fn (null)
bn /tmp/Makefile
begin to open file
begin to open file2222
begin to fwrite data
fwrite over
File close success
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
2. 传送较大的文件testhw
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
wp->state = 8
Get in the update form
fn (null)
bn /tmp/Makefile
begin to open file
begin to open file2222
begin to fwrite data
fwrite over
File close success
wp->state = 1
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
wp->state = 2
3. 传送2M的文件系统也只用了10+秒。
改变这个buffer的大小,只是在传送的时候每次占用了1024的大小,而在传送完之后就释放了,所以不会有太大影响!