Golang socket

chevin · · 1208 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

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.结果截图

 

以上。

 


有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:chevin

查看原文:Golang socket

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1208 次点击  
加入收藏 微博
上一篇:Golang atomic
下一篇:Golang sync
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传