如何使用Go和gorilla websocket仅发送给一个客户端,而不是所有客户端

我正在尝试使用Go学习网络套接字。 我一直在看大猩猩websocket的示例。</ p>

我已经查看了这两个示例,展示了如何使用大猩猩websocket:</ p>

https://github.com/gorilla/websocket/tree/master/examples </ p >

https://www.youtube.com/watch?v=ysAZ_oqPOo0 </ p>

所有这些示例都展示了如何连接到Websocket服务器,发送和接收文本。 但是我不明白的是,如何只能发送给一个客户。 因为在真实的应用程序中您将拥有用户,所以我们不希望所有用户都收到相同的消息和相同的数据。 有没有办法让我获取一个连接的唯一ID,我可以将其保存在像redis这样的数据库中,并将其链接到同一数据库中的用户ID,然后使用该websocket ID发送回特定的客户端(如果这样) 用户ID收到消息或通知? 这是如何实现这样的目标吗? 如果是这样,那我该怎么办?</ p>
</ div>

展开原文

原文

I am trying to learn websockets with Go. I have been looking at examples with gorilla websocket.

I have checked out these 2 examples that show how to use gorilla websocket:

https://github.com/gorilla/websocket/tree/master/examples

https://www.youtube.com/watch?v=ysAZ_oqPOo0

All of these examples show how to connect to a websocket server, send and receive texts. But what I don't understand is how you can send to only one client. Because in a real world application you will have users, and we don't want all users to receive the same message and same data. Is there a way for me to get the unique id of a connection which I can save in a database like redis and link it to a user id in the same database, and then use that websocket id to send back to a specific client if that user id received a message or a notification? Is this how one would go about and achieve something like this? If that is the case, how would I that?

dongliuzi3410
dongliuzi3410 我同意@BravadaZadada。有多种方法可以完成此操作,但是您的需求是基本的。只需分配任何新的websocket。在地图中连接一个唯一的密钥,当您准备对其进行写入时,调用mapname[“clientname”]。WriteMessage(1,[]byte(msg))
接近 5 年之前 回复
douhuang1852
douhuang1852 将Gorilla集线器字段从connectionsmap[*connection]bool更改为connectionsmap[string]*connection,其中字符串键是id。将id字符串字段添加到连接。创建连接并为地图类型进行较小更改时分配ID。完成。
接近 5 年之前 回复

1个回答

Is there a way for me to get the unique id of a connection which I can save in a database like redis and link it to a user id in the same database, and then use that websocket id to send back to a specific client if that user id received a message or a notification?

Sure! You can generate Id by yourself while user registering. Just add userId field in connection structure

In chat example you have hub, which contains connections pool. That pool is using to broadcast messages to all users:

case m := <-h.broadcast:
    for c := range h.connections {
        select {
        case c.send <- m:
        default:
            close(c.send)
            delete(h.connections, c)
        }
    }
}

So there you go. You should make method to send private message, depend on userId

doushizhou4477
doushizhou4477 很高兴看到您通过id选择或忽略的示例...
接近 2 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
将Websocket消息发送到Go中的特定客户端(使用Gorilla)

<div class="post-text" itemprop="text"> <p>I am very new to Go and have found myself working with sockets as my first project. This is a redundant question, but I have failed to understand how to send a websocket update to a specific client in Go (using Gorilla).</p> <p>The broad problem that I am trying to solve is - Building a typeahead using websockets and a search engine like ES/Lucene. I have maintained a bunch of indexes on my search engine and have a Go wrapper around it. When I started working on using websockets in Go, I have been finding almost all the examples showing broadcasting mechanism. When I tried to dig into this and tried to modify the example given in Gorilla's github <a href="https://github.com/gorilla/websocket/tree/master/examples/chat" rel="nofollow noreferrer">repo</a> based on the examples given in <a href="https://github.com/gorilla/websocket/issues/46" rel="nofollow noreferrer">this</a> thread and in this <a href="https://stackoverflow.com/questions/31598147/how-to-send-to-only-one-client-and-not-all-clients-using-go-and-gorilla-websocke">answer</a>, I don't seem to understand <code>connections</code> and how does that fit in <code>client.go</code></p> <p>Ideally, the way I would like to see this working is -</p> <ul> <li>A socket connection between the client and server is established</li> <li>Upon the client sending inputs via the socket, the server fetches it and throws into into a channel (Go channel)</li> <li>The indexing wrapper checks for this channel, and once there is something to fetch, the index is retrieved and written back to the socket</li> </ul> <p>How can the server uniquely identify the <code>Client</code>?</p> <p>I have used the examples given on Gorilla's Github <a href="https://github.com/gorilla/websocket/tree/master/examples/chat" rel="nofollow noreferrer">repo</a></p> <p>From my codebase <code>hub.go</code> has the following </p> <pre><code>type Hub struct { // Registered clients. clients map[*Client]bool // Inbound messages from the clients. broadcast chan []byte // Register requests from the clients. register chan *Client // Unregister requests from clients. unregister chan *Client connections map[string]*connection } func newHub() *Hub { return &amp;Hub{ broadcast: make(chan []byte), register: make(chan *Client), unregister: make(chan *Client), clients: make(map[*Client]bool), connection: make(map[*Client]bool), // is this alright? } } func (h *Hub) run() { for { select { case client := &lt;-h.register: h.clients[client] = true case client := &lt;-h.unregister: if _, ok := h.clients[client]; ok { delete(h.clients, client) close(client.send) } case message := &lt;-h.broadcast: for client := range h.connections { select { case client.send &lt;- message: default: close(client.send) delete(h.connections, client) } } } } } </code></pre> <p>and I am unsure with what I should be adding to <code>client.go</code></p> <pre><code>type Client struct { // unique ID for each client // id string // Hub object hub *Hub // The websocket connection. conn *websocket.Conn // Buffered channel of outbound messages. send chan []byte // connection --&gt; (what should the connection property be?) connection string } </code></pre> <p>Please note - I will be adding an <code>Id</code> field within the <code>Client</code> struct. How can I proceed from here?</p> </div>

Gorilla Websocket手动关闭客户端连接

<div class="post-text" itemprop="text"> <p>I try to close connect manual(use <a href="https://dwst.github.io/" rel="nofollow noreferrer">Dark WebSocket Terminal</a>),but the client tell me 1005 (No Status Rcvd)<br> Server:</p> <pre><code>ReadLoop: for { mt, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) log.Println("messageType:", mt) if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { log.Printf("error: %v", err) } c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) break ReadLoop } log.Printf("recv: %s", message) //do sth in here err = c.WriteMessage(mt, message) if err != nil { //WriteMessage wrong log.Println("write:", err) break ReadLoop } } </code></pre> <p>It is not work and show the expected outputting the following:</p> <pre><code>read: websocket: close 1005 (no status) messageType: -1 error: websocket: close 1005 (no status) </code></pre> <p>How should i go about this?</p> </div>

带有Web代理的Golang Gorilla Websocket

<div class="post-text" itemprop="text"> <p>I'm working on a POC using Gorilla/Websocket to communicate, through a Web Proxy, with the Websocket Check Website "echo.websocket.org".</p> <p>I'm using the free online Proxy "hide.me/en/" for testing.</p> <p>When I simply try to communicate with "echo.websocket.org" (Server side), my client-site Websocket POC reach the response.</p> <p>But when i try to add the Proxy gesture, everything goes wrong :(</p> <p>Here is a sample of my code :</p> <pre><code>package main import ( "flag" "log" "net/url" "os" "os/signal" "time" "github.com/gorilla/websocket" "net/http" ) var addrWebsocket = flag.String("addrWebsocket", "echo.websocket.org", "http service address") func main() { flag.Parse() log.SetFlags(0) interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) //Initialize the WebSocket URL and the Path to follow uWS := url.URL{Scheme: "wss", Host: *addrWebsocket} //Initialize the Proxy URL and the Path to follow uProxy, _ := url.Parse("https://hide.me/en/proxy") //Set the Dialer (especially the proxy) dialer := websocket.Dialer{ Proxy: http.ProxyURL(uProxy), } //dialer := websocket.DefaultDialer ==&gt; with this default dialer, it works ! c, _, err := dialer.Dial(uWS.String(), nil) // ==&gt; With the proxy config, it fails here ! defer c.Close() done := make(chan struct{}) go func() { defer c.Close() defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } log.Printf("recv: %s", message) } }() ticker := time.NewTicker(time.Second) defer ticker.Stop() for { select { case t := &lt;-ticker.C: err := c.WriteMessage(websocket.TextMessage, []byte(t.String())) if err != nil { log.Println("write:", err) return } case &lt;-interrupt: log.Println("interrupt") err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { log.Println("write close:", err) return } select { case &lt;-done: case &lt;-time.After(time.Second): } c.Close() return } } } </code></pre> <p>I'm a very beginner in Go so don't hesitate to correct me if my code un not clear and clean.</p> <p>Thanks for your help !</p> </div>

Golang-扩展websocket客户端以实现与不同服务器的多个连接

<div class="post-text" itemprop="text"> <p>I have a websocket client. In reality, it is far more complex than the basic code shown below. I now need to scale this client code to open connections to multiple servers. Ultimately, the tasks that need to be performed when a message is received from the servers is identical. What would be the best approach to handle this? As I said above the actual code performed when receiving the message is far more complex than shown in the example.</p> <pre><code>package main import ( "flag" "log" "net/url" "os" "os/signal" "time" "github.com/gorilla/websocket" ) var addr = flag.String("addr", "localhost:1234", "http service address") func main() { flag.Parse() log.SetFlags(0) interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) // u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"} u := url.URL{Scheme: "ws", Host: *addr, Path: "/"} log.Printf("connecting to %s", u.String()) c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { log.Fatal("dial:", err) } defer c.Close() done := make(chan struct{}) go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } log.Printf("recv: %s", message) } }() ticker := time.NewTicker(time.Second) defer ticker.Stop() for { select { case &lt;-done: return case t := &lt;-ticker.C: err := c.WriteMessage(websocket.TextMessage, []byte(t.String())) if err != nil { log.Println("write:", err) return } case &lt;-interrupt: log.Println("interrupt") // Cleanly close the connection by sending a close message and then // waiting (with timeout) for the server to close the connection. err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) if err != nil { log.Println("write close:", err) return } select { case &lt;-done: case &lt;-time.After(time.Second): } return } } } </code></pre> </div>

Gorilla Websocket没有收到消息

<div class="post-text" itemprop="text"> <p>I am building a gateway in Golang that communicates with Gorilla websockets.</p> <p>I am running it on Ubuntu 16.04, and testing it currently with a .NET console app.</p> <p>Using Wireshark on Windows and sniffit on Ubuntu have determined that <em>messages are being sent correctly from the Windows client and received by the Ubuntu box</em>.</p> <p>In my code, however, sometimes after a few successful messages, and sometimes after none, my gateway is failing to read the message (still sitting at <code>_, msg, errCon := conn.ReadMessage()</code>)</p> <p>An example of the output will be:</p> <blockquote> <p>2018/03/27 02:38:06 Awaiting Message ... 2018/03/27 02:38:07 Message received: main.AdminRequest{Data:"{\"SomeDataHeader\":\"SomeData\"}", Requestor:"user", Type:"JustDoSomethingRequest", Ukey:"talca"} 2018/03/27 02:38:07 {"SomeDataHeader":"SomeData"} 2018/03/27 02:38:07 Awaiting Message ...</p> </blockquote> <p>As I have previously said, it may receive a few messages like this, but, despite network traffic on both ends continuing, no more messages will be received</p> <p>I am fairly new with Golang, and working under the assumption that I am missing something.</p> <p><strike>I have trimmed out error handling and the like for the sake of brevity in the code below, but this is an example of the failing code.</strike></p> <p><strong>EDIT</strong> As requested I have added Golang full code, and C# client code below (although, as I stated, Wireshark and sniffit have determined that data is going over the wire)</p> <pre><code>package main import ( "fmt" "net/http" "github.com/gorilla/websocket" "encoding/json" "log" ) var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true }, } type AdminRequest struct { Data string `json:"Data"` Requestor string `json:"Requestor"` Type string `json:"Type"` Ukey string `json:"Ukey"` } func main() { http.HandleFunc("/a", func(w http.ResponseWriter, r *http.Request) { var conn, _ = upgrader.Upgrade(w, r, nil) go func(conn *websocket.Conn) { for { _, _, err := conn.ReadMessage() if err != nil { log.Println("Close: "+ err.Error()) conn.Close() return } } }(conn) go func(conn *websocket.Conn) { for { log.Println("Awaiting Message ...") _, msg, errCon := conn.ReadMessage() if errCon != nil { log.Println("Read Error:", errCon) break } log.Println("Message received: ") var r AdminRequest if err := json.Unmarshal(msg, &amp;r); err != nil { log.Println("Error: " + err.Error()); return; } fmt.Printf("%#v ", r) log.Println(r.Data); } }(conn) }) http.ListenAndServe(":3000", nil) } </code></pre> <p>C# Code:</p> <pre><code>public class Client : IDisposable { private ClientWebSocket _socket; string _address; int _port; public Client(string address) { _address = address; _socket = new ClientWebSocket(); } public async void SetupForReceivingStuffs() { while (_socket.State == WebSocketState.Open) { ArraySegment&lt;byte&gt; receivedBytes = new ArraySegment&lt;byte&gt;(new byte[1024]); WebSocketReceiveResult result = await _socket.ReceiveAsync(receivedBytes, CancellationToken.None); Console.WriteLine(Encoding.UTF8.GetString(receivedBytes.Array, 0, result.Count)); } } public async void SetupForSendingStuffs(ConcurrentQueue&lt;AdminRequest&gt; queue) { while (_socket.State == WebSocketState.Open) { AdminRequest next; while (queue.Count &gt; 0) { if (queue.TryDequeue(out next)) { await Send(next); } } await Task.Yield(); } } public async Task Connect() { while (_socket.State != WebSocketState.Open) { try { _socket = new ClientWebSocket(); await _socket.ConnectAsync(new Uri(_address), CancellationToken.None); Console.WriteLine("Socket state: " + _socket.State); } catch (Exception ex) { //Not getting hit Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } } } public Task Send&lt;TData&gt;(TData data) { string text = JsonConvert.SerializeObject(data); var encoded = Encoding.UTF8.GetBytes(text); var buffer = new ArraySegment&lt;Byte&gt;(encoded, 0, encoded.Length); return _socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None); } public void Dispose() { _socket.Dispose(); } } </code></pre> <p>Called by:</p> <pre><code>class Program { static ConcurrentQueue&lt;AdminRequest&gt; _toSend; static void Main(string[] args) { _toSend = new ConcurrentQueue&lt;AdminRequest&gt;(); Client client = new Client("ws:/(myip):(myport)/a"); client.Connect().Wait(); //client.SetupForReceivingStuffs(); client.SetupForSendingStuffs(_toSend); WriteInstructions(); LoopAuto(); Console.WriteLine("Bye"); } private static void LoopAuto() { DateTime nextMessage = DateTime.Now; while (true) { if (DateTime.Now &lt; nextMessage) continue; Console.WriteLine("Next"); nextMessage = DateTime.Now.AddSeconds(2); _toSend.Enqueue(new AdminRequest { Data = "{\"SomeDataHeader\":\"SomeData\"}", Requestor = "user", Type = "JustDoSomethingRequest", Ukey = "talca" }); } } private static ConsoleKeyInfo LoopManual() { ConsoleKeyInfo info; do { info = Console.ReadKey(true); if (info.KeyChar == '1') { _toSend.Enqueue(new AdminRequest { Data = "{\"SomeDataHeader\":\"SomeData\"}", Requestor = "user", Type = "JustDoSomethingRequest", Ukey = "talca" }); } else if (info.KeyChar == 'i') { WriteInstructions(); } } while (info.KeyChar != 'x'); return info; } private static void WriteInstructions() { Console.WriteLine("1. Send New Message"); Console.WriteLine("i. Instructions (these lines)"); Console.WriteLine("x: Exit"); } } </code></pre> </div>

GO Websocket向所有客户发送消息

<div class="post-text" itemprop="text"> <p>Everything works fine with this code (shortened it for better reading).</p> <p>When <code>Client1</code> sends a request to the Server, the Server responses to him instantly. But, the other clients can not see the response message.</p> <p>So I want to make it go further: When a client sends a request to the server, the server will response to all clients so that all clients can see the message.</p> <p>How can I do that? Any examples or nice tutorials for beginners?</p> <p>Thanks in advance!</p> <p>Server:</p> <pre><code>import ( "github.com/gorilla/websocket" ) func main() { http.Handle("/server", websocket.Handler(echoHandler)) } func echoHandler(ws *websocket.Conn) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { return } for { messageType, p, err := conn.ReadMessage() if err != nil { return } print_binary(p) // simple print of the message err = conn.WriteMessage(messageType, p); if err != nil { return } } } </code></pre> </div>

Websocket发送到特定客户端而不是广播

<div class="post-text" itemprop="text"> <p>I'm trying to modify the gorilla chat example to to send a message to a specific client instead of broadcast. First I'm storing the specific client in the hub against it's Id.</p> <p><strong>Hub.go</strong></p> <pre><code>type Hub struct { Clients map[int]*Client // Changed this piece to store id (int) Broadcast chan []byte Register chan *Client Unregister chan *Client } func (h *Hub) Run() { for { select { case client := &lt;-h.Register: fmt.Println("hub client register") h.Clients[client.Id] = client case client := &lt;-h.Unregister: fmt.Println("hub client Unregister") fmt.Println(h.Clients[client.Id]) if h.Clients[client.Id] != nil { delete(h.Clients, client.Id) close(client.Send) } case message := &lt;-h.Broadcast: fmt.Println("to send to a specific client", string(message)) } } } </code></pre> <p><strong>Client</strong></p> <p>I've added a field Id int to Client to know which client has sent a message</p> <pre><code>type Client struct { Hub *Hub Conn *websocket.Conn Send chan []byte Id int // Id of the client, } func (c *Client) readPump() { defer func() { c.Hub.Unregister &lt;- c c.Conn.Close() }() c.Conn.SetReadLimit(maxMessageSize) c.Conn.SetReadDeadline(time.Now().Add(pongWait)) c.Conn.SetPongHandler(func(string) error { c.Conn.SetReadDeadline(time.Now().Add(pongWait)); return nil }) for { _, message, err := c.Conn.ReadMessage() if err != nil { if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) { log.Printf("error: %v", err) } break } message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1)) fmt.Println("client read message", string(message), "from", c.Id) // {"to":512,"message":"Hi there."} c.Hub.Broadcast &lt;- message } } </code></pre> <p>What are the next steps to take to be able to send the message to a specific client instead of broadcasting.</p> <p>the message itself is coming as JSON from the client specifying 'to' indicating who to send and what message to send.</p> <pre><code>{"to":512,"message":"Hi there."} </code></pre> </div>

如何从golang的websocket服务器向客户端主动发送消息

<div class="post-text" itemprop="text"> <p>I'm a newcomer for the golang and websocket.</p> <p>I'm trying to write a websocket server which can send the messages actively to client once the handshake is done.</p> <p>but my server will just only send the message to the client when got the request from the client.</p> <p>Does anyone know how to implement this feature or where can I find the related answer for that? </p> <p>Thank you so much.</p> <p>the source code is as follows:</p> <pre><code>package main import ( "log" "net/http" ) func handler(w http.ResponseWriter, req *http.Request) { w.Header().Set("Content-Type", "text/plain") w.Write([]byte("Hi, the handshake is completed. ")) w.Write([]byte("Let's start to talk something. ")) } func main() { http.HandleFunc("/", handler) log.Printf("Start to listen on 443.") err := http.ListenAndServeTLS(":443", "server.crt", "server.key", nil) log.Fatal(err) } </code></pre> </div>

Golang WebSocket客户端,获取结果后关闭连接

<div class="post-text" itemprop="text"> <p>How I can implement this kind of scenario:</p> <p>1.I have LoginHandler which receives some user data - email and signedXml:</p> <pre><code>func LoginHandler(c *gin.Context) { var ( err error data LoginPost ) if err = c.BindJSON(&amp;data); err != nil { c.JSON(http.StatusBadRequest, gin.H{"status": "error"}) return } ... c.JSON(http.StatusOK, gin.H{"status": "ok"}) } </code></pre> <p>2.I need to send signedXml to another server via websocket</p> <p>3.Save result (success or error)</p> <p>4.Close connection</p> <p>Every HTTP request will open connection, send 1 message, get 1 result and finally close socket. I was trying with channel, but no success. Is this possible to implement my case?</p> <p><strong>UPDATE</strong></p> <pre><code>package main import ( "log" "net/url" "github.com/gorilla/mux" "github.com/gorilla/websocket" "net/http" ) func indexHandler(w http.ResponseWriter, r *http.Request) { message := r.FormValue("message") w.Write([]byte(message)) } func postHandler(w http.ResponseWriter, r *http.Request) { var ( message = r.FormValue("message") u = url.URL{Scheme: "ws", Host: "echo.websocket.org", Path: "/"} err error out []byte conn *websocket.Conn ) log.Printf("message: %s ", message) log.Printf("connecting to %s ", u.String()) conn, _, err = websocket.DefaultDialer.Dial(u.String(), nil) if err != nil { log.Fatal("dial:", err) } log.Println("write") if err = conn.WriteMessage(websocket.TextMessage, []byte(message)); err != nil { log.Fatal("write:", err) } log.Println("read") if _, out, err = conn.ReadMessage(); err != nil { log.Fatal("read:", err) } w.Write(out) log.Println("close") conn.Close() } func main() { r := mux.NewRouter() r.HandleFunc("/", indexHandler).Methods("GET") r.HandleFunc("/post", postHandler).Methods("POST") http.Handle("/", r) http.ListenAndServe(":8080", nil) } </code></pre> </div>

如何在GO的WebSocket中保持连接活跃

<div class="post-text" itemprop="text"> <p>I use <code>code.google.com/p/go.net/websocket</code> in server, so client can get notification from server. </p> <p>however, It seems after client connected to server, if there is no any data tranfer between client and server, server will return EOF error at <code>websocket.JSON.Receive()</code>, it looks like a timeout mechanism. </p> <p>And I have search in Google, it seems websocket protocol has a <strong>ping-pong</strong> heartbeat to maintain the connection, I want to ask whether <code>code.google.com/p/go.net/websocket</code> support this ping protocol or not?<br> What should I do if I want keep connection between client and server alive? </p> </div>

处理多个WebSocket连接

<div class="post-text" itemprop="text"> <p>I'm trying to create a program that will connect to several servers though gorilla web-sockets. I currently have a program that will iterate over a list of server addresses and create a new goroutine that will create its own Websocket.conn and handle reading and writing. </p> <p>The problem is that every time a new goroutine is created the previous goroutines are blocked and only the last one can continue. I believe this is because the gorilla websocket library is blocking each gorotutine, but I might be mistaken.</p> <p>I have tried putting a timer in the server list iterator and each goroutine will work perfectly but then the moment a new goroutine is made with another address the previous goroutine is blocked.</p> <p>The relevant bits of my code:</p> <p>In my <code>main.go</code></p> <pre class="lang-golang prettyprint-override"><code>for _, server := range servers { go control(ctx, server, port) } </code></pre> <p>In <code>control()</code></p> <pre class="lang-golang prettyprint-override"><code> func control(ctx context.Context, server, port string) { url := url.URL{ Scheme: "ws", Host: server + ":" + port, Path: "", } conn, _, err := websocket.DefaultDialer.Dial(url.String(), nil) if err != nil { panic(err) } defer conn.Close() go sendHandler(ctx, conn) go readHandler(ctx, conn) } readHandler(ctx context.Context, conn *websocket.Con) { for { _, p, err := conn.ReadMessage(); if err != nil { panic(err) } select { case &lt;-ctx.Done(): goto TERM default: // do nothing } } TERM: // do termination } sendHandler(ctx context.Context, conn *websocket.Con) { for _, msg := range msges { err = conn.WriteMessage(websocket.TextMessage, msg) if err != nil { panic(err) } } &lt;-ctx.Done() } </code></pre> <p>I removed the parts where I add waitgroups and other unnecessary pieces of code.</p> <p>So what I expect is for there to be 3n goroutines running (where n is the number of servers) without blocking but right now I see only 3 goroutines running which are the ones called by the last iteration of the server list.</p> <p>Thanks!</p> <p>EDIT 14/06/2019:</p> <p>I spent some time making a small working example and in the example the bug did not occur - none of the threads blocked each other. I'm still unsure what was causing it but here is my small working example:</p> <p><code>main.go</code></p> <pre class="lang-golang prettyprint-override"><code>package main import ( "context" "fmt" "os" "time" "os/signal" "syscall" "sync" "net/url" "github.com/gorilla/websocket" ) func main() { servers := []string{"5555","5556", "5557"} comms := make(chan os.Signal, 1) signal.Notify(comms, os.Interrupt, syscall.SIGTERM) ctx := context.Background() ctx, cancel := context.WithCancel(ctx) var wg sync.WaitGroup for _, server := range servers { wg.Add(1) go control(server, ctx, &amp;wg) } &lt;-comms cancel() wg.Wait() } func control(server string, ctx context.Context, wg *sync.WaitGroup) { fmt.Printf("Started control for %s ", server) url := url.URL { Scheme: "ws", Host: "0.0.0.0" + ":" + server, Path: "", } conn, _, err := websocket.DefaultDialer.Dial(url.String(), nil) if err != nil { panic(err) } defer conn.Close() var localwg sync.WaitGroup localwg.Add(1) go sendHandler(ctx, conn, &amp;localwg, server) localwg.Add(1) go readHandler(ctx, conn, &amp;localwg, server) &lt;- ctx.Done() localwg.Wait() wg.Done() return } func sendHandler(ctx context.Context, conn *websocket.Conn, wg *sync.WaitGroup, server string) { for i := 0; i &lt; 50; i++ { err := conn.WriteMessage(websocket.TextMessage, []byte("ping")) if err != nil { panic(err) } fmt.Printf("sent msg to %s ", server) time.Sleep(1 * time.Second) } &lt;- ctx.Done() wg.Done() } func readHandler(ctx context.Context, conn *websocket.Conn, wg *sync.WaitGroup, server string) { for { select { case &lt;- ctx.Done(): wg.Done() return default: _, p, err := conn.ReadMessage() if err != nil { wg.Done() fmt.Println("done") } fmt.Printf("Got [%s] from %s ", string(p), server) } } } </code></pre> <p>I tested it with dpallot's <a href="https://github.com/dpallot/simple-websocket-server" rel="nofollow noreferrer">simple-websocket-server</a> by a server on 5555, 5556 and 5557 respectively.</p> </div>

Websocket上的客户端JSON-RPC2.0所需的Golang库(或代码)

<div class="post-text" itemprop="text"> <p>I have to add </p> <ol> <li>JSON-RPC2.0 </li> <li>over websockets, to my </li> <li>Golang</li> <li>Client process</li> </ol> <p>to communicate with another server. Unfortunately, none of the requirements can be changed.</p> <p>I have libs and example code that offer parts of the solution but I have been unable to put it all together.</p> <p>I have looked at Ethereum (I cannot find a client example) <a href="https://godoc.org/github.com/ethereum/go-ethereum/rpc#Server.WebsocketHandler" rel="nofollow noreferrer">Ethereum rpc</a></p> <p>A <a href="https://stackoverflow.com/questions/29479360/json-rpc-client-go">stackoverflow question</a> that dials tcp.</p> <p>This <a href="https://ops.tips/gists/example-go-rpc-client-and-server/" rel="nofollow noreferrer">dials TCP</a></p> <p>net.rpc <a href="https://medium.com/@OmisNomis/creating-an-rpc-server-in-go-3a94797ab833" rel="nofollow noreferrer">not 2.0, dials tcp</a></p> <p>over http <a href="https://haisum.github.io/2015/10/13/rpc-jsonrpc-gorilla-example-in-golang/" rel="nofollow noreferrer">net/rpc and http</a></p> <p><a href="https://github.com/snaffi/booze" rel="nofollow noreferrer">This one</a> looked promising but I cannot make my client work.</p> <pre><code>type Params struct { Name string `json:"name"` } func main() { h := NewRPCHandler() h.Register("some_handler", dummySuccessHandler) ts := http.Server{Handler: h} defer ts.Close() conn, _, err := websocket.DefaultDialer.Dial("ws://127.0.0.1:8080/ws_rpc", nil) if err != nil { log.Printf("Error dialing %v", err) } client := jsonrpc.NewClient(conn.UnderlyingConn()) par := &amp;Params{"newuser"} req, err := json.Marshal(&amp;par) if err != nil { log.Printf("Bad marshal %#v", err) } var resp Result err = client.Call("some_handler", &amp;req, &amp;resp) </code></pre> <p>I tried with/without marshaling but I'm clutching at straws here.</p> </div>

Websocket在Echo Framework中向所有客户端发送消息

<div class="post-text" itemprop="text"> <p>I believe that this question is almost the same with <a href="https://stackoverflow.com/questions/31532652/go-websocket-send-all-clients-a-message">this.</a></p> <p>But I use websocket in Echo framework instead of Gorilla. So I think the approach will be different.</p> <p>Echo does provide the <a href="http://labstack.com/echo/recipes/websocket" rel="nofollow noreferrer">example.</a> But it only shows how to connect with single client. When there are more than one client, the other clients don't receive message from server. </p> <p>How do I make the server broadcasts message to all connected clients?</p> <p>The accepted answer from referred link says that I have to use connection pool to broadcast messages to all connections. How can I do this in Echo framework?</p> </div>

关闭已在服务器端发送,但客户端仍保持连接

<div class="post-text" itemprop="text"> <p>I have an application that communicates over an API and a websocket. The websocket is used to publish updated userdata to the client if it is changed in the database - this works perfectly, except for the case that the websocket does not receive any data in some cases. After a few seconds, the websocket starts working again. </p> <p>The server log (first, the websocket does not work and starts working again)</p> <blockquote> <p>msg="Failed to write data to Websocket: websocket: close sent"</p> <p>msg="Sending Ping Message to Client"</p> <p>msg="Failed to write ping message to Websocket: websocket: close sent"</p> <p>msg="Sending Ping Message to Client"</p> <p>msg="Sending Ping Message to Client"</p> <p>msg="Sending Ping Message to Client"</p> <p>msg="Sending Ping Message to Client"</p> </blockquote> <p>The client-side code: </p> <pre><code>&lt;html&gt; &lt;body&gt; &lt;p id="data"&gt;&lt;/p&gt; &lt;/body&gt; &lt;script&gt; var ws = new WebSocket("wss://example.com/ws"); function unloadPage() { toggleLoader(); ws.onclose = function () {}; ws.close(); } ws.onopen = function () { ws.send('Ping'); }; ws.onerror = function (error) { console.log('WebSocket Error ' + error); var d = document.getElementById("data"); d.innerHTML += "&lt;tr&gt;&lt;td&gt;Failed to connect to Server.&lt;/td&gt;&lt;/tr&gt;" }; ws.onmessage = function (e) { console.log(e); var data = e.data; var d = document.getElementById("data"); var parsedjson = JSON.parse(data); d.innerHTML = ""; for (var i = 0; i &lt; parsedjson.length; i++) { d.innerHTML += parsedjson; } }; ws.onclose = function () { console.log("Websocket has been closed"); }; window.addEventListener("beforeunload", unloadPage); &lt;/script&gt; &lt;/html&gt; </code></pre> <p>The Go Code (routed through gorilla mux):</p> <pre><code>var ( upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true }, } pingPeriod = (pongPeriod * 9) / 10 pongPeriod = 60 * time.Second writeWait = 10 * time.Second ) func PingResponse(ws *websocket.Conn) { conf := storage.GetConfig() defer ws.Close() ws.SetReadLimit(512) ws.SetReadDeadline(time.Now().Add(pongPeriod)) ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongPeriod)); return nil }) for { _, _, err := ws.ReadMessage() if err != nil { if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) { conf.Log.Debugf("Websocket Ping Read Failed: %v", err) } return } else { conf.Log.Debugf("Received message from Websocket client") } } } func ServeAllUsersWebsocket(datachan chan *[]storage.UserResponse) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { conf := storage.GetConfig() ws, err := upgrader.Upgrade(w, r, nil) if err != nil { conf.Log.Debugf("Failed to upgrade data to Websocket: %v", err) return } go allUserWebsocketWriter(ws, datachan) go PingResponse(ws) }) } func allUserWebsocketWriter(ws *websocket.Conn, datachan chan *[]storage.UserResponse) { conf := storage.GetConfig() pingticker := time.NewTicker(pingPeriod) defer func() { pingticker.Stop() ws.Close() }() userresponse, err := conf.Database.GetAllUsers() if err != nil { conf.Log.Errorf("Failed to query users from database: %v", err) return } ws.SetWriteDeadline(time.Now().Add(writeWait)) err = ws.WriteJSON(&amp;userresponse) if err != nil { conf.Log.Debugf("Failed to write initial user response: %v", err) return } for { select { case data := &lt;-datachan: ws.SetWriteDeadline(time.Now().Add(writeWait)) err := ws.WriteJSON(&amp;data) if err != nil { conf.Log.Debugf("Failed to write data to Websocket: %v", err) return } case &lt;-pingticker.C: ws.SetWriteDeadline(time.Now().Add(writeWait)) conf.Log.Debugf("Sending Ping Message to Client") if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil { conf.Log.Debugf("Failed to write ping message to Websocket: %v", err) return } } } } </code></pre> <p>Basically, we are posting the current data to the new Websocket Connection, when it is updated - this does always work. Afterwards, if the database changes, it posts the updated userlist into the channel - the websocket should then post it to the client which updates the list. We are also sending ping messages - which fail (as seen in the log above). The client itself does not log any errors or closes the websocket.</p> </div>

websocket 与 用户对接并发

实现 用户登录 对接 ,能处理多人数 聊天并发问题 求代码,,,,,,,,,

发送连接升级后,如何将客户端http连接升级到golang中的websockets

<div class="post-text" itemprop="text"> <p>I need a golang client that can upgrade from an http get response to a websocket connection.</p> <p>I have a JS client that works and I've seen direct ws client connections but I have to upgrade from http. I have tried looking for other 3GL solutions (Java, C#, Python) but I need to be able to implement the upgrade in Go. I have seen Dart detaching the socket and creating a websocket from it.</p> <pre><code>WebSocket.fromUpgradedSocket </code></pre> <p>I noticed <a href="https://github.com/golang/go/issues/28030" rel="nofollow noreferrer">Client does not support Hijack</a> but the discussion didn't get me anywhere. I am using github.com/gorilla/websocket but can change that if it helps.</p> <p>Server:</p> <pre><code> func main() { srv := Srv{} count = 0 http.HandleFunc("/", srv.handleRoot) http.HandleFunc("/ws", srv.handleWs) log.Fatal(http.ListenAndServe(":5002", nil)) } func (tool *Srv) handleRoot(w http.ResponseWriter, r *http.Request) { webSocketKey := hdr.Get("Sec-WebSocket-Key") log.Printf("Socket key = '%v'", webSocketKey) secWsAccept := computeAcceptKey(webSocketKey) log.Printf("Accept = '%v'", secWsAccept) w.Header().Add("sec-websocket-accept", secWsAccept) w.Header().Add("upgrade", "websockt") w.Header().Add("connection", "upgrade") w.WriteHeader(101) } func (tool *Srv) handleWs(w http.ResponseWriter, r *http.Request) { var upgrader = websocket.Upgrader{} conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Fatalf("Websocket fatal error. %v", err) } tool.conn = conn go tool.serviceWsRequests() } func (tool *Srv) serviceWsRequests() { for { log.Printf("starting ws") req := request{} err := tool.conn.ReadJSON(&amp;req) if err != nil { log.Printf("Failed to decode ws message. %v", err) break } fmt.Printf("Got request. %v ", req) if req.Method == "ping" { fmt.Printf("Param=%v ", req.Parameters) } } } var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") func computeAcceptKey(challengeKey string) string { h := sha1.New() h.Write([]byte(challengeKey)) h.Write(keyGUID) return base64.StdEncoding.EncodeToString(h.Sum(nil)) } </code></pre> <p>Client:</p> <pre><code> func main() { tr := &amp;http.Transport{ MaxIdleConns: 10, IdleConnTimeout: 30 * time.Second, DisableCompression: true, } client := &amp;http.Client{ Transport: tr, // Do NOT follow redirects CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, } wsKey, err := generateKey() if err != nil { log.Printf("Cannot generate challenge key %v", err) } // Get request for ws upgrade. req, err := http.NewRequest("GET", "http://localhost:5002", nil) req.Header.Add("Connection", "Upgrade") req.Header.Add("Upgrade", "websocket") req.Header.Add("Sec-WebSocket-Version", "13") req.Header.Add("Sec-WebSocket-Key", wsKey) log.Printf("ws key '%v'", wsKey) resp, err := client.Do(req) if err != nil { log.Printf("Get error %v", err) } defer func() { if resp != nil { err = resp.Body.Close() } }() log.Printf("Status='%v', proto='%v'", resp.Status, resp.Proto) body, err := ioutil.ReadAll(resp.Body) hdr := resp.Header for k, v := range hdr{ log.Printf("%v : %v", k, v) } log.Printf("Body = %v", string(body)) resp, err = http.Get("ws://localhost:5002/ws") if err != nil { log.Printf("Error '%v'", err) } } func generateKey() (string, error) { p := make([]byte, 16) if _, err := io.ReadFull(rand.Reader, p); err != nil { return "", err } return base64.StdEncoding.EncodeToString(p), nil } var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") func computeAcceptKey(challengeKey string) string { h := sha1.New() h.Write([]byte(challengeKey)) h.Write(keyGUID) return base64.StdEncoding.EncodeToString(h.Sum(nil)) } </code></pre> <p>I get an error </p> <pre><code>Error 'Get ws://localhost:5002/ws: unsupported protocol scheme "ws"' </code></pre> <p>Which doesn't surprise me because I haven't upgraded the connection. So how do I go an upgrade in Go?</p> </div>

如何设置大猩猩/ websocket连接以充当浏览器应用程序的JSON-RPC客户端?

<div class="post-text" itemprop="text"> <p>I have a frontend <a href="https://gist.github.com/fpawel/6953dfafef1591300c62e1a1ea1db97c" rel="nofollow noreferrer">aplication</a>, that connects to websocket and try to serve json-rpc2 to call client side from server. What is the best way to create <code>*rpc.Client</code> for it in a server application written in Go with "github.com/gorilla/websocket"? I tried to use <code>UnderlyingConn()</code> of <code>*websocket.Conn</code>: <code>jsonrpc2.NewClient(conn.UnderlyingConn())</code>, but it does not work.</p> </div>

如何从用Go编写的客户端连接到sockJS?

<div class="post-text" itemprop="text"> <p>I have a server that uses websockets. It is written in Go. For testing, I have another application written in Go. To test, I start the server, then run the test client. The test client creates websocket connections to the server and does things (basically impersonating user activity). Both the client and the server are using the gorilla/websockets library, and standard browsers also work fine with the server.</p> <p>This was all working beautifully.</p> <p>To support non-compliant browsers, I was asked to start using the <a href="https://github.com/igm/sockjs-go/" rel="nofollow noreferrer">SockJS</a> Go server library. I did this and the new version works just fine when used from a browser by clients using the <a href="http://sockjs.org" rel="nofollow noreferrer">SockJS</a> library.</p> <p>Now for the problem. SockJS does <em>not</em> accept incoming websocket connections. Only connections from the SockJS client. So my testing application doesn't work, and I'm unable to test.</p> <p>I could recover the old version of my connection code from git and make a separate connection type that uses gorilla/websockets and have my server listen on an additional port that only listens on localhost. This would allow me to test the functionality. The downside is that I have to maintain two versions of essentially the same code, and I wouldn't be testing the real user experience and possibly not find bugs until production.</p> <p>Ideally the SockJS server, considering it still <em>uses</em> gorilla/websockets as a dependency would automatically accept proper websocket connections, but barring that it seems I'd need a SockJS client library in Go which, as far as I can tell, doesn't exist.</p> <p>Does anyone have a solution for this? Thanks!</p> </div>

程序员的兼职技能课

程序员的兼职技能课

为linux系统设计一个简单的二级文件系统

实验目的: 通过一个简单多用户文件系统的设计,加深理解文件系统的内部功能及内部实现。 实验要求: 为linux系统设计一个简单的二级文件系统。要求做到以下几点: (1)可以实现下列几条命令(至少4条)

CCNA+HCNA+wireshark抓包综合网工技能提升套餐

本套餐包含思科路由交换CCNA,部分CCNP核心,华为HCNA以及wireshark抓包等类容,旨在培养具有综合能力的网络工程师。

董付国老师Python全栈学习优惠套餐

购买套餐的朋友可以关注微信公众号“Python小屋”,上传付款截图,然后领取董老师任意图书1本。

成年人用得到的6款资源网站!各个都是宝藏,绝对让你大饱眼福!

不管是学习还是工作,我们都需要一些资源帮助我们有效地解决实际问题。 很多人找资源只知道上百度,但是你们知道吗,有的资源是百度也搜索不出来的,那么今天小编就给大家介绍几款好用的资源网站,大家赶紧收入囊中吧! 1.网盘007 https://wangpan007.com/ 一款全能的资源搜索网站!只需要输入关键字,就能获得你想要的视频、音乐、压缩包等各种资源,网上...

矿车轴载荷计算方法的比较及选用

针对矿车轴的弯曲损坏,分析了固定式矿车车轴的受力,并对力叠加法以及当量负荷法2种计算方法进行了分析和比较,认为应采用当量负荷法进行车轴的设计计算。

Python数据清洗实战入门

Python数据清洗实战入门

C/C++跨平台研发从基础到高阶实战系列套餐

一 专题从基础的C语言核心到c++ 和stl完成基础强化; 二 再到数据结构,设计模式完成专业计算机技能强化; 三 通过跨平台网络编程,linux编程,qt界面编程,mfc编程,windows编程,c++与lua联合编程来完成应用强化 四 最后通过基于ffmpeg的音视频播放器,直播推流,屏幕录像,

Polar编码matlab程序

matlab实现的Polar codes源程序

2019全国大学生数学建模竞赛C题原版优秀论文

2019全国大学生数学建模竞赛C题原版优秀论文,PDF原版论文,不是图片合成的,是可编辑的文字版。共三篇。 C044.pdf C137.pdf C308.pdf

Linux常用命令大全(非常全!!!)

Linux常用命令大全(非常全!!!) 最近都在和Linux打交道,感觉还不错。我觉得Linux相比windows比较麻烦的就是很多东西都要用命令来控制,当然,这也是很多人喜欢linux的原因,比较短小但却功能强大。我将我了解到的命令列举一下,仅供大家参考: 系统信息 arch 显示机器的处理器架构 uname -m 显示机器的处理器架构 uname -r 显示正在使用的内核版本 d...

Linux下聊天室实现(基于C)

在linux下的基于TCP/IP,采用socket通信的聊天室,实现进入聊天室,进行多人群聊,指定人进行私聊,群主管理员功能,颗进行禁言,提出群聊等操作。个人账号可修改昵称或者修改密码,还可进行找回密

一个较完整的Qt用户登录界面设计

一个较完整的Qt用户登录界面,稍微移植可用,用sqlite数据库存储用户名和密码,具有增加和删除用户的功能,开发环境为ubuntu16.04+Qt5.6.1,win7下程序也编译可用。贡献出来,共同学

机器学习初学者必会的案例精讲

机器学习初学者必会的案例精讲

【C语言】贪吃蛇游戏代码(Visual C++6.0实现)

本游戏代码参考《C语言项目开发全程实录(第二版)》第六章。代码已在Visual C++6.0环境下编译测试通过,可在VC++6.0编译器中导入工程编译运行查看效果,或者也可以直接运行Release或D

Android小项目——新闻APP(源码)

Android小项目——新闻APP(源码),一个很简单的可以练手的Android Demo Ps:下载之前可以先看一下这篇文章——https://blog.csdn.net/qq_34149526/a

网络工程师小白入门--【思科CCNA、华为HCNA等网络工程师认证】

网络工程师小白入门--【思科CCNA、华为HCNA等网络工程师认证】

Android音视频开发全套

Android平台音视频开发全套,涉及:FFmpeg软解码解码、Mediacodec硬解码编码、Openssl音频播放、OpenGL ES视频渲染、RTMP推流等核心重要知识点。

YOLOv3目标检测实战:训练自己的数据集

YOLOv3目标检测实战:训练自己的数据集

2019 Python开发者日-培训

2019 Python开发者日-培训

2019 AI开发者大会

2019 AI开发者大会

Windows版YOLOv4目标检测实战:训练自己的数据集

Windows版YOLOv4目标检测实战:训练自己的数据集

4小时玩转微信小程序——基础入门与微信支付实战

4小时玩转微信小程序——基础入门与微信支付实战

因为看了这些书,我大二就拿了华为Offer

四年了,四年,你知道大学这四年我怎么过的么?

Python可以这样学(第四季:数据分析与科学计算可视化)

Python可以这样学(第四季:数据分析与科学计算可视化)

我说我不会算法,阿里把我挂了。

不说了,字节跳动也反手把我挂了。

技术大佬:我去,你写的 switch 语句也太老土了吧

昨天早上通过远程的方式 review 了两名新来同事的代码,大部分代码都写得很漂亮,严谨的同时注释也很到位,这令我非常满意。但当我看到他们当中有一个人写的 switch 语句时,还是忍不住破口大骂:“我擦,小王,你丫写的 switch 语句也太老土了吧!” 来看看小王写的代码吧,看完不要骂我装逼啊。 private static String createPlayer(PlayerTypes p...

YOLOv3目标检测实战系列课程

《YOLOv3目标检测实战系列课程》旨在帮助大家掌握YOLOv3目标检测的训练、原理、源码与网络模型改进方法。 本课程的YOLOv3使用原作darknet(c语言编写),在Ubuntu系统上做项目演示。 本系列课程包括三门课: (1)《YOLOv3目标检测实战:训练自己的数据集》 包括:安装darknet、给自己的数据集打标签、整理自己的数据集、修改配置文件、训练自己的数据集、测试训练出的网络模型、性能统计(mAP计算和画出PR曲线)和先验框聚类。 (2)《YOLOv3目标检测:原理与源码解析》讲解YOLOv1、YOLOv2、YOLOv3的原理、程序流程并解析各层的源码。 (3)《YOLOv3目标检测:网络模型改进方法》讲解YOLOv3的改进方法,包括改进1:不显示指定类别目标的方法 (增加功能) ;改进2:合并BN层到卷积层 (加快推理速度) ; 改进3:使用GIoU指标和损失函数 (提高检测精度) ;改进4:tiny YOLOv3 (简化网络模型)并介绍 AlexeyAB/darknet项目。

DirectX修复工具V4.0增强版

DirectX修复工具(DirectX Repair)是一款系统级工具软件,简便易用。本程序为绿色版,无需安装,可直接运行。 本程序的主要功能是检测当前系统的DirectX状态,如果发现异常则进行修复

C++语言基础视频教程

C++语言基础视频教程

形考任务一答案.zip

国开电大VisualBasic程序设计形考任务答案 请同学选择课程实验栏目“实验1 欢迎程序”或“实验2 计时秒表程序”的其中之一,在VB集成开发环境中认真完成实验。

相关热词 c# 局部 截图 页面 c#实现简单的文件管理器 c# where c# 取文件夹路径 c# 对比 当天 c# fir 滤波器 c# 和站 队列 c# txt 去空格 c#移除其他类事件 c# 自动截屏
立即提问