Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 47 additions & 7 deletions client/src/network/TcpClient.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require("client.src.TimeQueue")
local class = require("common.lib.class")
local Request = require("client.src.network.Request")
local ServerMessages = require("client.src.network.ServerMessages")
local Queue = require("common.lib.Queue")

---@class TcpSocket

Expand All @@ -22,12 +23,18 @@ local ServerMessages = require("client.src.network.ServerMessages")
---@field ip string
---@field port integer
---@field socket TcpSocket
---@field outgoingMessageQueue Queue
---@field sendRetryCount integer
---@field sendRetryLimit integer
local TcpClient = class(function(tcpClient)
-- holds data fragments
tcpClient.data = ""
--connectionUptime counts "E" messages, not seconds
tcpClient.connectionUptime = 0
tcpClient.receivedMessageQueue = ServerQueue()
tcpClient.outgoingMessageQueue = Queue()
tcpClient.sendRetryCount = 0
tcpClient.sendRetryLimit = 5
tcpClient.delayedProcessing = false
math.randomseed(os.time())
for i = 1, 4 do
Expand Down Expand Up @@ -97,18 +104,46 @@ function TcpClient:resetNetwork()
self.socket:close()
end
self.socket = nil
self.outgoingMessageQueue:clear()
end

function TcpClient:sendMessage(stringData)
if self:isConnected() then
local fullMessageSent, error, partialBytesSent = self.socket:send(stringData)
---@return boolean # if the connection is still considered open
function TcpClient:sendQueuedMessages()
while self.outgoingMessageQueue:len() > 0 do
local message = self.outgoingMessageQueue:peek()
local fullMessageSent, error, partialBytesSent = self.socket:send(message)
if fullMessageSent then
--logger.trace("json bytes sent in one go: " .. tostring(fullMessageSent))
return true
else
logger.error("Error sending network message: " .. (error or "") .. " only sent " .. (partialBytesSent or "0") .. "bytes")
self.outgoingMessageQueue:pop()
if self.sendRetryCount > 0 then
logger.debug("TcpClient retry succeeded after " .. self.sendRetryCount)
self.sendRetryCount = 0
end
elseif error == "closed" then
return false
elseif error == "timeout" and partialBytesSent and partialBytesSent > 0 then
local remaining = message:sub(partialBytesSent + 1)
self.outgoingMessageQueue[self.outgoingMessageQueue.first] = remaining
logger.trace("TcpClient partial send: " .. partialBytesSent .. "/" .. #message .. " bytes sent. " .. #remaining .. " bytes remain in queue.")
break
else
self.sendRetryCount = self.sendRetryCount + 1
logger.trace("TcpClient send timeout with no progress (retry " .. self.sendRetryCount .. "/" .. self.sendRetryLimit .. ")")
break
end
end

if self.sendRetryCount >= self.sendRetryLimit then
logger.info("TcpClient send failed after " .. self.sendRetryLimit .. " retries were attempted")
return false
end

return true
end

function TcpClient:sendMessage(stringData)
if self:isConnected() then
self.outgoingMessageQueue:push(stringData)
return self:sendQueuedMessages()
else
return false
end
Expand All @@ -129,6 +164,11 @@ function TcpClient:updateNetwork(dt)
self:queueMessage(data[1], data[2])
data = self.receiveNetworkQueue:popIfReady()
end
else
-- In non-delayed mode, try to send any queued messages
if self:isConnected() then
self:sendQueuedMessages()
end
end
end

Expand Down
37 changes: 20 additions & 17 deletions server/Connection.lua
Original file line number Diff line number Diff line change
Expand Up @@ -122,27 +122,30 @@ end
---@param connection Connection
---@return boolean # if the connection is still considered open
local function sendQueuedMessages(connection)
for i = connection.outgoingMessageQueue.first, connection.outgoingMessageQueue.last do
local message = connection.outgoingMessageQueue[i]
local success, error = connection.socket:send(message)
if not success then
if error == "closed" then
return false
else
connection.sendRetryCount = connection.sendRetryCount + 1
break
while connection.outgoingMessageQueue:len() > 0 do
local message = connection.outgoingMessageQueue:peek()
local fullMessageSent, error, partialBytesSent = connection.socket:send(message)
if fullMessageSent then
connection.outgoingMessageQueue:pop()
if connection.sendRetryCount > 0 then
logger.debug(connection.index .. " Retry succeeded after " .. connection.sendRetryCount)
connection.sendRetryCount = 0
end
elseif connection.sendRetryCount > 0 then
logger.debug(connection.index .. " Retry succeeded after " .. connection.sendRetryCount)
connection.sendRetryCount = 0
elseif error == "closed" then
return false
elseif error == "timeout" and partialBytesSent and partialBytesSent > 0 then
local remaining = message:sub(partialBytesSent + 1)
connection.outgoingMessageQueue[connection.outgoingMessageQueue.first] = remaining
logger.trace("Partial send: " .. partialBytesSent .. "/" .. #message .. " bytes sent. " .. #remaining .. " bytes remain in queue.")
break
else
connection.sendRetryCount = connection.sendRetryCount + 1
logger.trace("Send timeout with no progress (retry " .. connection.sendRetryCount .. "/" .. connection.sendRetryLimit .. ")")
break
end
end

if connection.sendRetryCount == 0 then
if connection.outgoingMessageQueue:len() > 0 then
connection.outgoingMessageQueue:clear()
end
elseif connection.sendRetryCount >= connection.sendRetryLimit then
if connection.sendRetryCount >= connection.sendRetryLimit then
logger.info("Closing connection " .. connection.index .. ". Connection.send failed after " .. connection.sendRetryLimit .. " retries were attempted")
return false
end
Expand Down
Loading