瀏覽器更新HTTP伺服器圖片並顯示
1 實驗目的
瀏覽器登入W5500伺服器顯示一張圖片,再通過檔案上傳一個圖片更新伺服器中的圖片;重新整理瀏覽器顯示更新後的圖片。
2 實驗總體設計
實驗主要分兩個部分:1:瀏覽器申請圖片資料以及上傳圖片資料:;
2:W5500伺服器接收資料以及處理HTTP請求和資料。
3 實驗原理
該實現的原理過程就是先利用取模軟體獲取一個圖片的十六進位制資料陣列,然後W5500伺服器將資料寫入FLASH裡面並記下寫入的位置,主函式迴圈檢測瀏覽器客戶端是否傳送TCP連線請求,如果檢測到請求報文伺服器就會與客戶端建立連線並傳輸第一包資料;第一包資料內包含一段有瀏覽器執行的HTML程式碼,瀏覽器獲取第一包資料後開始執行HTML程式碼,即瀏覽器向伺服器傳送第一張圖片資料請求,伺服器返回圖片的資料並由瀏覽器顯示在網頁上面,此時的圖片是我們第一次寫入FLASH的圖片資料,而伺服器返回資料的過程就是根據瀏覽器的第二個請求中的URL找到圖片並從FLASH讀取出來放在HTTP響應報文中傳送給瀏覽器,瀏覽器再顯示在網頁。
圖片更新的部分就是瀏覽器顯示第一張圖片後會根據我們編寫的HTML程式碼在網頁上顯示一個選擇按鈕以及一個文字框,該部分是HTML利用FORM表單來上傳檔案到我們的伺服器;我們在這裡使用的就是將我們的圖片以檔案的形式上傳到伺服器,伺服器根據表單的請求方式以及路徑來接收圖片資料並將資料寫入內部FLASH,由於我們使用的W5500開發板的內部FLASH是256K(經過測試300K的照片也能寫入,原因可能是內部FLASH實際上是512K的,這個可能是ST的問題在這裡不做解釋)的,所有我們把更新的圖片直接覆蓋掉原來的圖片資料;這樣也比較方便我們獲取資料;資料寫入後我們會在給瀏覽器的響應報文中加入一段HTML以及JAVASCRIPT的程式碼,以便於讓我們的瀏覽器重新整理頁面並從新傳送圖片請求來獲取更新後的圖片並顯示在頁面。
4 內部FLASH操作
4.1 STM32RCT6內部FLASH
STM32F103RCT6為大容量產品,其FLASH的大小是256K,所以一共可以分為128頁,每頁得大小是2K,地址範圍0X0800 0000-0X0803 FFFF;內部FLASH是存放我們下載的程式的,所以要把內部FLASH當做儲存器來使用的話就要考慮寫入地址與存放程式碼的地址是否重合,這裡我把前64頁放我的程式碼,從64頁開始用來存放我寫入的資料;即開始寫入或讀取的地址是0X0802 0000。(根據這裡的解釋我們每次更新的圖片的大小應該小於64K,但是我上面說過了實際測試的時候是可以上傳300K左右的資料的)
內部FLASH讀寫程式碼
uint16_t Flash_Write_Without_check(uint32_t iAddress, uint8_t *buf, uint16_t iNumByteToWrite)
{
uint16_t i=0;
while((i < iNumByteToWrite) && (FLASHStatus == FLASH_COMPLETE))
{
FLASHStatus = FLASH_ProgramHalfWord(iAddress, *(uint16_t*)buf);
i = i+2;
iAddress = iAddress + 2;
buf = buf + 2;
}
return iNumByteToWrite;
}
int Flash_Write(uint32_t iAddress, uint8_t *buf, uint32_t iNbrToWrite)
{
uint32_t secpos;
uint32_t iNumByteToWrite = iNbrToWrite;
uint16_t secoff;
uint16_t secremain;
uint16_t i = 0;
static uint8_t tmp[FLASH_PAGE_SIZE];
FLASH_UnlockBank1();
secpos=iAddress & (~(FLASH_PAGE_SIZE -1 )) ;//扇區地址
secoff=iAddress & (FLASH_PAGE_SIZE -1); //在扇區內的偏移
secremain=FLASH_PAGE_SIZE-secoff; //扇區剩餘空間大小
if(iNumByteToWrite<=secremain) secremain = iNumByteToWrite;//不大於4096個位元組
while(1)
{
ReadFlashNBtye(secpos, tmp, FLASH_PAGE_SIZE); //讀出整個扇區
for(i=0;i
{
if(tmp[secoff+i]!=0XFF)break; //需要擦除
}
if(i
{
FLASHStatus = FLASH_ErasePage(secpos); //擦除這個扇區
if(FLASHStatus != FLASH_COMPLETE)
return -1;
for(i=0;i
{
tmp[i+secoff]=buf[i]; //複製
}
Flash_Write_Without_check(secpos ,tmp ,FLASH_PAGE_SIZE);//寫入整個扇區
}
else
{
Flash_Write_Without_check(iAddress,buf,secremain);//寫已經擦除了的,直接寫入扇區剩餘區間.
}
if(iNumByteToWrite==secremain) //寫入結束了
break;
else
{
secpos += FLASH_PAGE_SIZE;
secoff = 0;//偏移位置為0
buf += secremain; //指標偏移
iAddress += secremain;//寫地址偏移
iNumByteToWrite -= secremain; //位元組數遞減
if(iNumByteToWrite>FLASH_PAGE_SIZE) secremain=FLASH_PAGE_SIZE;//下一個扇區還是寫不完
else secremain = iNumByteToWrite; //下一個扇區可以寫完了
}
}
FLASH_LockBank1();
return iNbrToWrite;
}
int ReadFlashNBtye(uint32_t ReadAddress, uint8_t *ReadBuff, uint32_t ReadNum)
{
int DataNum=0; //定義一個變數記錄讀取的個數
while(DataNum
{
*(ReadBuff+DataNum)=*(__IO uint8_t*)ReadAddress++; //讀一個資料地址加一
DataNum++;
}
return DataNum;
}
4.2 HTML部分程式碼
#define INDEX_HTML ""\
""\
""\
"
"\""\
""\
"
"\"
This is a test
"\""\
"
Pitcure Update
"\"
"\"
"\"
"\"
"\"
"\4.3 HTTP狀態機
該部分是迴圈檢測HTTP請求,獲取請求後經過解析函式獲取請求頭資訊以及URL和資料的型別與長度,再根據這些資料來選擇執行下一步操作,例如接收或者傳送圖片資料;
void do_https(void)
{
uint8 ch=SOCK_HTTPS;
uint16 len;
st_http_request *http_request;
memset(rx_buf,0x00,MAX_URI_SIZE);
http_request = (st_http_request*)rx_buf;
switch(getSn_SR(ch))
{
case SOCK_INIT:
listen(ch);
break;
case SOCK_LISTEN:
break;
case SOCK_ESTABLISHED:
if(getSn_IR(ch) & Sn_IR_CON)
{
setSn_IR(ch, Sn_IR_CON);
}
if ((len = getSn_RX_RSR(ch)) > 0)
{
len = recv(ch, (uint8*)http_request, len);
*(((uint8*)http_request)+len) = 0;
proc_http(ch, (uint8*)http_request);
disconnect(ch);
}
break;
case SOCK_CLOSE_WAIT:
if ((len = getSn_RX_RSR(ch)) > 0)
{
len = recv(ch, (uint8*)http_request, len);
*(((uint8*)http_request)+len) = 0;
proc_http(ch, (uint8*)http_request);
}
disconnect(ch);
break;
case SOCK_CLOSED:
socket(ch, Sn_MR_TCP, 80, 0x00);
break;
default:
break;
}
}
4.4 HTTP響應部分
void proc_http(SOCKET s, uint8 * buf)
{
int8* name;
int8 req_name[32]={0x00,};
unsigned long file_len=0;
uint16 send_len=0;
uint8* http_response;
int8 sub[10],numbuff[5];
uint32 content_len=0,rx_len=0;
uint16 fw_offset = 0;
uint16 wr_len = 0;
uint32 upload_file_len=0;
uint32 n_pages;
uint32 n_erased;
uint8 remain_len = 0;
uint16 i=0;
uint16 tmp_len=0;
uint8 remain_buf[3]={0xff,};
uint32 flash_dest =STARTADDR;
uint32 calc_checksum = 0;
st_http_request *http_request;
memset(tx_buf,0x00,MAX_URI_SIZE);
http_response = (uint8*)rx_buf;
http_request = (st_http_request*)tx_buf;
parse_http_request(http_request, buf);
switch (http_request->METHOD)
{
case METHOD_ERR :
memcpy(http_response, ERROR_REQUEST_PAGE, sizeof(ERROR_REQUEST_PAGE));
send(s, (uint8 *)http_response, strlen((int8 const*)http_response));
break;
case METHOD_HEAD:
case METHOD_GET:
name = http_request->URI;
if(strcmp(name,"/index.htm")==0||strcmp(name,"/")==0||(strcmp(name,"/index.html")==0))
{
file_len = strlen(INDEX_HTML);
make_http_response_head((uint8*)http_response, PTYPE_HTML,file_len);
send(s,http_response,strlen((char const*)http_response));
send_len=0;
while(file_len)
{
if(file_len>1024)
{
if(getSn_SR(s)!=SOCK_ESTABLISHED)
{
return;
}
send(s, (uint8 *)INDEX_HTML+send_len, 1024);
send_len+=1024;
file_len-=1024;
}
else
{
send(s, (uint8 *)INDEX_HTML+send_len, file_len);
send_len+=file_len;
file_len-=file_len;
}
}
}
else if(strcmp(name,"/img.jpg")==0)
{
send_img_jpg_page(s, http_response);
}
else if(strcmp(name,"/w5500.js")==0)
{
memset(tx_buf,0,MAX_URI_SIZE);
make_basic_config_setting_json_callback(tx_buf,ConfigMsg);
sprintf((char*)http_response,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length:%d\r\n\r\n%s",strlen(tx_buf),tx_buf);
send(s, (u_char *)http_response, strlen((char const*)http_response));
}
break;
case METHOD_POST:
mid(http_request->URI, "/", " ", req_name);
if(strcmp(req_name,"pitcure.cgi")==0)
{
mid((int8*)http_request->URI,"boundary=", "\r\n", (int8*)boundary);//boundary=
#ifdef DEBUG_HTTP
printf("boundary=%s\r\n",boundary);
#endif
memset(sub,0,10);
mid((char*)http_request->URI,"Content-Length: ","\r\n",sub);
content_len=atoi32(sub,10);
#ifdef DEBUG_HTTP
printf("content_len=%d\r\n",(uint32_t)content_len);
ee_WriteBytes((uint8_t *)sub,(uint16_t)STARTADDRDATA,strlen((char *)sub));
delay_ms(5);
memset(numbuff,0,5);
numbuff[0]=strlen((char *)sub);
ee_WriteBytes((uint8_t *)numbuff,(uint16_t)STARTADDRDATA+2,1);
#endif
if(content_len<0xffff7)//長度小於1M
{
while(rx_len!=content_len)
{
tmp_len=getSn_RX_RSR(s);
if(tmp_len>0)
{
if(tmp_len>1460) tmp_len=1460;
tmp_len=recv(s, (uint8*)rx_buf, tmp_len);
if(rx_len==0)//the first packet with header
{
int8* pos1;
int8* pos2;
uint16 hdr_len;
#ifdef DEBUG_HTTP
printf("http request=%d\r\n",strlen((int8*)rx_buf));
#endif
pos1=strstr((int8*)rx_buf,(int8*)boundary);
#ifdef DEBUG_HTTP
printf("pos1=%d, %s\r\n", strlen(pos1),pos1);
#endif
pos2=strstr((int8*)rx_buf,"\r\n\r\n");
hdr_len=strlen((int8*)boundary)+6+2+(pos2-pos1)+4+2;
upload_file_len=content_len-hdr_len;
#ifdef DEBUG_HTTP
printf("pos2=%d,boundarylen=%d,uploadfilelen=%d\r\n",pos2-pos1,strlen((int8*)boundary),upload_file_len);
#endif
fw_offset = pos2-pos1+4+2;
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
//erase required page
n_pages = FLASH_PagesMask(upload_file_len);
for(n_erased = 0; n_erased < n_pages; n_erased++)
{
FLASH_ErasePage(STARTADDR + 0x400 * n_erased);
IWDG_ReloadCounter();//feed wdg
}
wr_len = tmp_len-fw_offset;
//make a buf with lengh of multiful 4 and save remain bytes
remain_len = wr_len % 4;
memcpy(tmp_buf,&rx_buf[fw_offset],wr_len-remain_len);
wr_len = wr_len - remain_len;//real length
if(remain_len!=0)
{
memcpy(remain_buf,&rx_buf[tmp_len-remain_len],remain_len);
}
}else{
if(rx_len+tmp_len==content_len)//the last packet that includes boundary
{
wr_len = tmp_len - strlen((int8*)boundary) - 8;
}else{
wr_len = tmp_len;
}
fw_offset=0;
//make buffer
if(remain_len)
{
memcpy(tmp_buf,remain_buf,remain_len);
}
if(wr_len+remain_len>1460)
{
memcpy(&tmp_buf[remain_len],rx_buf,wr_len-remain_len);
//save remain bytes
memcpy(remain_buf,&rx_buf[tmp_len-remain_len],remain_len);
}else{
memcpy(&tmp_buf[remain_len],rx_buf, wr_len);
memset(&tmp_buf[wr_len+remain_len],0xff,3);
wr_len=wr_len+remain_len;
}
}
//program
for(i = 0; i
{
FLASH_ProgramWord(flash_dest, *(uint32*)((uint32)(tmp_buf + i)));
//checksum
calc_checksum += *(uint32*)(flash_dest);
flash_dest += 4;
}
rx_len+=tmp_len;
#ifdef DEBUG_HTTP
printf("len=%d, rx len=%d, wr len=%d, @x\r\n",tmp_len, rx_len, wr_len, flash_dest);
#endif
//program over
if(rx_len==content_len)
{
//lock flash again
FLASH_Lock();
make_delay_jump_msg(tx_buf,"The pitcure is updated...",5);
sprintf((char *)http_response,"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length:%d\r\n\r\n%s",strlen(tx_buf),tx_buf);
send(s, (uint8 *)http_response, strlen((char *)http_response));
}
}
}
}// while 結束
}//end of if(firmware upload)
break;
default :
break;
}
}
4.5 傳送圖片給瀏覽器
該部分是在伺服器接收到瀏覽器的圖片請求後從FLASH讀取圖片資料然後傳送給瀏覽器;瀏覽器顯示。
void send_img_jpg_page(SOCKET s, uint8 * buf)
{
uint32 file_len = 0;
uint32 send_len = 0,addr=0;
uint16 len = 0,lenth=0;
uint8 ReadBuff[ReadBuffsize];
uint8 img_size[10],numbuff[5];;
memset(numbuff,0,5);
ee_ReadBytes(numbuff,(uint16)STARTADDRDATA+2,1);
printf("num=%d",numbuff[0]);
memset(img_size,0,10);
ee_ReadBytes(img_size,(uint16)STARTADDRDATA,numbuff[0]);
delay_ms(10);
file_len=atoi32((char *)img_size,10);
printf("file_len=%d\r\n",(int)file_len);
make_http_response_head((unsigned char*)buf,PTYPE_JPEG, (u_long)file_len);
send(s, buf, strlen((char const*)buf));
while(file_len!=0)
{
memset(ReadBuff,0,ReadBuffsize);
lenth=ReadFlashNBtye(STARTADDR+addr,ReadBuff,ReadBuffsize);
delay_ms(5);
printf("%d",lenth);
send_len=0;
if(file_len)
{
if(file_len>1024)
{
if(getSn_SR(s)!=SOCK_ESTABLISHED)
{
return;
}
len=send(s, (uint8 *)ReadBuff, 1024);
delay_ms(5);
send_len+=len;
file_len-=len;
addr+=len;
printf("%d",lenth);
}
else
{
send(s, (uint8 *)ReadBuff, file_len);
send_len+=file_len;
file_len-=file_len;
printf("file_len=%d",(int)file_len);
}
}
}
return;
}
5 總結
該實驗其實是一個比較簡單的實驗;只要會寫簡單的HTML網頁描述語言來告訴瀏覽器執行圖片顯示以及上傳的操作,然後伺服器根據接收到的HTTP報文來選擇讀取或寫入圖片資料並將資料傳送給瀏覽器就可以了。最主要的就是我們的W5500開發板的使用,通過呼叫開發板自帶的SCOKET介面函式來接收和傳送HTTP報文,然後在呼叫解析函式解析報文再根據解析的內容選擇執行響應的操作,在W5500開發板中這些關於乙太網的介面函式都已經編寫好了,我們只需要呼叫這些函式然後將接收到的資料或者存放在記憶體的資料傳送到瀏覽器就可以了。
相關文章
- nodejs伺服器讀取圖片返回給前端(瀏覽器)顯示NodeJS伺服器前端瀏覽器
- chrome瀏覽器不能顯示本地圖片辦法解決(圖片預覽)Chrome瀏覽器地圖
- 手機瀏覽器不能顯示輪播圖或是其他圖片瀏覽器
- AXIOS從伺服器載入圖片並顯示iOS伺服器
- Windows10系統IE瀏覽器怎麼禁止顯示圖片Windows瀏覽器
- win10瀏覽器不能顯示圖片怎麼解決_win10瀏覽器圖片載入不出來怎麼辦Win10瀏覽器
- JXImageBrowser (圖片瀏覽器)瀏覽器
- win10瀏覽器看不了圖片不顯示怎麼解決Win10瀏覽器
- iOS圖片瀏覽器 - XLPhotoBrowser(類似微信多圖片瀏覽效果)iOS瀏覽器
- Win10系統搜狗瀏覽器無法顯示圖片如何解決Win10瀏覽器
- win10瀏覽器上沒有主頁圖示怎麼找回_win10瀏覽器主頁圖示如何顯示Win10瀏覽器
- iSee Pro for Mac圖片瀏覽器Mac瀏覽器
- GraphicConverter for Mac(圖片瀏覽器)Mac瀏覽器
- 幻燈片式圖片瀏覽器瀏覽器
- win7圖片只顯示圖示不顯示預覽圖解決方案Win7圖解
- 一起擼個朋友圈吧 - 圖片瀏覽(中)【圖片瀏覽器】瀏覽器
- Java上傳檔案到遠端伺服器和瀏覽器預覽圖片Java伺服器瀏覽器
- 高效圖片瀏覽器:Pixea Plus for Mac瀏覽器Mac
- GKPhotoBrowser--自定義圖片瀏覽器瀏覽器
- 圖片瀏覽器--學習筆記瀏覽器筆記
- el-image圖片預覽顯示bug
- chrome瀏覽器-Toolbar工具條不顯示Chrome瀏覽器
- 瀏覽器模擬顯示器不同解析度瀏覽器
- QLabel顯示圖片 ,並實現縮放
- 瀏覽器 Web 訪問剪下板圖片瀏覽器Web
- FotoTime Mac(圖片瀏覽管理器)Mac
- 如何實現一個圖片瀏覽器瀏覽器
- html背景圖片自適應瀏覽器HTML瀏覽器
- 谷歌瀏覽器控制檯顯示shadow DOM谷歌瀏覽器
- 瀏覽器能正常訪問圖片,但是放到img src下就無法顯示的解決方案瀏覽器
- img圖片無法顯示利用onerror事件顯示替代圖片Error事件
- FLASH PLAYER 谷歌瀏覽器瀏覽網站無法正常顯示的問題谷歌瀏覽器網站
- 從瀏覽器位址列到顯示頁面的步驟瀏覽器
- 相容所有瀏覽器的圖片上傳本地預覽效果瀏覽器
- ApolloOne for mac(圖片瀏覽工具)Mac
- Swift 3 圖片瀏覽工具Swift
- ABase ImageBrowserActivity之圖片瀏覽
- Electron為檔案瀏覽器建立圖示(三)瀏覽器