douguanya6399 2017-06-15 04:21
浏览 46
已采纳

如何在不阻止服务器的情况下通过tcp将数据发送到客户端?

I'm writing a game server and as this is my first time, I've been wondering how to send packets to the client without lagging the server.
Even if the client is lagging, packets should be sent to them. (Not sure if this is the right thing to do, but if I don't send packets to them, the client won't be in sync) So here's my idea at first:

Each player gets 2 goroutines when they connect: one for sending and other for receiving.

// in the server main loop
select {
    case player.sendChan <- somepacket:
    default:
}

// this is sendChan:
p.sendChan := make(chan Packet, 100)

// in server player's sending loop (in their own goroutine)
for {
    packet := <- p.sendChan:
    sendPacket(packet) // this will block
}

So here the server's mainloop can send at most 100 packets to the player channel without blocking, while the sendPacket is blocking (due to lag maybe).
But the problem is if the player is blocking after 100 packets, the server will stop. That is obviously bad. And Go has no way to specify unbounded channels.

Then I thought about launching a new gorouting for each sendPacket but that seems like it would waste too much system resources and make the whole thing slow.

So the question is: What is the best way? I don't think the server should waste resources for a laggy client, but at the same time, they should be sent all packets. Is there a better way to do this? (I'm not sure how it's done in the real world so any other solutions would be fine too)

  • 写回答

1条回答 默认 最新

  • 普通网友 2017-06-15 07:35
    关注

    Try this approach based on the Gorilla Chat Example:

    In the server main loop:

    select {
        case player.sendChan <- somepacket:
        default:
           // The player cannot receive the packet. Close channel to
           // signal the player to exit. 
           close(player.sendChan)
    
           // Remove the player from server's collection of players
           // to avoid sending to closed channel.
           ...
    
           // Let the player's sending loop close the connection 
           // and do other cleanup.
    }
    

    This is sendChan:

    p.sendChan := make(chan Packet, 100)
    

    In server player's sending loop (in their own goroutine):

    // Loop will exit when p.sendChan is closed.
    for packet := range p.sendChan {
        // Always write with a deadline.
        p.conn.SetWriteDeadline(time.Now().Add(writeWait))
        err := sendPacket(packet)
        // Break out of write loop on any error.
        if err != nil {
           break
        }
    }
    // We reach this point on error sending packet or close on p.sendChan.
    // Remove the player from the server's collection, close the connection and
    // do any necessary cleanup for the player.
    ...
    

    展开全部

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
编辑
预览

报告相同问题?

手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部