|
2D-программирование Вопросы, касающиеся двумерного программирования |
02.10.2014, 21:41
|
#1
|
ПроЭктировщик
Регистрация: 02.10.2014
Сообщений: 102
Написано 5 полезных сообщений (для 25 пользователей)
|
TCP\IP клиент-сервер загвоздка
Доброго времени суток!
Разъясните незнающему, пожалуйста, кто в теме:
Сделал образцы сервера и клиента tcp. Работают...
Загвоздка в том, что если запустить 15+ клиентов, то сервер полностью зависает (на приеме пакетов. принт показывает приход 8192 байт с одного потока, в этот момент), пока не прибить некоторое кол-во клиентов.
В чем здесь причина? Неправильный размер пакета, переполнение TCP буфера...? Или еще что-то?
Разъясните кто-нибудь...
сервер:
;//////////////////////////////////////////////////////////////////////
;//////////////////////////////////////////////////////////////////////
;SERVER
;//////////////////////////////////////////////////////////////////////
;//////////////////////////////////////////////////////////////////////
;request code (action id):
;SERVER > CLIENT
;1001 - create player
;1004 - update pos
;CLIENT > SERVER
;1002 - request
;global vars:
Global player_count
Global PACK_SIZE = 536 ;bytes
Global PORT = 49001
Type player_type
Field player_counter
Field x#,y#,z#
Field mesh
Field stream
End Type
;global massives:
Global S_server
Global S_serv_bank = CreateBank(PACK_SIZE)
;default mode for pivots:
Graphics3D 320,240,0,2
;CREATE SERVER:
S_server = CreateTCPServer(PORT)
If Not S_server
RuntimeError "cannot create"
End
Else
Print "created"
End If
;###########################################################################################
;loop
;###########################################################################################
While Not KeyHit(1)
;CONNECT\CREATE NEW PLAYER:
S_define_new_stream()
;READ REQUESTS FROM CLIENT:
For p.player_type = Each player_type
If p.player_type <> Null
If Not Eof(p\stream)
;debug:
If ReadAvail(p\stream) > 0
;DebugLog "incoming bytes: " + ReadAvail(p\stream)
Print "incoming bytes: " + ReadAvail(p\stream)
End If
;debug.
Repeat
If ReadAvail(p\stream) => PACK_SIZE
ReadBytes(S_serv_bank,p\stream,0,PACK_SIZE)
;request code:
If PeekInt(S_serv_bank,0) = 1002
;request type:
inner_request = PeekInt(S_serv_bank,4)
;execute request:
S_request_execute(p.player_type,inner_request)
;send result of request execute to all clients:
x# = EntityX(p\mesh)
y# = EntityY(p\mesh)
z# = EntityZ(p\mesh)
yaw# = EntityYaw#(p\mesh)
p\x = x
p\y = y
p\z = z
pl_id = p\player_counter
ACTION_ID = 1004
S_send_actions_to_all(ACTION_ID,x#,y#,z#,yaw#,pl_id)
End If
End If
Until ReadAvail(p\stream) < PACK_SIZE
Else
Print "client crashed"
Delete p
End If
End If
Next
Wend
;###########################################################################################
Function S_define_new_stream()
;connect\create new player:
;if new stream (client) defined:
S_inner_stream = AcceptTCPStream(S_server)
If S_inner_stream
Print "new player connected"
;NEW PLAYER (local. create pivot like pos\rot clone (header) of client player entity):
p.player_type = New player_type
;player link (stream) = connected stream id:
p\stream = S_inner_stream
;player pivot:
p\mesh = CreatePivot()
;counter (id):
player_count = player_count + 1
Print "count of players: " + player_count
;SEND TO ALL: CREATE NEW PLAYER:
PositionEntity p\mesh,0,0,0
p\player_counter = player_count
pl_id = player_count
x# = EntityX(p\mesh)
y# = EntityY(p\mesh)
z# = EntityZ(p\mesh)
p\x = x
p\y = y
p\z = z
ACTION_ID = 1001
S_send_actions_to_all(ACTION_ID,x#,y#,z#,yaw#,pl_id)
;SEND TO NEW STREAM: ALL EXIST PLAYERS:
For p.player_type = Each player_type
;if not eof:
If Not Eof(S_inner_stream)
;and not self:
If p\player_counter <> player_count
;action id:
PokeInt S_serv_bank,0,1001
;x,y,z
PokeFloat S_serv_bank,4,p\x
PokeFloat S_serv_bank,8,p\y
PokeFloat S_serv_bank,12,p\z
;id
PokeInt S_serv_bank,16,p\player_counter
;send
WriteBytes S_serv_bank,S_inner_stream,0,PACK_SIZE
End If
Else
Print "client crashed"
Delete p
End If
Next
End If
End Function
;###########################################################################################
Function S_request_execute(p.player_type,inner_request)
;execute request:
speed# = 0.9
;request type:
Select inner_request
;z+
Case 1
;move server pivot:
MoveEntity p\mesh,0,0,speed
;z-
Case 2
MoveEntity p\mesh,0,0,-speed
;x+
Case 3
TurnEntity p\mesh,0,1,0
;x-
Case 4
TurnEntity p\mesh,0,-1,0
;y+
; Case 5
; TurnEntity p\mesh,0,1,0
;y-
; Case 6
; TurnEntity p\mesh,0,-1,0
End Select
End Function
;###########################################################################################
Function S_send_actions_to_all(ACTION_ID,x#,y#,z#,yaw#,pl_id)
;send actions to all clients:
For p.player_type = Each player_type
If p.player_type <> Null
If Not Eof(p\stream)
;action:
PokeInt S_serv_bank,0,ACTION_ID
;x,y,z
PokeFloat S_serv_bank,4,x#
PokeFloat S_serv_bank,8,y#
PokeFloat S_serv_bank,12,z#
PokeFloat S_serv_bank,20,yaw#
;id
PokeInt S_serv_bank,16,pl_id
;send:
WriteBytes S_serv_bank,p\stream,0,PACK_SIZE
Else
Print "client crashed"
Delete p
End If
End If
Next
End Function
клиент:
;//////////////////////////////////////////////////////////////////////
;//////////////////////////////////////////////////////////////////////
;CLIENT
;//////////////////////////////////////////////////////////////////////
;//////////////////////////////////////////////////////////////////////
;request code (action id):
;SERVER > CLIENT
;1001 - create player
;1004 - update pos
;CLIENT > SERVER
;1002 - request
;global vars:
Global game_limit_speed = CreateTimer(60)
;
Global PACK_SIZE = 536 ;bytes
Global PORT = 49001
Global IP$ = "localhost" ;set ip here
;
Global player_created
Type player_type
Field player_counter
Field x#,y#,z#
Field mesh
End Type
;global massives:
Global C_server_link
Global C_client_bank = CreateBank(PACK_SIZE)
;graphics:
Graphics3D 640,480,16,2
;3d misc for scene:
Global light = CreateLight(1)
PositionEntity light,0,10,0
Global player_mesh = CreateSphere()
HideEntity player_mesh
Global box = CreateCube()
Global camera = CreateCamera()
PositionEntity camera,0,20,-15
RotateEntity camera,50,0,0
CameraZoom camera,2
CameraFogRange camera,2,100
CameraFogMode camera,True
CameraFogColor camera,150,200,255
CameraClsColor camera,150,200,255
grass=CreateTexture(64,64,1)
SetBuffer TextureBuffer(grass)
ClsColor 22,100,22
Cls
For i=0 To 256
Color 0+Rnd(10),50+Rnd(155),0+Rnd(10)
Plot Rnd(64),Rnd(64)
Next
SetBuffer BackBuffer()
ScaleTexture grass,3,3
Color 255,255,255
ClsColor 0,0,0
plane=CreatePlane()
EntityTexture plane,grass
;CONNECT TO SERVER:
;Print "PRESS ENTER"
Repeat
;If KeyHit(28);enter
C_connect_to_server()
;End If
Until C_server_link <> 0
;###########################################################################################
;loop
;###########################################################################################
period = 1000 / 40
time = MilliSecs() - period
While Not KeyHit(1)
;waiter:
WaitTimer(game_limit_speed)
;fractional remainder:
Repeat
elapsed = MilliSecs() - time
Until elapsed
ticks=elapsed/period
tween#=Float(elapsed Mod period)/Float(period)
For k=1 To ticks
If k=ticks Then CaptureWorld
time=time+period
;##########################
;
calculate_game()
;
;##########################
UpdateWorld
Next
AntiAlias True
RenderWorld tween
;wire:
If KeyHit(57)
wire = 1 - wire
End If
WireFrame wire
;pl.count:
i = 0
For p.player_type = Each player_type
i = i + 1
Next
Text 10,40,i + " - players"
Flip
Wend
;###########################################################################################
Function calculate_game()
;READ REQUESTS FROM SERVER:
If Not Eof(C_server_link)
Repeat
If ReadAvail(C_server_link) => PACK_SIZE
ReadBytes(C_client_bank,C_server_link,0,PACK_SIZE)
;INITIALIZE ME:
If player_created = 0
;create me:
If PeekInt(C_client_bank,0) = 1001
;create me:
p.player_type = New player_type
p\mesh = CopyEntity(player_mesh)
anim_entity = p\mesh
ShowEntity p\mesh
p\player_counter = PeekInt(C_client_bank,16)
x# = PeekFloat(C_client_bank,4)
y# = PeekFloat(C_client_bank,8)
z# = PeekFloat(C_client_bank,12)
PositionEntity p\mesh,x,y,z
;
;player created (me):
player_created = 1
End If
;ALL OTHER ACTIONS:
End If
If player_created = 1
;create other players:
If PeekInt(C_client_bank,0) = 1001
p.player_type = New player_type
p\mesh = CopyEntity(player_mesh)
ShowEntity p\mesh
p\player_counter = PeekInt(C_client_bank,16)
x# = PeekFloat(C_client_bank,4)
y# = PeekFloat(C_client_bank,8)
z# = PeekFloat(C_client_bank,12)
PositionEntity p\mesh,x,y,z
End If
;update pos (me and other):
If PeekInt(C_client_bank,0) = 1004
id = PeekInt(C_client_bank,16)
For p.player_type = Each player_type
If p\player_counter = id
x# = PeekFloat(C_client_bank,4)
y# = PeekFloat(C_client_bank,8)
z# = PeekFloat(C_client_bank,12)
yaw# = PeekFloat(C_client_bank,20)
PositionEntity p\mesh,x,y,z
RotateEntity p\mesh,0,yaw,0
End If
Next
End If
End If
End If
Until ReadAvail(C_server_link) < PACK_SIZE
Else
RuntimeError "server crashed"
End
End If
;SEND REQUESTS TO SERVER:
If player_created = 1
;random player motion:
SeedRnd MilliSecs()
request = Rand(1,4)
C_server_request(request)
;manual motion:
; If KeyDown(200);z+
; request = 1
; C_server_request(request)
; End If
; If KeyDown(208);z-
; request = 2
; C_server_request(request)
; End If
; If KeyDown(205);x+
; request = 3
; C_server_request(request)
; End If
; If KeyDown(203);x-
; request = 4
; C_server_request(request)
; End If
End If
End Function
;###########################################################################################
Function C_connect_to_server()
;connect to server:
Print "connecting..."
C_server_link = OpenTCPStream(IP$,PORT)
If Not C_server_link
RuntimeError "failed"
End
End If
End Function
;###########################################################################################
Function C_server_request(request)
;send request:
If Not Eof(C_server_link)
PokeInt C_client_bank,0,1002
PokeInt C_client_bank,4,request
WriteBytes C_client_bank,C_server_link,0,PACK_SIZE
Else
RuntimeError "server crashed"
End If
End Function
|
(Offline)
|
|
02.10.2014, 23:37
|
#2
|
.
Регистрация: 05.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений (для 6,863 пользователей)
|
Ответ: TCP\IP клиент-сервер загвоздка
Я писал сетевые приложения на блице, были проблемы с 10+ клиентами тоже. Разные, и все очень странные.
В основном дело в том что с сетью в блокирующем контексте работать по опреелению - нельзя. Причин много, и об этом не мало литературы.
Следственно серверные решения нужно писать в асинхронной либо мультипоточной модели.
Первая - асинхронная, показала себя как весьма масштабируемая и применяется в очень большом спектре реальных серверных решений.
Но блиц не поддерживает никакой асинхронности в коде. Я не знаю как там задник сделан, но проблемы я свои еще много лет назад по поводу сети на нем так и не решил.
Рассмотри другие языки для серверной логики.
Также серверная логика не имеет ничего общего к клиентской, та же система Entity и всякие рендеры, коллизия и т.п. - все очень отличается на серверах от клиентов.
Следственно тут не суть важно какое серверное решение ты выберешь, если оно не походит на клинета - это не аргумент вообще.
Если знаешь JS, пиши на node.js - так будет проще стартовать, и быстрее будет результат.
|
(Offline)
|
|
Эти 4 пользователя(ей) сказали Спасибо moka за это полезное сообщение:
|
|
03.10.2014, 00:24
|
#3
|
Зануда с интернетом
Регистрация: 04.09.2005
Сообщений: 14,014
Написано 6,798 полезных сообщений (для 20,935 пользователей)
|
Ответ: TCP\IP клиент-сервер загвоздка
Можно попробовать размазать опрос по времени, внеся правку: читать полученные сообщение не "пока не прочитан PACK целиком", а "N байт и выходить из обработки". Но такая асинхронность выйдет боком: код запутается и станет скорее изыском, лучше, конечно, запилить асинхронность на потоках. Например (при неимении возможности поступить как советует moka), написать dll на чём-то многопоточность поддерживающем, и либо общаться через блокирующие blitz-прогу функции (ЕстьЛиГотовыйПак(), ПролучитьЗагурженныйПак()), либо через общий буфер (число, возвращаемое CreateBank - реальный адрес памяти, который можно использовать в DLL), имеющий маркер (изменяемый атомарно) для управления синхронизацией ("пакет готов","ожидаю следующий пакет") и область под тело пакета.
__________________
http://nabatchikov.com
Мир нужно делать лучше и чище. Иначе, зачем мы живем? tormoz
А я растила сына на преданьях
о принцах, троллях, потайных свиданьях,
погонях, похищениях невест.
Да кто же знал, что сказка душу съест?
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
03.10.2014, 01:21
|
#4
|
ПроЭктировщик
Регистрация: 02.10.2014
Сообщений: 102
Написано 5 полезных сообщений (для 25 пользователей)
|
Ответ: TCP\IP клиент-сервер загвоздка
moka, impersonalis, благодарю вас!
Теперь имею представление о происходящем.
Буду думать над предложениями...
|
(Offline)
|
|
04.10.2014, 16:14
|
#5
|
Разработчик
Регистрация: 06.06.2011
Адрес: Ирк. обл.
Сообщений: 541
Написано 133 полезных сообщений (для 220 пользователей)
|
Ответ: TCP\IP клиент-сервер загвоздка
Проще серверную часть на другом яп. писать . Пиши в лс могу помочь. Даже кодом поделюсь реализации серверной части.
__________________
|
(Offline)
|
|
Сообщение было полезно следующим пользователям:
|
|
04.10.2014, 20:20
|
#6
|
ПроЭктировщик
Регистрация: 02.10.2014
Сообщений: 102
Написано 5 полезных сообщений (для 25 пользователей)
|
Ответ: TCP\IP клиент-сервер загвоздка
L-ee-X, большущее спасибо!
Решил пока что оставить сетевые вопросы, и взяться за другое.
P.S. Если кому-то будет интересно:
В вышеприведенном примере удалось сделать нормальную работу с 54 клиентами (еще больше клиентов "матрица" видеокарты не позволяла шибко, а без граф. режима дописывать и проверять просто не стал), через реализацию ожидания ответа от сервера (ничего не предпринимать) на конкретный запрос клиента.
|
(Offline)
|
|
Ваши права в разделе
|
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 09:05.
|