<p>Here's my <a href="https://github.com/hunkeelin/goplayground/blob/master/server.go" rel="nofollow">code in github</a>. For this question it's only <code>server.go</code> and <code>server.cfg</code>. </p>
<p><em>What I want my program do:</em> open the socket on the port specified in the cfg. Machines can telnet into the host, any message sent will be returned as uppercase. The connection is closed only if the client exit the session or I the software from the server side stop running.</p>
<p><em>What it's doing</em>: The program will automatically close my telnet connection after the first message.</p>
<p><em>What I tried:</em></p>
<ul>
<li>comment out <code>c.Close()</code> in the <code>dowork1</code> function:</li>
<li><p>result: Only the first message will get returned as all cap. All subsequence messages will do nothing. The count logic will also break in the <code>dowork1</code> function. That is because <code>atomic.AddInt64(count,-1)</code> got called without closing the connection. Therefore, if a machine is connected to the server and type it's first message. The program will count-- and a new machine can established with the server without fearing the limit I set in <code>server.cfg</code></p></li>
<li><p>Put a for loop inside <code>dowork1</code>. I believe the reason why the program is not doing what I want is I need a separate loop to handle the connection. </p></li>
<li><p>result: The serverside got spammed because inside the loop in <code>dowork</code> there's a count-- and it will continuously count-- causing the program to timeout. </p></li>
</ul>
<p>I also tried other things as in modified the code here and there but i basically end up in square one most of the time. Any pointers in how to solve my current problem will be appreciate</p>
<p>Thanks.</p>
<hr/>**评论:**<br/><br/>Dummies102: <pre><p>I think the problem is that you only read from your connection once. Look at this:</p>
<pre><code>package main
import (
"bufio"
"fmt"
"log"
"net"
"os"
"strings"
"sync/atomic"
)
func dowork(c net.Conn) {
scanner := bufio.NewScanner(c)
for scanner.Scan() {
msg := scanner.Text()
fmt.Println("Message Received:", string(msg))
c.Write([]byte(strings.ToUpper(msg) + "\n"))
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "error reading from connection:", err)
}
}
func main() {
var count int64 = 0
maxConns := 1
l, err := net.Listen("tcp", ":2222")
if err != nil {
log.Fatal(err)
}
defer l.Close()
for {
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}
fmt.Println("Current number of connections \n", count)
if count >= int64(maxConns) {
log.Println("over limit")
conn.Close()
continue
}
go func() {
atomic.AddInt64(&count, 1)
dowork(conn)
atomic.AddInt64(&count, -1)
}()
}
}
</code></pre>
<p>can't guarantee the sync logic is correct... I don't think the read of count in the comparison is safe, but it's a good example.</p></pre>juniorsysadmin1: <pre><p>Thanks, that's my problem. I got another question. If I modify your code from <code>dowork(conn)</code> to <code>go dowork(conn)</code>. The count will always stays at 0, why is that? </p></pre>Dummies102: <pre><p>because it returns immediately, and so <code>atomic.AddInt64(&count, -1)</code> is executed before dowork is done processing. It's already in a goroutine, so no need to run it in another one. I wrote it like that so that there would be a separation of concerns between the connection limit logic and the "dowork" logic</p></pre>epiris: <pre><p>You probably want to change your atomic decrement to run in a defer if you end up with an outer recover in your final implementation, otherwise occasional panics could eventually prevent all requests from being serviced. If you want to ratelimit more granularly perhaps per IP and a global shared max while allowing occasional bursts you may want to look into: <a href="https://godoc.org/golang.org/x/time/rate" rel="nofollow">https://godoc.org/golang.org/x/time/rate</a> </p></pre>juniorsysadmin1: <pre><p>Yes, another guy who look at my code suggested the same thign on defer.</p>
<pre><code>fun defer {
c.close()
atomic.AddInt64(&count, -1)
}()
</code></pre>
<p>defer is quite new to me and I don't really understand it. What's the difference between defer and putting the content of defer at the last?</p></pre>ar1819: <pre><p>defer is a statement, not a function. It basically says - run a function in defer statement AFTER we had returned from the current one or on panic.</p></pre>epiris: <pre><p>You don't want to do anything after the increment operation before first calling defer, the same way you see Mutex operations lock and defer a Unlock right after. The reason for this is if a panic occurs but is later recovered and the Mutex (or in your case counter) is used after the recover the defer will still ensure the lock is release (or counter is decremented). This means don't defer a full func block for this, defer the atomic by itself. In your example if close panics the atomic operation doesn't run. </p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传