package mainimport ( "fmt" "net" "os")type Mail struct { clientName string from string to string data string reciveData bool}func main() { listen, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("127.0.0.1"), 25, ""}) if err != nil { fmt.Println("監聽連接埠失敗:", err.Error()) return } defer listen.Close() recive(listen)}func recive(listen *net.TCPListener) { for { conn, err := listen.AcceptTCP() //接收串連 defer conn.Close() if err != nil { fmt.Println("用戶端串連異常", err.Error()) //用戶端串連異常 continue } conn.Write([]byte("220 GoMailSever ")) fmt.Println("新用戶端", conn.RemoteAddr().String()) go func() { tmpBuffer := make([]byte, 0) //建立待處理位元組切片 readerChannel := make(chan []byte, 16) //建立channel通訊管道 _mail := &Mail{} go reader(readerChannel, conn, _mail) //channel資訊接收端 data := make([]byte, 1024) //建立輸出緩衝切片 for { i, err := conn.Read(data) //從Socket讀取資料 if err != nil { fmt.Println("讀取發生錯誤", err.Error()) //讀取失敗發生錯誤 return } tmpBuffer = DepackMail(append(tmpBuffer, data[:i]...), readerChannel) //用自訂協議處理位元組 //fmt.Println(data, string(data)) } }() }}func reader(readerChannel chan []byte, conn *net.TCPConn, _mail *Mail) { for { select { case data := <-readerChannel: fmt.Println(string(data[0:4])) switch string(data[0:4]) { case "HELO": _mail.clientName = string(data[4+2:]) conn.Write([]byte("250 Give Me Mail")) break case "MAIL": _mail.from = string(data[4+2:]) conn.Write([]byte("250 Give I am fine")) break case "RCPT": _mail.to = string(data[4+2:]) conn.Write([]byte("250 Give I am fine")) break case "DATA": conn.Write([]byte("354 Give I am fine")) break case "QUIT": conn.Write([]byte("221 ByeBye")) file, _ := os.Create("./mail/3.eml") file.WriteString(_mail.data) file.Close() fmt.Println(_mail) break default: _mail.data = _mail.data + string(data) fmt.Println(string(_mail.data[len(_mail.data)-1:])) if string(_mail.data[len(_mail.data)-1:]) == "." { fmt.Println("111") conn.Write([]byte("250 Give I am fine")) } break } } }}func DepackMail(buffer []byte, readerChannel chan []byte) []byte { length := len(buffer) var i int for i = 0; i < length; { if length < i+4 { //2位為尾標記 break } var sIndex int for dump := i; dump < length-1; dump++ { if buffer[dump] == byte(13) && buffer[dump+1] == byte(10) { sIndex = dump } } if sIndex <= 0 { break } data := buffer[i:sIndex] readerChannel <- data //向管道發送資料 i = sIndex + 2 } if i == length { //全部處理完畢返回空包 return make([]byte, 0) } return buffer[i:] //未處理完畢返回 剩餘包}