0

我的问题是如何以 1024 字节的包裹从服务器示例“切割”接收数据,因为当答案来自服务器的数据包(如 2 部分)时,我不知道如何解决这个问题。前任。当第一个数据包到达时,服务器通知的大小是1988,收到的是1444,没关系,但是当第二个数据包到达时,通知的大小是808333347,收到540,1444 + 540 = 1984之和是对的. 我不知道这个号码 808333347 是从哪里来的。我正在搜索这个解决方案,然后所有人都使用 udp 进行教学,我需要这个用于 tcp/ip 连接。请帮助我,解决这个问题。

班上:

public class Connection implements Runnable {
    private static  Connection     instance;
    private         SocketChannel  channel        = null;
    private         int            port           = 0;
    private         int            service        = 0;
    private final   int            SOCKET_TIMEOUT = 15 * 1000;
    private final   int            SOCKET_BYTES   = 16 * 1024;
    private final   Charset        CHARSET        = Charset.forName("ISO-8859-1");
    private         String         host           = null; 
    private         String         message        = "";

public Connection(String host, String port){
    this.host       = host;
    this.port       = Integer.parseInt(port);
}
public static Connection createConnection(String host, String port) {
     if(instance == null){
        instance = new Conexao(host, port);
     }
     return instance;
}
public void connect(){
    try{
        instance.channel = SocketChannel.open();
        instance.channel.socket().setSoTimeout(SOCKET_TIMEOUT);
        instance.channel.socket().setTcpNoDelay(false);
        instance.channel.socket().setKeepAlive(true);
        instance.channel.connect(new InetSocketAddress(host, port));
        instance.channel.configureBlocking(false);
    } catch (IOException ioe){
        Log.d(TAG, ioe.getMessage() + " " + ioe.toString());
    }
}
@Override public void run() {
    if(null != instance.channel){
        if(instance.channel.isConnected()){
            Log.d(TAG, "CHANNEL CONNECTED = TRUE");
        } else {
            Log.d(TAG, "CHANNEL CONNECTED = FALSE");
        }
    } else {
        instance.connect();
        Log.d(TAG, "CHANNEL CONNECTED");
    }
    sendMessage();
    while(true){
        receiveMessage();
    }
}
public void sendMessage() {
    int         size    = message.length();
    ByteBuffer  buffer  = ByteBuffer.allocate(4 + 4 + size);
    buffer.putInt(service).putInt(size).put(message.getBytes());
    buffer.flip();
    for(int i = 0; i < size; i++){
        try {
            instance.channel.write(buffer);
        } catch (IOException ioe) {
            Log.d(TAG, ioe.getMessage() + " " + ioe.toString());
        }
    }
}
public void receiveMessage(){
    ByteBuffer  buffer      = ByteBuffer.allocateDirect(SOCKET_BYTES);
    int         bytesReaded = 0;
    String      received    = "";
    buffer.clear();
    try {
        do {
            bytesReaded = instance.channel.read(buffer);
        } while (bytesReaded == 0);
    } catch (IOException ioe) {
        Log.d(TAG, ioe.getMessage() + " " + ioe.toString());
    }
    buffer.flip();
    int size    =  buffer.getInt();
    received    += CHARSET.decode(buffer);
    Log.d(TAG,"SERVIÇE: " + size + "/" + received.length() + " MSG: " + received);
}
public int getService() {
    return service;
}
public void setService(int service) {
    this.service = service;
}
public String getMessage() {
    return message;
}
public void setMessage(String message) {
    this.message = message;
}

我改变了这样的功能:

public void receiveMessage(){
    ByteBuffer  buffer      = ByteBuffer.allocateDirect(SOCKET_BYTES);
    int         bytesReaded = 0;
    String      received    = "";
    buffer.clear();
    try {
        bytesReaded = instance.channel.read(buffer);
    } catch (IOException ioe) {
        Log.d(TAG, ioe.getMessage() + " " + ioe.toString());
    }
    buffer.flip();
    if(bytesReaded >= 4){
        if(size == 0 && size < 5000) size = buffer.getInt();
        received    += CHARSET.decode(buffer);
        answer      += received;
        if(size == answer.length()){
            Log.d(TAG,"SERVICE: " + size + "/" + answer.length() + " " + answer);
        }
    }
}

但是现在非常难看。

4

2 回答 2

0

您无法控制数据如何从任何一端到达 TCP 连接。它可以一次到达一个字节,也可以以任何其他数量到达数据大小。您必须在接收端循环,直到您拥有所需的一切。您需要为套接字的大小使用相同的读取缓冲区,以便您可以为此循环累积数据,并保留可能属于后续消息的任何数据。

“通知大小”不能像您所说的那么大。这只是一个错误的结果。可能你已经不同步了。

于 2013-10-06T20:26:56.380 回答
0

问题在于,使用 TCP,您无法控制数据的发送方式(分段)。你不知道用 . 读取了多少数据channel.read(...)

receiveMessage()在一个循环中调用,在那里您将读取的数据填充到缓冲区中。

你不能确定

int size    =  buffer.getInt();

是您收到的消息的大小(仅在第一次调用中,如果您收到至少 4 个字节。)。您必须记住前 4 个接收到的字节,即大小,(因为您使用getInt()),然后您必须记住,channel.read(...)直到您收到size 个字节,然后 -> 处理下一条消息。

还可以重新使用您的缓冲区。由于您使用NIO(且非阻塞),我也建议您使用select(), 而不是忙于阅读。

于 2013-10-06T20:41:53.487 回答