1.本例子实现了一个简单的TCP echo。客户端发送Hello,服务端回应World。
参考:《Socket编程》
2.服务端代码
package main import ( "net"
"fmt"
"os"
"time" ) //错误处理函数
func checkErr(err error, extra string) bool { if err != nil { formatStr := " Err : %s\n"; if extra != "" { formatStr = extra + formatStr; } fmt.Fprintf(os.Stderr, formatStr, err.Error()); return true; } return false; } //连接处理函数
func svrConnHandler(conn net.Conn) { fmt.Println("Client connect success :", conn.RemoteAddr().String()); conn.SetReadDeadline(time.Now().Add(2 * time.Minute)) request := make([]byte, 128); defer conn.Close(); for { readLen, err := conn.Read(request) if checkErr(err, "Read") { break; } //socket被关闭了
if readLen == 0 { fmt.Println("Client connection close!"); break; } else { //输出接收到的信息
fmt.Println(string(request[:readLen])) time.Sleep(time.Second); //发送
conn.Write([]byte("World !")); } request = make([]byte, 128); } } func main() { //解析地址
tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:6666"); if checkErr(err, "ResolveTCPAddr") { return; } //设置监听地址
listener, err := net.ListenTCP("tcp", tcpAddr); if checkErr(err, "ListenTCP") { return; } for { //监听
fmt.Println("Start wait for client.") conn, err := listener.Accept(); if checkErr(err, "Accept") { continue; } //消息处理函数
go svrConnHandler(conn); } }
3.客户端代码
package main import ( "fmt"
"os"
"net"
"sync" ) var gLocker sync.Mutex; //全局锁
var gCondition *sync.Cond; //全局条件变量 //错误处理函数
func checkErr(err error, extra string) bool { if err != nil { formatStr := " Err : %s\n"; if extra != "" { formatStr = extra + formatStr; } fmt.Fprintf(os.Stderr, formatStr, err.Error()); return true; } return false; } //连接处理函数
func clientConnHandler(conn net.Conn) { gLocker.Lock(); defer gLocker.Unlock(); defer conn.Close(); request := make([]byte, 128); for { readLen, err := conn.Read(request) if checkErr(err, "Read") { gCondition.Signal(); break; } //socket被关闭了
if readLen == 0 { fmt.Println("Server connection close!"); //条件变量同步通知
gCondition.Signal(); break; } else { //输出接收到的信息
fmt.Println(string(request[:readLen])) //发送
conn.Write([]byte("Hello !")); } request = make([]byte, 128); } } func main() { //解析地址
tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:6666"); if checkErr(err, "ResolveTCPAddr") { return; } conn, err := net.DialTCP("tcp", nil, tcpAddr); if checkErr(err, "DialTCP") { return; } fmt.Println("Connect server success.") gLocker.Lock(); gCondition = sync.NewCond(&gLocker); //发送数据给服务器
conn.Write([]byte("Hello !")); //处理连接(lock在上面调用了,所以clientConnHandler函数必须等wait函数调用后才能lock,这样就能保证调用的先后顺序)
go clientConnHandler(conn); //主线程阻塞,等待Singal结束
for { //条件变量同步等待
gCondition.Wait(); break; } gLocker.Unlock(); fmt.Println("Client finish.") }
PS:关于sync.Cond可以参考下一篇文章:《Golang sync》
4.结果截图
以上。