簡單的Socket實現HTTP

關於HTTP協議,可以參考:

http協議

首先直接用標準庫的net/http包

package main

import (
	"log"
	"net/http"
)

func index(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "index.html")
}

func main() {
	http.HandleFunc("/", index)
	log.Println("Now Listening...")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

Socket實現:

package main

import (
	"io/ioutil"
	"log"
	"net"
	"strconv"
	"strings"
	"time"
)

//簡單的響應結構體
type Response struct {
	net.Conn
	header map[string]string
	code   int
	status string
}

//newResponse
func NewResponse(conn net.Conn) *Response {
	return &Response{
		Conn:   conn,
		header: make(map[string]string),
	}
}

//響應消息報頭
func (this *Response) WriteHeader(key, value string) {
	this.header[key] = value
}
//響應狀態
func (this *Response) Status(code int, status string) {
	this.code = code
	this.status = status
}
//響應
func (this *Response) Write(data []byte) {
	this.Status(200, "OK")
	wheader := []byte("HTTP/1.1 " + strconv.Itoa(this.code) + " " + this.status + "\n")
	this.WriteHeader("Content-Type", "text/html")
	this.WriteHeader("Date", time.Now().Format(time.RFC1123))
	this.WriteHeader("Content-Length", strconv.Itoa(len(data)))
	for k, v := range this.header {
		wheader = append(wheader, []byte(k+":"+v+"\n")...)
	}
	wheader = append(wheader, '\n')
	log.Println(string(wheader))
	log.Println(string(data))
	this.Conn.Write(wheader)
	this.Conn.Write(data)
}
//讀取文件
func getFileContent(path string) []byte {
	data, err := ioutil.ReadFile(path)
	CheckErr("read file error:", err)
	return data
}

func CheckErr(errInfo string, err error) {
	if err != nil {
		log.Fatalln(errInfo, err.Error())
	}
}

func Handle(conn net.Conn) {
	r := ParseRequest(conn)
	w := NewResponse(conn)
	var data []byte
	if r.path[1:] != "" {
		if r.path[1:] != "favicon.ico" {
			data = getFileContent(r.path)
		} else {
			data = []byte{}
		}

	} else {
		data = getFileContent("./index.html")
	}
	w.Write(data)
	conn.Close()
}
//簡單請求結構體
type Request struct {
	method string
	path   string
	//header map[string]string
}
//解釋請求
func ParseRequest(conn net.Conn) *Request {
	rbuf := make([]byte, 1024)
	n, err := conn.Read(rbuf)
	if err != nil {
		log.Println("connection read err:", err)
		conn.Close()
	}
	rbuf = rbuf[:n]
	mindex := strings.Index(string(rbuf), "/")
	method := strings.Trim(string(rbuf[:mindex]), " ")
	path := strings.Trim(getMidStr(string(rbuf), method, "HTTP/"), " ")
	return &Request{
		method: method,
		path:   path,
	}
}

func getMidStr(str, start, end string) string {
	stIndex := strings.Index(str, start)
	if stIndex > -1 {
		endIndex := strings.Index(str, end)
		if endIndex > stIndex {
			return str[stIndex+len(start) : endIndex]
		}
	}
	return ""
}

func main() {
	ls, err := net.Listen("tcp", ":8080")
	CheckErr("listen err:", err)
	defer ls.Close()
	log.Println("Now Listening...")
	for {
		conn, err := ls.Accept()
		if err != nil {
			log.Println("Accept err:", err.Error())
			conn.Close()
			continue
		}
		go Handle(conn)
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章