如何从 Java 网络获取某些数据类型作为消息 ID

How to get certain data types from Java networking as the message id

我正在开发多人游戏,它是在 GameMaker 工作室创建的。我已经在 game maker 中创建了一个服务器和一个客户端,它们工作得很好,但是 game maker 服务器不能 运行 在任何虚拟机上,因为它必须使用 DirectX。

所以我想重写 Java 中的服务器,这会大大扩展我的选择范围。我看了很多教程,我只看到人们发送 "strings" 作为消息,我想用字节替换它。因为在我在 GameMaker 中创建的服务器中,我使用消息 ID 来标识每条消息应该引用的位置。这些是我阅读的行:

buffer_seek(buffer, buffer_seek_start, 0);
var mid = buffer_read(buffer, buffer_u8);
switch(mid) {

    case 0: 

但据我所知,在 Java 中只有一个输入流。我怎样才能像下面的代码那样拆分该消息: (GameMaker 的网络异步事件(服务器的))

    case network_type_data:

var buffer = ds_map_find_value(async_load, "buffer");
var socket = ds_map_find_value(async_load, "id");

buffer_seek(buffer, buffer_seek_start, 0);
var mid = buffer_read(buffer, buffer_u8);
switch(mid) {

    case 0: 
    //let's updated the first information we can get whether the user is registering or loging in
    //Reads what username was assigned to player
    var username = buffer_read(buffer, buffer_string);
    //Updates information of players
    UpdatePlayerInfo("name", username, socket);
    SendRoomList(1, socket);
    break;

    case 1: //player wants to create a server
    //find the name of the player
        show_debug_message("a player created a room");
       if(Room_exists(socket) == false and PlayerInRoom(socket) == false) {
        var Room = CreateRoom(socket, 2);


        JoinRoom(socket, Room);  
        SendRoomList(1, socket);
    }
    break;

    case 2: //player wants to join the server

     var desired_room = buffer_read(buffer, buffer_u8); 
     if(PlayerInRoom(socket) == false) {
     JoinRoom(socket, desired_room);
     }

    break;



    }
}

Java 的 ByteBuffer 是一个良好的开端,可以从简单的流中获取 String 以外的项目。本质上,您从 TCP 输入流中获取一大块字节到一个 ByteBuffer 实例中,然后您可以调用 getInt()、getDouble() 和其他类似的方法来从中获取基本类型。

下面是它的一些用法,与问题中的脚本类似。

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;


public class JavaIo {

    // number of bytes in a user name
    private static final int SIZE_OF_USER_NAME = 30;
    // number of bytes in the internal buffer
    private static final int BUFFER_SIZE = 1024;

    public void workWithConnection() {
        final int portNumber = 12345; // TODO: read this from config file or command line arguments instead
        try (
                ServerSocket server = new ServerSocket(portNumber);
                Socket connection = server.accept();
                SocketChannel channel = connection.getChannel();
        ) {
            final ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
            channel.read(buffer);   // fill buffer from the input stream
            // since your buffer in GameMaker is unsigned, let's prevent all that signed to unsigned nonsense by doing a
            // bitmask
            final int mid = buffer.get() & 0x000000FF;
            switch(mid) {
                case 0:
                    // grab some bytes from the buffer and change them into a String
                    final byte[] usernameBytes = new byte[SIZE_OF_USER_NAME];
                    buffer.get(usernameBytes);
                    final String username = new String( usernameBytes, Charset.forName(StandardCharsets.UTF_8.name()));
                    // ...
                    break;
                case 1:
                    // grab 4 bytes from the buffer and change it into an integer
                    final int roomId = buffer.getInt();
                    // ...
                    break;
                default:
                    // ...
            }
        } catch(IOException ioe) {
            // TODO: handle exception
        }
    }

}

参考文献:

Convert a byte array to integer in java and vice versa

http://www.ibm.com/developerworks/java/tutorials/j-nio/j-nio.html