第二十七篇:socket练习(1):实现浏览器静态文件的访问、处理404
一:代码格式整理:先将服务端代码中响应浏览器的代码函数 拎出来放到服务端包中

二:代码
服务端代码:

package main
import (
"fmt"
"net"
"runtime"
"time"
)
func main() {
lis,err:=net.Listen("tcp","127.0.0.1:8099")
if err !=nil{
fmt.Println(err.Error())
return
}
defer lis.Close()
fmt.Println("创建监听成功,等待客户端连接")
go func() {
//写一个死循环每两秒进行打印输出
for {
fmt.Printf("当前任务数:%d\n",runtime.NumGoroutine())
time.Sleep(time.Second*2)
}
}()
for {
client,err:=lis.Accept()
if err !=nil{
fmt.Println(err.Error())
return
}
/* 每当有客户端连接的时候,就开一个协程
改造代码很简单,直接加上 go 即可以;*/
go func(c net.Conn){
defer c.Close()
buf:=make([]byte,4096)
//服务端读
n,err:=c.Read(buf)
if err !=nil{
fmt.Println(err.Error())
return
}
/* if GetRequestPath(string(buf[0:n]))=="/delay"{
time.Sleep(time.Second*5)
}*/
//服务端发送
c.Write([]byte(response(ReadHtml(GetRequestPath(string(buf[:n]))))))
}(client)
}
}
包中代码:

package main
import (
"fmt"
"io/ioutil"
"os"
"regexp"
)
func GetRequestPath(rq string) string{
r:=regexp.MustCompile(`GET\s(.*?)\sHTTP`)
if r.MatchString(rq){
return r.FindStringSubmatch(rq)[1]
}else {
return "/"
}
}
func response(body []byte)string{
str:=`HTTP/1.1 200 OK
Server:myServer
Content-Type:text/html
%s
`
/*
%s为占位符 可以将传递的body,
无论是字符还是切片都可以进行格式化;
*/
ret:=fmt.Sprintf(str,body)
return ret
}
//判断文件是否存在
func ExistsFile(path string) (bool,error){
//os.Stat(path) path可以是绝对路径,也可以是相对路径返回文件相关信息;
_,err:=os.Stat("./web"+path)
if err==nil{
return true,nil
}else {
//os.IsNotExist 判断不存在
if os.IsNotExist(err){
return false,err
}else{//其它错误(比如权限不足等)
return false,err
}
}
}
//如果文件存在则读取
func ReadHtml(path string)[]byte{
exist,_:=ExistsFile(path)
if exist{
//这里可以使用ioutil.ReadAll也可以使用ioutil.ReadFile
//如果使用ioutil.ReadAll需要使用os.OPen先把文件给打开;
file,_:=ioutil.ReadFile("./web"+path)
return file
}else {
return []byte("404")
}
}
默认首页:

浏览器请求如下:

这里404的状态码有问题,如下:

整体代码修改优化如下:
(1):定义状态码结构体

(2):服务端代码:
package main
import (
"fmt"
"net"
"runtime"
"time"
)
func main() {
lis,err:=net.Listen("tcp","127.0.0.1:8099")
if err !=nil{
fmt.Println(err.Error())
return
}
defer lis.Close()
fmt.Println("创建监听成功,等待客户端连接")
go func() {
//写一个死循环每两秒进行打印输出
for {
fmt.Printf("当前任务数:%d\n",runtime.NumGoroutine())
time.Sleep(time.Second*2)
}
}()
for {
client,err:=lis.Accept()
if err !=nil{
fmt.Println(err.Error())
return
}
/* 每当有客户端连接的时候,就开一个协程
改造代码很简单,直接加上 go 即可以;*/
go func(c net.Conn){
defer c.Close()
buf:=make([]byte,4096)
//服务端读
n,err:=c.Read(buf)
if err !=nil{
fmt.Println(err.Error())
return
}
/* if GetRequestPath(string(buf[0:n]))=="/delay"{
time.Sleep(time.Second*5)
}*/
//服务端发送
c.Write([]byte(ReadHtml(GetRequestPath(string(buf[:n])))))
}(client)
}
}
(3):netutil包函数
package main
import (
"fmt"
"io/ioutil"
"os"
"regexp"
)
func GetRequestPath(rq string) string{
r:=regexp.MustCompile(`GET\s(.*?)\sHTTP`)
if r.MatchString(rq){
return r.FindStringSubmatch(rq)[1]
}else {
return "/"
}
}
func response(body []byte,status HttpStatus)string{
str:=`HTTP/1.1 %d %s
Server:myServer
Content-Type:text/html
%s
`
/*
%s为占位符 可以将传递的body,
无论是字符还是切片都可以进行格式化;
*/
ret:=fmt.Sprintf(str,status.Code,status.Message,body)
return ret
}
//判断文件是否存在
func ExistsFile(path string) (bool,error){
//os.Stat(path) path可以是绝对路径,也可以是相对路径返回文件相关信息;
_,err:=os.Stat("./web"+path)
if err==nil{
return true,nil
}else {
//os.IsNotExist 判断不存在
if os.IsNotExist(err){
return false,err
}else{//其它错误(比如权限不足等)
return false,err
}
}
}
//如果文件存在则读取
func ReadHtml(path string)string{
exist,_:=ExistsFile(path)
if exist{
//这里可以使用ioutil.ReadAll也可以使用ioutil.ReadFile
//如果使用ioutil.ReadAll需要使用os.OPen先把文件给打开;
file,_:=ioutil.ReadFile("./web"+path)
response(file,NewHttpStatus(200,"ok"))
}else {
response([]byte("404"),NewHttpStatus(404,"Not Found"))
}
}
浏览器请求如下:


浙公网安备 33010602011771号