Socket服務(wù)器是網(wǎng)絡(luò)服務(wù)中常用的服務(wù)器。使用 go 語言實(shí)現(xiàn)這個(gè)業(yè)務(wù)場景是很容易的搁拙。
這樣的網(wǎng)絡(luò)通訊秒梳,需要一個(gè)服務(wù)端和至少一個(gè)客戶端。
我們計(jì)劃構(gòu)建一個(gè)這樣的通訊過程箕速。服務(wù)端啟動(dòng)后等待客戶端的訪問酪碘。客戶端發(fā)送一段信息給服務(wù)端盐茎。服務(wù)端接收信息后兴垦,再回饋給客戶端一段信息。
首先要建立服務(wù)端庭呜。
服務(wù)端最先要做的事情就是“建立Socket端口監(jiān)聽”
netListen, err := net.Listen("tcp", "localhost:1024")
這樣代碼滑进,表明監(jiān)聽的本機(jī)端口是 1024,而使用的通訊協(xié)議是 TCP募谎。
當(dāng)監(jiān)聽結(jié)束扶关,模塊任務(wù)完成時(shí),最后要close這個(gè)netListen
defer netListen.Close()
使用日志功能数冬,讓服務(wù)端窗口能看到服務(wù)已經(jīng)運(yùn)行了节槐。
Log("Waiting for clients ...")
之后使用一個(gè) for 循環(huán),無盡的等待那些不知何時(shí)來訪問的客戶端信息拐纱。
for 循環(huán)體內(nèi)铜异,要監(jiān)聽 netListen 的信息接收情況
conn, err := netListen.Accept()
當(dāng)有來自客戶端的訪問時(shí),接收訪問秸架。并且在服務(wù)端的日志記錄已經(jīng)有客戶端連接成功了揍庄。
Log(conn.RemoteAddr().String(), "tcp connect success")
conn.RemoteAddr().String() 表示的就是遠(yuǎn)程客戶端。
然后东抹,我們開啟一個(gè) goroutine 處理連接任務(wù)蚂子。
go handleConnection(conn)
處理過程就是接收客戶端信息和反饋給客戶端信息
n, err := conn.Read(buffer)
conn.Write([]byte(strTemp))
服務(wù)端代碼示例:
package main
import (
"net"
"fmt"
"os"
"log"
"time"
)
func main() {
//建立socket端口監(jiān)聽
netListen, err := net.Listen("tcp", "localhost:1024")
CheckError(err)
defer netListen.Close()
Log("Waiting for clients ...")
//等待客戶端訪問
for{
conn, err := netListen.Accept() //監(jiān)聽接收
if err != nil{
continue //如果發(fā)生錯(cuò)誤,繼續(xù)下一個(gè)循環(huán)缭黔。
}
Log(conn.RemoteAddr().String(), "tcp connect success") //tcp連接成功
go handleConnection(conn)
}
}
//處理連接
func handleConnection(conn net.Conn) {
buffer := make([]byte, 2048) //建立一個(gè)slice
for{
n, err := conn.Read(buffer) //讀取客戶端傳來的內(nèi)容
if err != nil{
Log(conn.RemoteAddr().String(), "connection error: ", err)
return //當(dāng)遠(yuǎn)程客戶端連接發(fā)生錯(cuò)誤(斷開)后食茎,終止此協(xié)程。
}
Log(conn.RemoteAddr().String(), "receive data string:\n", string(buffer[:n]))
//返回給客戶端的信息
strTemp := "CofoxServer got msg \""+string(buffer[:n])+"\" at "+time.Now().String()
conn.Write([]byte(strTemp))
}
}
//日志處理
func Log(v ...interface{}) {
log.Println(v...)
}
//錯(cuò)誤處理
func CheckError(err error) {
if err != nil{
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
}
}
客戶端的業(yè)務(wù)邏輯是馏谨,發(fā)送信息給服務(wù)端别渔,然后接收服務(wù)端的反饋。
conn, err := net.DialTCP("tcp", nil, tcpAddr)
用 TCP 協(xié)議撥號(hào)(Dial)到服務(wù)端。如果沒有發(fā)生錯(cuò)誤哎媚,就說明撥通了喇伯。于是在客戶端日志記錄連接成功
fmt.Println("connection success")
然后在這個(gè)已經(jīng)通暢的連接里,進(jìn)行發(fā)送和接收信息的任務(wù)抄伍。
conn.Write([]byte(words)) 是發(fā)送信息
conn.Read(buffer) 是接收信息
如果接收發(fā)生錯(cuò)誤艘刚,就記錄錯(cuò)誤
Log(conn.RemoteAddr().String(), "waiting server back msg error: ", err)
并且中斷進(jìn)程管宵。
如果沒有發(fā)生錯(cuò)誤截珍,就把接收到的信息在日志中記錄。
Log(conn.RemoteAddr().String(), "receive server back msg: ", string(buffer[:n]))
客戶端代碼示例:
package main
import (
"net"
"fmt"
"log"
"os"
)
//發(fā)送信息
func sender(conn net.Conn) {
words := "Hello Server!"
conn.Write([]byte(words))
fmt.Println("send over")
//接收服務(wù)端反饋
buffer := make([]byte, 2048)
n, err := conn.Read(buffer)
if err != nil {
Log(conn.RemoteAddr().String(), "waiting server back msg error: ", err)
return
}
Log(conn.RemoteAddr().String(), "receive server back msg: ", string(buffer[:n]))
}
//日志
func Log(v ...interface{}) {
log.Println(v...)
}
func main() {
server := "127.0.0.1:1024"
tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
fmt.Println("connection success")
sender(conn)
}