如何用NASM汇编写一个静态资源服务器?(三)、发布到服务器测试

147 阅读4分钟

前言

前两节中我们已经完成了多进程设计,但还是有个bug,那就是只能读取40960字节,所以本章来完善一下,这部分很好设计,可是当初写的有点繁琐了,再者也想分好几章来记录。

但还有个不足的地方,我们的服务器不会返回Content-Length,意味着浏览器在进行下载时,不会显示进度,他只能尝试一直读取,直到对方断开连接后,会视为下载成功,

看下完整代码

%include "/home/HouXinLin/project/nasm/include/io.inc"

SECTION .data
notfound_response db 'HTTP/1.1 404 OK', 0Dh, 0Ah, 'Content-Type: text/html', 0Dh, 0Ah, 'Content-Length: 10', 0Dh, 0Ah, 0Dh, 0Ah, 'not found!', 0Dh, 0Ah, 0h
headers db 'HTTP/1.1 200 OK', 0Dh, 0Ah, 'Content-Type: application/octet-stream', 0Dh, 0Ah, 0Dh, 0Ah

root db '/home/HouXinLin/test', 0h

msg db 'accept',0h

ok db 'ok',0h

fail db 'fail',0h

SO_REUSEADDR db 1,0h

SECTION .bss

fileContents resb 40960

responseBuffer resb 40960

requestBuffer resb 4096

fullPath resb 1024

requestPath resb 1024

socketbuf resb 4


SECTION .text

global CMAIN

CMAIN:

    mov ebp, esp

    xor eax, eax

    xor ebx, ebx

    xor edi, edi

    xor esi, esi

socket:

    push byte 6

    push byte 1

    push byte 2

    mov ecx, esp

    mov ebx, 1

    mov eax, 102

    int 80h ;;创建Socket

bind:

    push eax

    mov edi,4

    mov esi,SO_REUSEADDR

    mov edx,2

    mov ecx,1

    mov ebx,eax

    mov eax,366

    int 80h

    pop eax

    mov edi, eax ;;edi存放server socket描述副

    push dword 0x00000000

    push word 0x901f ;;端口8080

    push word 2

    mov ecx, esp

    push byte 16

    push ecx

    push edi

    mov ecx, esp

    mov ebx, 2

    mov eax, 102

    int 80h ;;绑定8080端口

    cmp eax,0

    je listen

    jmp exit

listen:

    push byte 1

    push edi

    mov ecx, esp

    mov ebx, 4

    mov eax, 102

    int 80h ;监听

accept:

    push byte 0

    push byte 0

    push edi

    mov ecx, esp

    mov ebx, 5

    mov eax, 102

int 80h

    mov esi, eax ;;将客户端描述符保存到esi中


    mov eax, 2

    int 80h

    cmp eax, 0

    jz read

    jmp accept

read:

    mov edx,6

    mov ecx,msg

    mov ebx,1

    mov eax,4

    int 80h

    mov edx, 4096 ;;读取客户端内容

    mov ecx, requestBuffer

    mov ebx, esi

    mov eax, 3

    int 80h


getRequestResourcePath: ;;获取请求资源路径

    mov eax,requestBuffer

    mov ebx,eax

    nextResourceChar:

    cmp byte[ebx],32 ;;如果是空格

    jz record ;;开始记录

    inc ebx ;;下一个字符

    jmp nextResourceChar

    ret

record:

    mov edx,ebx ;;ebx是第一个空格后的位置

    sub edx,eax ;存放开始索引

    mov ecx, requestBuffer

    add ecx,edx ;;从ecx后的位置开始查看地一个空格

    mov edx,0

hasEnd:

    inc ecx

    cmp byte[ecx],32 ;;如果下一个也是空格

    jz finishSearch

    mov eax, dword[ecx] ;;获取当前字符

    mov dword[requestPath+edx],eax

    inc edx

    jmp hasEnd

finishSearch:

    push esi

    mov esi,root

    mov edi,fullPath

    mov ecx,20

    rep movsb ;;复制root

    mov esi,requestPath

    mov edi,fullPath

    add edi,20

    mov ecx,edx

    rep movsb

    pop esi


openFile:

    mov ecx, 4 ;;打开文件

    mov ebx, fullPath

    mov eax, 5

    int 80h
    cmp eax,0

    jl notfound
    push eax ;;保存文件描述符


write:


    mov edx,59

    mov ecx, headers ;;输出头

    mov ebx, esi

    mov eax, 4

    int 80h

hasNext:

    pop eax ;;文件描述符传递给readFile

    push eax

    call readFile ;;调用之后eax保存读取的大小,fileContents保存文件内容

    push eax

    mov edx,eax

    mov ecx, fileContents ;;输出内容

    mov ebx, esi

    mov eax, 4

    int 80h

    pop eax ;;读取的文件字节数

    cmp eax,0

    jz closeSocket

    jmp hasNext
    
notfound:

    mov edx,76

    mov ecx, notfound_response 

    mov ebx, esi

    mov eax, 4

    int 80h
closeSocket:

    ;;关闭客户端socket


    push 2

    push esi

    mov ecx, esp

    mov ebx, 13

    mov eax, 102

    int 80h

    cmp eax,0

    jz exit

    mov edx,4

    mov ecx,fail

    mov ebx,1

    mov eax,4

    int 80h

    jmp exit

readFile:

    mov edx, 40960 ;;尝试读取40960个字节到fileContents

    mov ecx, fileContents

    mov ebx, eax

    mov eax, 3

    int 80h ;读取

    ret

exit:

    mov ebx,0

    mov eax,1

    int 80h

没有多大改动,只是调整了原本的执行流程,先发送59字节的头信息,然后不停尝试读取文件,当读取不到文件内容时,将在eax中返回0,所以在下面我们判断一下,如果成立,则关闭socket,否则返回去继续读取。

cmp eax,0

jz closeSocket

jmp hasNext

还有一个就是当打开文件失败时,eax是一个负数,通过jl判断如果小于的话,直接返回not found

cmp eax,0

jl notfound

push eax 

通过下面命令生成一个可执行文件。

nasm -f elf socket.asm 
ld -m elf_i386 socket.o -o socket

通过cooldesktop工具上传,并且执行,就可以测试了