GAME MAKER 강좌
KAYAN
◈ 네트워크 연결 지연에 따른 설정(Ping)
서버가 종료되거나, 클라이언트의 네트워크가 갑자기 예기치 않게 끊기거나, 오류가 발생해 통신이
안 되는 경우, 또는 네트워크 회선이 좋지 않은 경우 등과 같이 정상적인 종료가 아닌 특수한 상황일 때는
[네트워크 비동기 이벤트]가 발동이 되지 않습니다.
이와 같은 경우 이벤트를 별도로 설정해주어야 합니다.
서버와 클라이언트 간의 네트워크 연결 지연(Ping)에 따른 설정을 구성해봅시다.
먼저 클라이언트에서는 [Alarm 0 이벤트]에서 처리하도록 합시다.
★ obj_client 오브젝트 - Create 이벤트 ★ alarm[0] = 1; //ping 체크 ping = 0; |
클라이언트 [Alarm 0 이벤트]에서 알람 1단위마다 서버의 100 번 수신 이벤트로 메시지를 보냅니다.
이것은 단순히 메시지가 전달되었는지만을 체크하는 것 뿐이에요.
★ obj_client 오브젝트 - Alarm 0 이벤트 ★ //ping 체크 alarm[0] = 1; var _send; buffer_seek( global.net_buffer, buffer_seek_start, 0 ); buffer_write( global.net_buffer , buffer_u16, 100 ); //서버에 보낼 패킷 번호 _send = network_send_packet( global.client_socket, global.net_buffer, buffer_tell( global.net_buffer ) ); if !( _send <= 0 ){ ping = 0; }//패킷 보내기 성공했으면 ping을 0으로 처리 |
패킷을 성공적으로 보내면 ping을 0으로 처리합니다.
하지만, 지연시간이 지정시간을 초과하면 클라이언트는 채팅을 나간 것으로 처리합니다.
★ obj_client 오브젝트 - Alarm 0 이벤트 ★ //ping 체크 alarm[0] = 1; var _send; buffer_seek( global.net_buffer, buffer_seek_start, 0 ); buffer_write( global.net_buffer , buffer_u16, 100 ); //서버에 보낼 패킷 번호 _send = network_send_packet( global.client_socket, global.net_buffer, buffer_tell( global.net_buffer ) ); if !( _send <= 0 ){ ping = 0; } //---------- ▼ var time_out = 60*5; //타임 아웃 ping+ = 1; //ping if ping > time_out{ instance_destroy( ); show_message( "서버에 연결이 되지 않습니다." ); room_goto( room_open ); //메인 화면으로 돌아감 } //---------- ▲ |
이번에는 서버에서의 처리입니다.
서버에서는 클라이언트 수만큼 처리해야 합니다.
일단 지연시간을 처리하기위해 배열로 클라이언트 수만큼 생성합니다.
★ obj_server 오브젝트 - Create 이벤트 ★ global.client_ping = array_create( global.player_max+10, 0 ); //클라이언트 ping 체크 alarm[1] = 1; |
클라이언트가 서버의 100 번 수신 이벤트로 패킷을 보냈으므로 100번 수신 이벤트에서
해당 클라이언트의 ping 을 0으로 처리합니다.
★ obj_server 오브젝트 - Async - Networking 이벤트 ★ var n_id = ds_map_find_value( async_load, "id" ); if n_id = global.local_socket{ //--------- 서버 IP 체크 ... //--------- 서버 IP 체크 } if n_id == global.server_socket{ //--------- 클라이언트 연결/해제 이벤트 ... //--------- 클라이언트 연결/해제 이벤트 } else{ var sock = ds_map_find_value( async_load, "id" ); //클라이언트 소켓 var t_buffer = ds_map_find_value( async_load, "buffer" ); //버퍼 var cmd_type = buffer_read( t_buffer, buffer_u16 ); //수신 패킷 이벤트 번호 var pos = ds_list_find_index( global.socketlist, sock ); //저장한 소켓 목록 switch ( cmd_type ){ case 1: // 새로운 클라이언트 접속시 세부 정보 수신... break; case 5: // 클라이언트 데이터 수신... break; //--------- ▼ 클라이언트 PING 체크 case 100: global.client_ping[sock] = 0; break; //--------- ▲ 클라이언트 PING 체크 } |
그리고 서버 오브젝트의 [Alarm 1 이벤트]에서 모든 클라이언트의 ping을 체크합니다.
★ obj_server 오브젝트 - Alarm 1 이벤트 ★ alarm[1] = 1; // ping 체크 var time_out = 60*5; //클라이언트 연결 지연 초과 시간 var n, i, k, sock; n = ds_list_size( global.socketlist ); k = 0; repeat( n ){ sock = ds_list_find_value( global.socketlist, k ); //클라이언트 검색 global.client_ping[sock]+ = 1; //지연 시간 체크 if ( global.client_ping[sock]< = time_out ){ k+ = 1; }//지정시간 이내면 다음 클라이언트 체크 } |
지연시간이 지정시간을 초과하면 클라이언트는 채팅을 나간 것으로 처리합니다.
★ obj_server 오브젝트 - Alarm 1 이벤트 ★ alarm[1] = 1; // ping 체크 var time_out = 60*5; //클라이언트 연결 지연 초과 시간 var n, i, k, sock; n = ds_list_size( global.socketlist ); k = 0; repeat( n ){ sock = ds_list_find_value( global.socketlist, k ); //클라이언트 검색 global.client_ping[sock]+ = 1; //지연 시간 체크 if ( global.client_ping[sock] <= time_out ){ k+ = 1; }//지정시간내면 다음 클라이언트 체크 //--------- ▼ 연결 지연이 지정한 시간보다 초과되면 해당 클라이언트 삭제 else{ var t, pos; pos = ds_list_find_index( global.socketlist, sock ); t = "["+string( ds_map_find_value( global.player_map, "player_"+string( sock ) ) )+"]님이 나갔습니다."; ds_list_add( global.chat_list, t ); //클라이언트 정보 삭제 ds_list_delete( global.socketlist, pos ); if ds_map_exists( global.player_map, "player_"+string( sock ) ) { ds_map_delete( global.player_map, "player_"+string( sock ) ); } //클라이언트들에게 보낼 접속자 정보 var _map = json_encode( global.player_map ); // buffer_seek( global.net_buffer, buffer_seek_start, 0 ); buffer_write( global.net_buffer , buffer_u16, 1 ); //패킷 이벤트 번호 buffer_write( global.net_buffer , buffer_string, global.playername ); //서버 관리자 닉네임 buffer_write( global.net_buffer , buffer_string, t ); //챗 buffer_write( global.net_buffer , buffer_string, _map ); //클라이언트 정보 for ( var i = 0; i < ds_list_size( global.socketlist ); i+ = 1; ){ network_send_packet( ds_list_find_value( global.socketlist, i ), global.net_buffer, buffer_tell( global.net_buffer ) ); } } //--------- ▲ 연결 지연이 지정한 시간보다 초과되면 해당 클라이언트 삭제 } |
지연 시간이 초과된 클라이언트는 삭제하고, 정보를 갱신하도록 다른 클라이언트에게 새 데이터를 보냅니다.
단순하지만, 기본적인 기능만있는 채팅 프로그램이 만들어졌습니다.
강좌는 여기까지입니다.
복잡하다고보면 복잡할 수 있고, 단순하다면 단순할 수 있는 강좌였다고 볼 수 있겠네요.
강좌에서는 간단하게 어떻게 메시지를 주고 받는지를 중점을 두었지만, 여러분들은 좀 더 채팅다운 앱을 제작하실 수 있을 겁니다.
잠깐! 중요한 부분이 아직 남았습니다.
게임메이커는 윈도우 창모드일 떄, 드래그하면 게임이 멈추게 됩니다.
(▲ 게임이 멈춤)
네트워크 게임은 게임이 멈추게되면 정상적으로 패킷을 주고 받을 수 가 없어 문제가 발생할 수 있어요.
이렇게 되면 게임이 멈춘 클라이언트는 Ping값이 초과되어 게임에서 강제로 나가게 됩니다.
서버도 예외는 아니죠.
서버가 멈추게되면 다른 클라이언트는 자동으로 게임이 종료가 됩니다.
아래의 익스텐션을 추가 적용시키면 드래그하더라도 게임이 멈추는 것을 방지할 수 있습니다.
----------- 패키지파일 -----------
(▲ 게임은 계속 작동함)
적용방법은 간단합니다.
상단 메뉴의 Tools ▶ Import Local Package 를 눌러 첨부 패키지를 추가합니다.
추가하면 익스텐션들과 오브젝트 1개가 추가되는데 이 오브젝트(obj_frame_freeze_fix)를 게임 시작 룸에 배치하면 됩니다.
(▲ 오브젝트)
(▲ 룸에 배치)
그리고 이 익스텐션은 윈도우 내부에 윈도우 보더를 별도로 생성해 사용하기 때문에 게임 옵션의 윈도우 보더는 비활성화해야 합니다.
윈도우 보더 비활성화는 [Game Option]▶[Windows]▶[Graphics]에서 Borderless Window 항목을 체크하면 됩니다.
'GameMaker강좌[GMS2] > 네트워크강좌' 카테고리의 다른 글
[게임메이커 강좌-네트워크][GMS2] 멀티플레이어 게임 만들기-2-서버 만들기 (0) | 2024.12.25 |
---|---|
[게임메이커 강좌-네트워크][GMS2] 멀티 플레이어 게임 만들기-1-메인화면 (1) | 2024.12.25 |
[게임메이커 강좌-네트워킹][GMS2] 채팅 프로그램 만들기-5-접속자 표시 (0) | 2024.12.24 |
[게임메이커 강좌-네트워킹][GMS2] 채팅 프로그램 만들기-4-채팅 메시지 보내기 (0) | 2024.12.24 |
[게임메이커 강좌-네트워킹][GMS2] 채팅 프로그램 만들기-3-메시지 송수신 (0) | 2024.12.23 |
댓글