GVKun编程网logo

Golang(10)Web Service - Web Socket

17

关于Golang(10)WebService-WebSocket的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于amazon-web-services–如何为WebSocket协议配置AW

关于Golang(10)Web Service - Web Socket的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于amazon-web-services – 如何为WebSocket协议配置AWS ELB和Nginx?、flex 数据传输 httpservice, webservice, RemoteObject, socket、goland 实现websocket server的示例代码、Golang websocket等相关知识的信息别忘了在本站进行查找喔。

本文目录一览:

Golang(10)Web Service - Web Socket

Golang(10)Web Service - Web Socket

Golang(10)Web Service - Web Socket

8.1 Socket
2 types of socket,TCP Socket,UDP Socket. IP,port,TCP/UDP.

8.2 WebSocket
Implement the Push Notification to browsers
https://github.com/astaxie/build-web-application-with-golang/blob/master/ebook/08.2.md

iOS and Android can support web socket too.
http://www.elabs.se/blog/66-using-websockets-in-native-ios-and-android-apps

Install the the go.net package
>go get code.google.com/p/go.net/websocket

Error Message:
go: missing Mercurial command. See http://golang.org/s/gogetcmd package code.google.com/p/go.net/websocket: exec: "hg": executable file not found in $PATH

Solution:
https://code.google.com/p/go-wiki/wiki/GoGetTools
>sudo port install mercurial

Error Message:
Error: org.macports.extract for port py27-docutils returned: command execution Failed Error: Failed to install py27-docutils
:error:extract Failed to install py27-docutils :debug:extract Couldn't open "/System/Library/Frameworks/Tcl.framework/Versions/8.5/Resources/tclIndex": no such file or directory while executing

Solution:
>sudo port clean
>sudo port selfupdate
>sudo port install py27-docutils
>sudo port install mercurial

>>go getcode.google.com/p/go.net/websocket

Follow the document,but I get these error when I try to connect to web socket server.

Error Message:
Failed: Error during WebSocket handshake: Unexpected response code: 403

Solution:
Make them the same domain name.

Go Server Side
package main

import (
"code.google.com/p/go.net/websocket"
"fmt"
"log"
"net/http"
)

func Echo(ws *websocket.Conn) {
var err error

for {
var reply string

if err = websocket.Message.Receive(ws,&reply); err != nil {
fmt.Println("Can't receive")
break
}

fmt.Println("Received back from client: " + reply)

msg := "Received: " + reply
fmt.Println("Sending to client: " + msg)

if err = websocket.Message.Send(ws,msg); err != nil {
fmt.Println("Can't send")
break
}
}
}

func main() {
http.Handle("/",http.FileServer(http.Dir(".")))
http.Handle("/socket",websocket.Handler(Echo))

if err := http.ListenAndServe("127.0.0.1:8008",nil); err != nil {
log.Fatal("ListenAndServe:",err)
}
}

HTML Client Side
<html>
<head></head>
<body>
<script type="text/javascript">
var sock = null;
var wsuri = "ws://127.0.0.1:8008/socket";

window.onload = function() {

console.log("onload");

sock = new WebSocket(wsuri);

sock.onopen = function() {
console.log("connected to " + wsuri);
}

sock.onclose = function(e) {
console.log("connection closed (" + e.code + ")");
}

sock.onmessage = function(e) {
console.log("message received: " + e.data);
}
};

function send() {
var msg = document.getElementById('message').value;
sock.send(msg);
};
</script>
<h1>WebSocket Echo Test</h1>
<form>
<p>
Message: <input id="message" type="text" value="Hello,world!">
</p>
</form>
<button onclick="send();">Send Message</button>
</body>
</html>


8.3 REST
…soon...

8.4 RCP (Remote Procedure Call Protocol)
…snip...

References:
https://github.com/astaxie/build-web-application-with-golang/blob/master/ebook/08.0.md

web socket push notification
http://html5hacks.com/blog/2013/04/21/push-notifications-to-the-browser-with-server-sent-events/
http://stackoverflow.com/questions/15884480/static-html-page-created-the-websocket-connection-golang-server-directly

amazon-web-services – 如何为WebSocket协议配置AWS ELB和Nginx?

amazon-web-services – 如何为WebSocket协议配置AWS ELB和Nginx?

我在AWS中有N层架构Web应用程序. HTTP请求流顺序由此:

> Nginx-ELB(公共ELB,代理Nginx)
> Nginx(公共子网中的EC2实例,侦听端口80,代理到AP-ELB)
> AP-ELB(内部ELB,AP-Server代理)
> AP-Server(私有子网中的EC2实例,侦听端口80)

我想将WebSocket功能应用于此体系结构.
如何配置两层ELB和Nginx后面?

解决方法:

使用另一个端口用于ws://协议,因为ELB不允许在不同模式(HTTP / TCP)中侦听相同的端口.例如:ws:// Nginx-ELB:8081 / ws-endpoint

这分为两部分解释.

Nginx部分

>在端口80上侦听HTTP,然后代理到AP-ELB端口80.
>在端口8081上侦听WebSocket,然后代理到AP-ELB端口8081.

关于WebSocket代理,您可以参考这个configuration.

配置示例如下:

# Web
server {
  listen       80;
  server_name  localhost;

  charset utf-8;

  error_log /var/log/Nginx/lnmnt/error.log error;
  access_log off;

  set $upstream_endpoint      <ap_elb_domain_name>;

  more_set_headers  'Cache-Control: max-age=0, no-cache, no-store';
  location / {
    proxy_connect_timeout       75;
    proxy_send_timeout          300;
    proxy_read_timeout          300;
    send_timeout                300;
    proxy_set_header        Host $host;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Forwarded-Host    $host;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_pass              $upstream_adm_endpoint;
  }
}

# WebSocket
server {
  listen  8081 proxy_protocol;
  server_name localhost;
  error_log /var/log/Nginx/lnmnt/websocket.error.log error;
  access_log off;
  real_ip_header proxy_protocol;

  set $upstream_ws_endpoint   <ap_elb_domain_name>:8081;

  location / {
    proxy_set_header        Host $host;
    proxy_http_version      1.1;
    proxy_set_header        Upgrade $http_upgrade;
    proxy_set_header        Connection "upgrade";
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header        X-Real-IP $remote_addr;
    proxy_set_header        X-Forwarded-Proto $scheme;
    proxy_pass              $upstream_ws_endpoint;
  }
}

ELB部分

Nginx的-ELB

创建端口转发如下​​:

> 80(HTTP)转发到80(HTTP)
> 8081(TCP)转发到8081(TCP)

然后使用您的AWS CLI执行:

aws elb create-load-balancer-policy \
  --load-balancer-name Nginx-ELB \
  --policy-name EnableProxyProtocol \
  --policy-type-name ProxyProtocolPolicyType \
  --policy-attributes AttributeName=ProxyProtocol,AttributeValue=True

aws elb set-load-balancer-policies-for-backend-server \
  --load-balancer-name Nginx-ELB \
  --instance-port 8081 \
  --policy-names EnableProxyProtocol

AP-ELB

创建端口转发如下​​:

> 80(HTTP)转发到80(HTTP)
> 8081(TCP)转发到80(TCP)

不要为此ELB应用任何负载均衡器政策!

这部分让我头疼了好几天.如果对两个ELB应用相同的策略,则永远无法获得正确的结果.

现在,使用AWS ELB和Nginx享受您的WebSocket.

flex 数据传输 httpservice, webservice, RemoteObject, socket

flex 数据传输 httpservice, webservice, RemoteObject, socket

原文地址:http://hi.baidu.com/zhao_gw/blog/item/3a4a2ac422196ba58226acd9.html

Flex数据交互方法- httpservice,webservice,RemoteObject,socket.
写在前面:
使用SOAP Web Service同Flex交互有很多好处,但是它很慢,使用定制化XML好一点,却不标准化.
那么最好的ASP.Net 和flex交互方法是什么?

1. HTTPService
实际上应该叫做XML via HTTPService,就是用get和post方式进行数据传输,同平常的web form提交大致一
样. 好处就是很简单,通用性高. 不管你用asp,jsp,还是XXP,任何可以生成标准XML的程序都可以和你的
Flex程序进行交互. 处理大量数据时,速度慢,下面是个简单的例子: 登录
http://www.helloria.com/showtopic.aspx?topicid=37&forumpage=1&page=1#53

2. WebService
通用的叫做SOAP,用datatable返回数据,没有内建的Paging功能. 不直接返回dataset. 并且大型数据交互
速度慢.
但,它是比较通用的接口,大多服务器通信都支持,不过服务器端实现起来比较复杂.

3. Remoting
基于AMF的数据交互,速度以及性能是最好的. 支持dataset和datatable,以及OR mapping工具.
Fast,reliable and secure,需要一个Flex Remoting Gateway来做数据de/seralization.
优点:
1.传输数据类型比较丰富。
2.可以支持AMF0,AMF3两种数据封装类型,AMF3是Flash Player 9或更高级才能支持,
有了AMF3,可以直接传送二进制文件流数据。

3.传输效率相对比较高。

4.对各种后台的支持也比较好。

FDS(LCDS) - 是Adobe主推的FlashRemoting服务端,功能强大(当然也支持AMF0,AMF3格式,
java和net平台都支持),质量也不错,可惜这个是需要银子的。

Blazeds - 是Adobe另外一个开源的FlashRemoting项目,基于Java平台的,支持AMF0,AMF3格式
AmfPHP - 一种基于PHP的RPC工具,支持FlashRemoting中AMF0和AMF3两种格式,开源项目。
Openamf - 一种基于Java的FlashRemoting开源项目,目前只支持AMF0格式。
GDS(Granite Data Services) - 也是一个基于Java平台的FlashRemoting项目,支持AMF3的。
WebORB - 一个支持.net,java,PHP,ruby等开发平台的FlashRemoting项目,也支持AMF0和AMF3。
FluorineFx - 一个支持.net开发平台的FlashRemoting开源项目, AMF0,AMF3,RTMP,RTMPT 。

缺点 :

1.需要后台服务端装相应版本的Flash Remoting模块才可以使用。
2.如果使用虚拟主机的话配置起来比较麻烦。

4. Socket: 没什么说的,基于socket通讯的,这也是flash和传统web开发中,通讯方式最不同的地方,socket可以建立持久连接,因此可以用来做网游,多人聊天,视频等应用。

什么是AMF? AMF0,AMF3
做Flex RIA交互的都知道有3种数据交互方式,HttpService,WebService 和remoting.
大家又公认Remoting是最有效率的方法!

那么Remoting为什么会更有效率呢,这就涉及到数据封装格式.

AMF是Adobe独家开发的数据封装格式,AMF(Action Message Format) binary format.
Remoting传输这种压缩的数据格式,而且传输的的数据还包括
ByteArray等多种形态(

參考AMF3 Specification ).

Flash可以直接访问,并且由于它是基于二进制的数据传输,所以相对于xml SOAP、json、webService等基于字符串的数据格式,有数据体积小和效率高的特点。

AMF目前有AMF0和AMF3两种格式,AMF随着ActionScript3的问世,直接从AMF0升级到 AMF3.

Flash8以前版本只支持AMF0,flash9支持两种格式。AMF3比AMF0效率更高。

goland 实现websocket server的示例代码

goland 实现websocket server的示例代码

采用go 实现的websocket,已经调试通过在此记录。

测试工具网址:https://www.idcd.com/tool/socket

在这里插入图片描述

在这里插入图片描述

话不多说上全部代码:

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"net/http"
	uuid "github.com/satori/go.uuid"
)

//Client:单个websocket
type Client struct {
	Id      string
	Socket  *websocket.Conn
	Message chan []byte
}

var clientCount   uint // 客户端数量

//从websocket中直接读取数据
func (c *Client) Read() {
	defer func() {
		//客户端关闭
		if err := c.Socket.Close(); err != nil {
			fmt.Printf("client [%s] disconnect err: %s", c.Id, err)
		}
		//关闭后直接注销客户端
		//WebsocketManager.UnRegisterClient(c)
		clientCount--
		fmt.Printf("client [%s],客户端关闭:[%s],Count [%d]\n", c.Id, websocket.CloseMessage, clientCount)
	}()

	for {
		messageType, message, err := c.Socket.ReadMessage()
		//读取数据失败
		if err != nil || messageType == websocket.CloseMessage {
			fmt.Printf("client [%s],数据读取失败或通道关闭:[%s],客户端连接状态:[%s]\n", c.Id, err.Error(), websocket.CloseMessage)
			break
		}

		// TODO 解析发送过来的参数
		//var data ReadData
		//err = json.Unmarshal(message, &data)
		//if err != nil {
		//  fmt.Println("数据解析失败")
		//	return
		//}

		// TODO 前端请求返回数据到指定客户端

		// 简单测试
		c.Message <- message


	}
}

//写入数据到websocket中
func (c *Client) Write() {
	defer func() {
		//客户端关闭
		if err := c.Socket.Close(); err != nil {
			fmt.Printf("client [%s] disconnect err: %s \n", c.Id, err)
			return
		}
		//关闭后直接注销客户端
		//WebsocketManager.UnRegisterClient(c)
		clientCount--
		fmt.Printf("client [%s],客户端关闭:[%s]\n", c.Id, websocket.CloseMessage)
	}()

	for {
		select {
		case message, ok := <-c.Message:

			if !ok {
				//数据写入失败,关闭通道
				fmt.Printf("client [%s],客户端连接状态:[%s]\n", c.Id, websocket.CloseMessage)
				_ = c.Socket.WriteMessage(websocket.CloseMessage, []byte{})
				//消息通道关闭后直接注销客户端
				return
			}

			err := c.Socket.WriteMessage(websocket.TextMessage, message)
			if err != nil {
				fmt.Printf("client [%s] write message err: %s \n", c.Id, err)
				return
			}
		}
	}
}


// 方法二: 通过对象创建  客户端连接
func WsClient(context *gin.Context) {
	upGrande := websocket.Upgrader{
		//设置允许跨域
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
		//设置请求协议
		Subprotocols: []string{context.GetHeader("Sec-WebSocket-Protocol")},
	}
	//创建连接
	conn, err := upGrande.Upgrade(context.Writer, context.Request, nil)
	if err != nil {
		fmt.Printf("websocket connect error: %s", context.Param("channel"))
		//format.NewResponseJson(context).Error(51001)
		return
	}
	//生成唯一标识client_id
	var uuid = uuid.NewV4().String()
	client := &Client{
		Id:      uuid,
		Socket:  conn,
		Message: make(chan []byte, 1024),
	}
	//注册
	//ws.WebsocketManager.RegisterClient(client)
	clientCount++

	//起协程,实时接收和回复数据
	go client.Read()
	go client.Write()
}

// 方法一: 直接创建客户端
func NewConnection(c *gin.Context) {
	// 定义同源检查,这里只作简单试验不校验
	upGrader := websocket.Upgrader{
	   CheckOrigin: func(r *http.Request) bool {
	       return true
	   },
	}
	 ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
	//ws, err := websocket.Upgrade(c.Writer, c.Request, nil, 1024, 1024)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"msg": "服务端错误",
		})
		return
	}


	var message = make(chan []byte)

	go func() {
		defer ws.Close()

		for {
			fmt.Println("start transfer message")
			msgType, msg, err := ws.ReadMessage()
			if err != nil || websocket.CloseMessage == msgType {
				fmt.Println("webSocket read error")
				return
			}
			message <- msg
		}

	}()

	go func() {
		defer ws.Close()

		for {
			mm, ok := <- message

			if !ok {
				//数据写入失败,关闭通道
				fmt.Printf("客户端连接状态:[%s]\n", websocket.CloseMessage)
				_ = ws.WriteMessage(websocket.CloseMessage, []byte{})
				//消息通道关闭后直接注销客户端
				return
			}

			err := ws.WriteMessage(websocket.TextMessage, mm)
			if err != nil {
				fmt.Println("webSocket write error")
				return
			}
		}
	}()

	//for {
	//
	//}

	 开始通信
	//for {
	//	fmt.Println("start transfer message")
	//	msgType, msg, err := ws.ReadMessage()
	//	if err != nil {
	//		fmt.Println("webSocket read error")
	//		return
	//	}
	//	err = ws.WriteMessage(msgType, msg)
	//	if err != nil {
	//		fmt.Println("webSocket write error")
	//		return
	//	}
	//}
}

// ws://127.0.0.1:9090/wsTest
func main() {
	r := gin.Default()

	// 方法一: 直接创建客户端
	r.GET("/wsTest", NewConnection)
	// 方法二: 通过对象创建  客户端连接
	r.GET("/wsTest1", WsClient)

	clientCount = 0
	r.Run("127.0.0.1:9090")
}

拷贝全部代码到工程即可测试。

到此这篇关于goland 实现websocket server的示例代码的文章就介绍到这了,更多相关goland 实现websocket server内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

您可能感兴趣的文章:
  • go的websocket实现原理与用法详解
  • Go 实现百万WebSocket连接的方法示例
  • 利用Go语言搭建WebSocket服务端方法示例
  • golang基于websocket实现的简易聊天室程序
  • 利用 Go 语言编写一个简单的 WebSocket 推送服务
  • golang websocket 服务端的实现
  • Golang使用WebSocket通信的实现
  • 使用Go语言创建WebSocket服务的实现示例

Golang websocket

Golang websocket

环境:Win10 + Go1.9.2

1. 先下载并引用 golang 的 websocket 库

①golang 的官方库都在 https://github.com/golang 下,而 websocket 库在 /net 下。

②如果没有安装 Git,需要先安装 Git。

③使用 go get -u github.com/golang/net/websocket 下载代码,将安装在环境变量 GOPATH 配置的路径中。

代码中使用路径为 "golang.org/x/net/websocket",在对应路径下没有代码的话则引用出错,可将对应代码放在 GOPAHT/golang.org/x/net 下。

2. 服务端 Go 代码

package main

import (
    "fmt"
    "golang.org/x/net/websocket"
    "net/http"
    "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 *websocket.Conn) {
    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() {
    http.Handle("/echo", websocket.Handler(svrConnHandler));
    err := http.ListenAndServe(":6666", nil);
    checkErr(err, "ListenAndServe");
    fmt.Println("Func finish.");
}

 PS:《Golang socket》中使用了 go coroutine 来处理 connection 的消息阻塞接收,websocket 不需要进行这样的处理,否则将报 use of closed network connection 的错误!

 3.

①客户端 Go 代码

package main

import (
    "fmt"
    "golang.org/x/net/websocket"
    "os"
    "sync"
)

var gLocker sync.Mutex;    //全局锁
var gCondition *sync.Cond; //全局条件变量

var origin = "http://127.0.0.1:6666/"
var url = "ws://127.0.0.1:6666/echo"

//错误处理函数
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 *websocket.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() {
    conn, err := websocket.Dial(url, "", origin);
    if checkErr(err, "Dial") {
        return;
    }

    gLocker.Lock();
    gCondition = sync.NewCond(&gLocker);
    _, err = conn.Write([]byte("Hello !"));
    go clientConnHandler(conn);

    //主线程阻塞,等待Singal结束
    for {
        //条件变量同步等待
        gCondition.Wait();
        break;
    }
    gLocker.Unlock();
    fmt.Println("Client finish.")
}

②如果客户端不使用 Go 代码,可以使用 Cocos Creator 的 js 代码

cc.Class({
    extends: cc.Component,

    properties: {

    },

    ctor: function () {
        this.ws = null;
    },

    onLoad: function () {
        var self = this;

        this.ws = new WebSocket("ws://127.0.0.1:6666/echo");
        this.ws.onopen = function (event) {

            console.log("Send Text WS was opened.");

            if (self.ws.readyState === WebSocket.OPEN) {
                self.ws.send("Hello !");
            }
            else{
                console.log("WebSocket instance wasn''t ready...");
            }
        };

        this.ws.onmessage = function (event) {
            console.log("response text msg: " + event.data);
            self.ws.send("Hello !");
        };

        this.ws.onerror = function (event) {
            console.log("Send Text fired an error");
        };

        this.ws.onclose = function (event) {
            console.log("WebSocket instance closed.");
        };

    },

    // called every frame
    update: function (dt) {

    },
});

今天关于Golang(10)Web Service - Web Socket的分享就到这里,希望大家有所收获,若想了解更多关于amazon-web-services – 如何为WebSocket协议配置AWS ELB和Nginx?、flex 数据传输 httpservice, webservice, RemoteObject, socket、goland 实现websocket server的示例代码、Golang websocket等相关知识,可以在本站进行查询。

本文标签: