首页 文章

Java TCP Client-send被阻止了?

提问于
浏览
1

我正在编写一个与C服务器通信的Java TCP客户端 . 我必须在两者之间交替发送和接收 . 这是我的代码 .

  • 服务器将二进制msg(len)的长度发送给客户端(java)

  • 客户端发送"ok"字符串

  • 服务器发送二进制文件并且客户端分配一个'len'字节的字节数组来接收它 .

  • 它再次发送回"ok" .

第1步 . 工作 . 我得到“len”的 Value . 但是,客户端获取“发送被阻止”,服务器等待接收数据 .

任何人都可以看看 .

在try块中我定义了:

Socket echoSocket = new Socket("192.168.178.20",2400);
            OutputStream os = echoSocket.getOutputStream();       
            InputStream ins = echoSocket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(ins));

            String fromPU = null;


            if( (fromPU = br.readLine()) !=  null){
            System.out.println("Pu returns  as="+fromPU);  

            len = Integer.parseInt(fromPU.trim());
            System.out.println("value of len from PU="+len);

            byte[] str = "Ok\n".getBytes();
            os.write(str, 0, str.length);
            os.flush();

            byte[] buffer = new byte[len];
            int bytes;
            StringBuilder curMsg = new StringBuilder();
            bytes =ins.read(buffer);
            System.out.println("bytes="+bytes); 
            curMsg.append(new String(buffer, 0, bytes));            
            System.out.println("ciphertext="+curMsg); 
                    os.write(str, 0, str.length);
            os.flush();
            }

更新:

这是我的代码 . 目前,任何一方都没有recv或发送阻止 . 但是,无论是使用Buffered Reader还是DataInput Stream阅读器,我都无法发送ok消息 . 在服务器端,我获得了大量的字节而不是2个字节的ok .

Socket echoSocket = new Socket("192.168.178.20",2400);
            OutputStream os = echoSocket.getOutputStream();   
            InputStream ins = echoSocket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(ins));
            DataInputStream dis = new DataInputStream(ins);
            DataOutputStream dos = new DataOutputStream(os);
            if( (fromPU = dis.readLine()) !=  null){
            //if( (fromPU = br.readLine()) !=  null){
            System.out.println("PU Server returns length as="+fromPU);      
            len = Integer.parseInt(fromPU.trim());
            byte[] str = "Ok".getBytes();
            System.out.println("str.length="+str.length);
            dos.writeInt(str.length);
            if (str.length > 0) {
                    dos.write(str, 0, str.length);
                 System.out.println("sent ok");
            }
            byte[] buffer = new byte[len];
            int bytes;
            StringBuilder curMsg = new StringBuilder();
            bytes =ins.read(buffer);
            System.out.println("bytes="+bytes); 
                curMsg.append(new String(buffer, 0, bytes));            
                System.out.println("binarytext="+curMsg); 

            dos.writeInt(str.length);
            if (str.length > 0) {
                    dos.write(str, 0, str.length);
                 System.out.println("sent ok");
            }

2 回答

  • 3

    在流周围使用 BufferedReader 然后尝试从流中读取二进制数据是一个坏主意 . 如果服务器实际上一次性发送了所有数据,并且 BufferedReader 已经读取了二进制数据以及它返回的行,我不会感到惊讶 .

    你在控制协议吗?如果是这样,我建议你改变它以将数据长度发送为二进制(例如固定的4字节),这样你就不需要弄清楚如何在文本和二进制之间切换(这基本上是一种痛苦) .

    如果你可以't do that, you' ll可能只需要一次读取一个字节开始直到你看到代表 \n 的字节,然后转换你've read into text, parse it, and then read the rest as a chunk. That'的效率稍低(一次读取一个字节而不是一次读取一个缓冲区)但我想在那时读取的数据量非常小 .

  • 0

    几点想法:

    len = Integer.parseInt(fromPU.trim());

    你应该检查给定的大小与最大值有关 . 您的服务器不太可能向客户端发送2 GB的消息 . (也许它会,但可能有更好的设计 . :)你通常不想分配多少内存,远程客户端要求你分配 . 这是一种容易远程拒绝服务攻击的方法 .

    BufferedReader br = new BufferedReader(new InputStreamReader(ins));
    / * ...... * /
    bytes = ins.read(buffer);

    也许你的 BufferedReader 吸收了太多的数据? (服务器在继续之前是否等待 Ok ?)您是否确定在附加 BufferedReader 对象后允许您从底层的 InputStreamReader 对象中读取?

    请注意,TCP可以在接下来的两周内以十个字节的形式自由传递数据:) - 因为封装,不同的硬件等等使得很难分辨出最终将在两个对等体之间使用的数据包的大小,大多数寻找特定数据量的应用程序将使用类似这样的代码来填充缓冲区(在Unix环境中从高级编程中窃取,这是一本很好的书;可惜代码在C中,你的代码是在Java中,但是原理是一样的):

    ssize_t             /* Read "n" bytes from a descriptor  */
    readn(int fd, void *ptr, size_t n)
    {
        size_t      nleft;
        ssize_t     nread;
    
        nleft = n;
        while (nleft > 0) {
            if ((nread = read(fd, ptr, nleft)) < 0) {
                if (nleft == n)
                    return(-1); /* error, return -1 */
                else
                    break;      /* error, return amount read so far */
            } else if (nread == 0) {
                break;          /* EOF */
            }
            nleft -= nread;
            ptr   += nread;
        }
        return(n - nleft);      /* return >= 0 */
    }
    

    需要注意的是,填充缓冲区可能会对 read() 进行一次,十次或一百次调用,并且您的代码必须能够抵御网络功能的轻微变化 .

相关问题