Java TCP Client-send被阻止了?

时间:2011-04-29 08:40:47

标签: java sockets tcp

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

  1. 服务器将二进制msg(len)的长度发送到客户端(java)
  2. 客户端发送“ok”字符串
  3. 服务器发送二进制文件,客户端分配一个'len'字节的字节数组来接收它。
  4. 它再次发回“ok”。
  5. 步骤1.工作。我得到“len”的价值。但是,客户端“发送被阻止”,服务器等待接收数据。

    任何人都可以看看。

    在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个字节的确定。

                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 个答案:

答案 0 :(得分:3)

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

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

如果你不能这样做,你可能需要一次只读一个字节,直到看到代表\n的字节,然后将你读到的内容转换为文本,解析它,然后将其余部分作为一个块读取。这效率稍低(一次读取一个字节而不是一次读取一个缓冲区),但我想在那时读取的数据量非常小。

答案 1 :(得分:0)

几点想法:

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

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

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

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

请注意,TCP可以在接下来的两周内以10个字节的块自由传送数据:) - 因为封装,不同的硬件等等使得很难分辨最终将在两者之间使用的数据包的大小两个同行,大多数应用程序正在寻找特定数量的数据,而不是使用类似这样的代码填充他们的缓冲区(从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()进行一次,十次或一百次调用,并且您的代码必须能够抵御网络功能的轻微变化。