GAME MAKER 강좌
KAYAN
◈ 채팅 메시지 보내기
이제 본격적으로 서버와 클라이언트 간에 메시지를 주고 받아봅시다.
먼저, 이전에 채팅 테스트를 했던 obj_chat 오브젝트의 [Step 이벤트] 내용을 지웁니다.
그리고 서버 오브젝트에 [Step 이벤트]를 추가하고, 채팅 메시지를 접속한 클라이언트에게 보내도록 합니다.
★ obj_server 오브젝트 - Step 이벤트 ★ if keyboard_check_pressed( vk_enter ){ keyboard_string = string_replace_all( keyboard_string, "\n", "" ); if string_length( keyboard_string )>100{ keyboard_string = string_copy( keyboard_string, 1, 100 ); } if !( keyboard_string == "" ){ // == == == var t = "[서버관리자]["+string( global.playername )+"]"+keyboard_string; ds_list_add( global.chat_list, t ); var i, sock; for ( var i = 0; i < ds_list_size( global.socketlist ); i++; ) { sock = ds_list_find_value( global.socketlist, i ); buffer_seek( global.net_buffer, buffer_seek_start, 0 ); buffer_write( global.net_buffer, buffer_u16, 5 ); //패킷 이벤트 번호 buffer_write( global.net_buffer, buffer_string, t ); network_send_packet( sock, global.net_buffer, buffer_tell( global.net_buffer ) ); } // == == == keyboard_string = ""; } } |
채팅 메시지는 클라이언트의 5번 수신 이벤트로 보낼 겁니다.
그러면 클라이언트 오브젝트 [네트워크 비동기 이벤트]의 5번 수신 이벤트에서 패킷을 정리합니다.
★ obj_client 오브젝트 - Async - Networking 이벤트 ★ var n_id = ds_map_find_value( async_load, "id" ); if n_id == global.client_socket{ //서버로 부터 받은 패킷 데이터 // == == == == == == == == == == == == == == var type = ds_map_find_value( async_load, "type" ); if ( type == network_type_data ){ var t_buffer = ds_map_find_value( async_load, "buffer" ); var cmd_type = buffer_read( t_buffer, buffer_u16 ); switch ( cmd_type ){ //--------- 클라이언트 세부 정보 갱신 case 1: global.server_name = buffer_read( t_buffer, buffer_string ); var t = buffer_read( t_buffer, buffer_string ); ds_map_destroy( global.player_map ); global.player_map = json_decode( buffer_read( t_buffer, buffer_string ) ); //접속자들 정보 ds_list_add( global.chat_list, t ); break; //--------- 클라이언트 세부 정보 갱신 //--------- 서버에 처음 접속했을 때 case 2: var _id = buffer_read( t_buffer, buffer_u16 ); var t = buffer_read( t_buffer, buffer_string ); global.user_id = _id; ds_list_add( global.chat_list, t ); break; //--------- 서버에 처음 접속했을 때 //--------- ▼ 챗팅 case 5: var t = buffer_read( t_buffer, buffer_string ); ds_list_add( global.chat_list, t ); break; //--------- ▲ 챗팅 } } // == == == == == == == == == == == == == == } |
버퍼를 읽고, 채팅글로 추가합니다.
이제 클라이언트도 채팅 메시지를 서버로 보내 봅시다.
클라이언트 오브젝트에 [Step 이벤트]를 추가하고, 서버로 메시지를 보냅니다.
★ obj_client 오브젝트 - Step 이벤트 ★ if keyboard_check_pressed( vk_enter ){ keyboard_string = string_replace_all( keyboard_string, "\n", "" ); if string_length( keyboard_string )>100{ keyboard_string = string_copy( keyboard_string, 1, 100 ); } if !( keyboard_string == "" ){ // == == == buffer_seek( global.net_buffer, buffer_seek_start, 0 ); buffer_write( global.net_buffer, buffer_u16, 5 ); //패킷 이벤트 번호 buffer_write( global.net_buffer, buffer_string, "["+global.playername+"]"+keyboard_string ); network_send_packet( global.client_socket, global.net_buffer, buffer_tell( global.net_buffer ) ); // == == == keyboard_string = ""; } } |
수신 이벤트 번호를 서버와 클라이언트가 다르게 처리할 수 있지만, 코딩할 떄 동일한 번호로 처리하는 것이
수정하거나 확인하기가 좋습니다.
강좌에서는 서버에서도 클라이언트와 동일하게 5번 수신 이벤트에서 처리하겠습니다.
서버 오브젝트 [네트워크 비동기 이벤트]의 5번 수신 이벤트에서 클라이언트가 보낸 메시지 패킷을 정리합니다.
★ obj_server 오브젝트 - Async - Networking 이벤트 ★ var n_id = ds_map_find_value( async_load, "id" ); //--------- 서버 IP 체크 if n_id = global.local_socket{ var _ip = ds_map_find_value( async_load, "ip" ); global.local_server_IP = _ip; exit; } //--------- 서버 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: var t = buffer_read( t_buffer, buffer_string ); ds_list_add( global.chat_list, t ); //받은 메시지는 다시 모든 클라이언트에게 보냄 buffer_seek( global.net_buffer, buffer_seek_start, 0 ); buffer_write( global.net_buffer , buffer_u16, 5 ); //패킷 번호 buffer_write( global.net_buffer , buffer_string, t ); 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 ) ); } break; } //--------- ▲ 클라이언트 데이터 수신 } |
당연하지만, 클라이언트가 여러명일 경우, 클라이언트 1명이 보낸 메시지는 서버밖에 모릅니다.
따라서 서버는 다른 클라이언트에게도 메시지를 보내주어야 채팅 참여자 모두가 메시지를 확인할 수 있습니다.
◈ 네트워크 비동기 이벤트 종합 정리
여기까지 [네트워크 비동기 이벤트]를 어떻게 구성했는지 정리해봅시다.
먼저 서버 오브젝트의 [네트워크 비동기 이벤트]입니다.
★ obj_server 오브젝트 - Async - Networking 이벤트 ★ var n_id = ds_map_find_value( async_load, "id" ); //--------- 서버 IP 체크 if n_id = global.local_socket{ var _ip = ds_map_find_value( async_load, "ip" ); global.local_server_IP = _ip; exit; } //--------- 서버 IP 체크 if n_id == global.server_socket{ //--------- 클라이언트 연결/해제 체크 var type = ds_map_find_value( async_load, "type" ); switch( type ){ case network_type_connect://현재 소켓에 새로운 클라이언트 접속 var sock = ds_map_find_value( async_load, "socket" ); ds_list_add( global.socketlist, sock ); buffer_seek( global.net_buffer, buffer_seek_start, 0 ); buffer_write( global.net_buffer , buffer_u16, 2 ); //패킷 이벤트 번호 buffer_write( global.net_buffer , buffer_u16, sock ); //접속자에게 유저 id 할당 buffer_write( global.net_buffer , buffer_string, "환영합니다!" ); network_send_packet( sock, global.net_buffer, buffer_tell( global.net_buffer ) ); global.client_ping[sock] = 0; //ping 체크 // break; case network_type_disconnect://현재 소켓에 클라이언트 연결 종료 var sock = ds_map_find_value( async_load, "socket" ); var t, pos; pos = ds_list_find_index( global.socketlist, sock ); ds_list_delete( global.socketlist, pos ); //클라이언트 소켓 t = "["+string( ds_map_find_value( global.player_map, "player_"+string( sock ) ) )+"]님이 나갔습니다."; ds_list_add( global.chat_list, t ); 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 ) ); } break; } //--------- 클라이언트 연결/해제 체크 } 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: var _name = buffer_read( t_buffer, buffer_string ); //플레이어 이름 ds_map_set( global.player_map, "player_"+string( sock ), string( _name ) ); //서버 챗팅 적용 var t = "["+_name+"]님이 접속하셨습니다."; ds_list_add( global.chat_list, t ); //클라이언트들에게 보낼 접속자 정보 if !( ds_map_exists( global.player_map, "player_order" ) ){ ds_map_add_list( global.player_map, "player_order", global.socketlist ); } else{ ds_map_replace_list( global.player_map, "player_order", global.socketlist ); } 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 ) ); } break; //--------- 새로운 클라이언트 접속시 세부 정보 수신 //--------- 채팅 case 5: var t = buffer_read( t_buffer, buffer_string ); ds_list_add( global.chat_list, t ); // buffer_seek( global.net_buffer, buffer_seek_start, 0 ); buffer_write( global.net_buffer , buffer_u16, 5 ); //패킷 번호 buffer_write( global.net_buffer , buffer_string, t ); 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 ) ); } break; //--------- 채팅 } // == == == == == == == == == == == 클라이언트 데이터 수신 } |
다음은 클라이언트 오브젝트의 [네트워크 비동기 이벤트]를 확인해봅시다.
★ obj_client 오브젝트 - Async - Networking 이벤트 ★ var n_id = ds_map_find_value( async_load, "id" ); if n_id == global.client_socket{ var type = ds_map_find_value( async_load, "type" ); if ( type == network_type_data ){ // == == == == == == == == == == == = 서버로 부터 받은 패킷 데이터 var t_buffer = ds_map_find_value( async_load, "buffer" ); var cmd_type = buffer_read( t_buffer, buffer_u16 ); switch ( cmd_type ){ //--------- 클라이언트 세부 정보 갱신 case 1: global.server_name = buffer_read( t_buffer, buffer_string ); var t = buffer_read( t_buffer, buffer_string ); ds_map_destroy( global.player_map ); global.player_map = json_decode( buffer_read( t_buffer, buffer_string ) ); //접속자들 정보 ds_list_add( global.chat_list, t ); break; //--------- 클라이언트 세부 정보 갱신 //--------- 서버에 처음 접속했을 때 case 2: var _id = buffer_read( t_buffer, buffer_u16 ); var t = buffer_read( t_buffer, buffer_string ); global.user_id = _id; ds_list_add( global.chat_list, t ); break; //--------- 서버에 처음 접속했을 때 //--------- 챗팅 case 5: var t = buffer_read( t_buffer, buffer_string ); ds_list_add( global.chat_list, t ); break; //--------- 챗팅 } // == == == == == == == == == == == = 서버로 부터 받은 패킷 데이터 } } |
이제 서버와 클라이언트간의 대화가 가능해졌습니다.
잘 작동하는지 테스트해봅시다.
'GameMaker강좌[GMS2] > 네트워크강좌' 카테고리의 다른 글
[게임메이커 강좌-네트워킹][GMS2] 채팅 프로그램 만들기-6-네트워크 연결 지연에 따른 설정(Ping) (0) | 2024.12.24 |
---|---|
[게임메이커 강좌-네트워킹][GMS2] 채팅 프로그램 만들기-5-접속자 표시 (0) | 2024.12.24 |
[게임메이커 강좌-네트워킹][GMS2] 채팅 프로그램 만들기-3-메시지 송수신 (0) | 2024.12.23 |
[게임메이커 강좌-네트워킹][GMS2] 채팅 프로그램 만들기-2-서버/클라이언트 (0) | 2024.12.23 |
[게임메이커 강좌-네트워킹][GMS2] 채팅 프로그램 만들기-1-채팅 기본 구성 (0) | 2024.12.21 |
댓글