Last few chars in a string sent over socket sometimes missing in Java network program

孤街醉人 提交于 2020-12-26 14:45:03

问题


Right now, I'm trying to write a GUI based Java tic-tac-toe game that functions over a network connection. It essentially works at this point, however I have an intermittent error in which several chars sent over the network connection are lost during gameplay. One case looked like this, when println statements were added to message sends/reads:

Player 1: Just sent ROW 14 COLUMN 11 GAMEOVER true

Player 2: Just received ROW 14 COLUMN 11 GAMEOV

Im pretty sure the error is happening when I read over the network. The read takes place in its own thread, with a BufferedReader wrapped around the socket's InputStream, and looks like this:

try {
        int input;
        while((input = dataIn.read()) != -1 ){
            char msgChar = (char)input;
            String message = msgChar + "";
           while(dataIn.ready()){
               msgChar = (char)dataIn.read();
               message+= msgChar;
           }
           System.out.println("Just received " + message);
           this.processMessage(message);

        }
        this.sock.close();


    } 

My sendMessage method is pretty simple, (just a write over a DataOutputStream wrapped around the socket's outputstream) so I don't think the problem is happening there:

try {
        dataOut.writeBytes(message);
        System.out.println("Just sent " + message);
    } 

Any thoughts would be highly appreciated. Thanks!


回答1:


As it turns out, the ready() method guaruntees only that the next read WON'T block. Consequently, !ready() does not guaruntee that the next read WILL block. Just that it could.

I believe that the problem here had to do with the TCP stack itself. Being stream-oriented, when bytes were written to the socket, TCP makes no guarantees as to the order or grouping of the bytes it sends. I suspect that the TCP stack was breaking up the sent string in a way that made sense to it, and that in the process, the ready() method must detect some sort of underlying break in the stream, and return false, in spite of the fact that more information is available.

I refactored the code to add a newline character to every message send, then simply performed a readLine() instead. This allowed my network protocol to be dependent on the newline character as a message delimiter, rather than the ready() method. I'm happy to say this fixed the problem.

Thanks for all your input!




回答2:


Try flushing the OutputStream on the sender side. The last bytes might remain in some intenal buffers.




回答3:


It is really important what types of streamed objects you use to operate with data. It seems to me that this troubleshooting is created by the fact that you use DataOutputStream for sending info, but something else for receiving. Try to send and receive info by DataOutputStream and DataInputStream respectively.

Matter fact, if you send something by calling dataOut.writeBoolean(b) but trying to receive this thing by calling dataIn.readString(), you will eventually get nothing. DataInputStream and DataOutputStream are type-sensitive. Try to refactor your code keeping it in mind.

Moreover, some input streams return on invocation of read() a single byte. Here you try to convert this one single byte into char, while in java char by default consists of two bytes.

       msgChar = (char)dataIn.read();

Check whether it is a reason of data loss.



来源:https://stackoverflow.com/questions/30141635/last-few-chars-in-a-string-sent-over-socket-sometimes-missing-in-java-network-pr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!