golang long-polling 长轮训

2014-06-12 11:17  1992人阅读  评论 (0)

go

package main

import (
    "fmt"
    "io"
    "net/http"
    "log"
    "time"
    "strconv"
    "encoding/json"
)

var mc *MessageCenter

type Message struct {
    Uid int
    Message string
}

type MessageCenter struct {
    // 测试 没有加读写锁
    messageList []*Message
    userList map[int]chan string
}

func NewMessageCenter() *MessageCenter {
    mc := new(MessageCenter)
    mc.messageList = make([]*Message, 0, 100)
    mc.userList = make(map[int]chan string)
    return mc
}

func (mc *MessageCenter) GetMessage(uid int) []string {
    messages := make([]string, 0, 10)
    for i, msg := range mc.messageList {
        if msg == nil {
            continue
        }
        if msg.Uid == uid {
            messages = append(messages, msg.Message)
            // 临时方案 只是测试用 应更换为list
            mc.messageList[i] = nil
        }
    }
    return messages
}

func (mc *MessageCenter) GetMessageChan(uid int) <- chan string {
    messageChan := make(chan string)
    mc.userList[uid] = messageChan
    return messageChan
}

func (mc *MessageCenter) SendMessage(uid int, message string) {
    messageChan, exist := mc.userList[uid]
    if exist {
        messageChan <- message
        return
    }
    // 未考虑同一账号多登陆情况
    mc.messageList = append(mc.messageList, &Message{uid, message})
}

func (mc *MessageCenter) RemoveUser(uid int) {
    _, exist := mc.userList[uid]
    if exist {
        delete(mc.userList, uid)
    }
}

func IndexServer(w http.ResponseWriter, req *http.Request) {
    http.ServeFile(w, req, "longpoll.html")
}

func SendMessageServer(w http.ResponseWriter, req *http.Request) {
    uid, _ := strconv.Atoi(req.FormValue("uid"))
    message := req.FormValue("message")

    mc.SendMessage(uid, message)

    io.WriteString(w, `{}`)
}

func PollMessageServer(w http.ResponseWriter, req *http.Request) {
    uid, _ := strconv.Atoi(req.FormValue("uid"))

    messages := mc.GetMessage(uid)

    if len(messages) > 0 {
        jsonData, _ := json.Marshal(map[string]interface{}{"status":0, "messages":messages})
        w.Write(jsonData)
        return
    }

    messageChan := mc.GetMessageChan(uid)

    select {
    case message := <- messageChan:
        jsonData, _ := json.Marshal(map[string]interface{}{"status":0, "messages":[]string{message}})
        w.Write(jsonData)
    case <- time.After(10 * time.Second):
        mc.RemoveUser(uid)
        jsonData, _ := json.Marshal(map[string]interface{}{"status":1, "messages":nil})
        n, err := w.Write(jsonData)
        fmt.Println(n, err)
    }
}

func main() {
    fmt.Println("http://127.0.0.1:8080/")

    mc = NewMessageCenter()

    http.HandleFunc("/", IndexServer)
    http.HandleFunc("/sendmessage", SendMessageServer)
    http.HandleFunc("/pollmessage", PollMessageServer)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

html

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>long-polling</title>
    <style type="text/css">
        .msg {padding: 10px;margin-bottom: 10px;border: 1px solid #ccc;border-radius: 8px;}
    </style>
    <script type="text/javascript" src="http://www.v2ex.com/static/js/jquery.js"></script>
    <script type="text/javascript">
        $(function () {
            $('#uid').val(Date.now() % 10000);
            var setTimeoutId = 0;
            var ajax = null;
            var getmessage = function() {
                var data = {uid:$('#uid').val()};
                ajax = $.getJSON('/pollmessage', data, function(resp) {
                    if (resp.status == 0) {
                        for (var i = 0; i < resp.messages.length; i++) {
                            $('#messagelist').append('<div class="msg">'+resp.messages[i]+'</div>');
                        };
                    }
                    if (setTimeoutId > 0) {
                        setTimeoutId = setTimeout(getmessage, 3000);
                    }
                });
                console.dir(ajax);
            };
            $('#getmessagebtn').click(function(){
                this.disabled = true;
                setTimeoutId = setTimeout(getmessage, 10);
            });
            $('#sendmessagebtn').click(function(){
                var data = {uid:$('#senduid').val(), 'message':$('#message').val()};
                $.post('/sendmessage', data, function(resp){}, 'json');
            });
            $('#stopgetmessagebtn').click(function(){
                clearTimeout(setTimeoutId);
                setTimeoutId = 0
                if (ajax != null) {
                    ajax.abort();
                }
                $('#getmessagebtn').prop('disabled', false);
            });
        });
    </script>
</head>
<body>
Send User ID: <input type="number" id="senduid" /> Message: <input type="text" id="message" /> <button id="sendmessagebtn">发送消息</button>
<hr/>
RecvUser ID: <input type="number" id="uid" /> <button id="getmessagebtn">接收消息</button> <button id="stopgetmessagebtn">停止接收消息</button>
<div id="messagelist"></div>
</body>
</html>
2015-11-25 12:49 UlricQin
有没有地方可以看到这个站点的所有文章列表?只看标题,这样我可以快速获取信息。