2011-11-13 101 views
1

我编写客户端 - 服务器应用程序。客户端将在普通的java上运行在android和服务器上。我需要将数据从客户端交换到服务器,然后从服务器交换到客户端。我的问题是,当我从客户端发送文件到服务器时,服务器停留在从套接字接收数据上。这里是我的代码:android java和套接字

客户端发送文件:

Log.i("======", "sendToServer=============="); 
    OutputStream output = sk.getOutputStream();  

    String pathToOurFile = directory + File.separator + file; 

    FileInputStream fileInputStream = new FileInputStream(pathToOurFile); 
    byte[] buffer = new byte[sk.getSendBufferSize()]; 
    int bytesRead = 0; 

    while((bytesRead = fileInputStream.read(buffer))>0) 
    { 
     output.write(buffer,0,bytesRead); 
    } 

    fileInputStream.close(); 

服务器获取数据:

System.out.println("I get data"); 
    File file=null; 

    InputStream input = sk.getInputStream(); 

    file = new File("C://protocolFIle/" + "temp.xml"); 
    FileOutputStream out = new FileOutputStream(file); 

    byte[] buffer = new byte[sk.getReceiveBufferSize()]; 

    int bytesReceived = 0; 

    while((bytesReceived = input.read(buffer))>0) { 
     out.write(buffer,0,bytesReceived); 
    } 

    return file; 

服务器停留在服务器端线

while((bytesReceived = input.read(buffer))>0) { 
     out.write(buffer,0,bytesReceived); 
    } 

。当我发送数据时,我想我需要在客户端以某种方式发出信号。我知道我可以在客户端编写“output.close()”,然后服务器获取文件并在while循环中断开,但我将来需要此输出。有谁知道我怎么能发送这个文件,服务器不卡住?也许我需要以另一种方式发送此文件。谢谢你的帮助。

回答

2

在客户端使用close()实际上不会有太大的帮助,因为诸如close()之类的TCP/IP API方法几乎没有任何意义,因为它是在应用层发信号结束消息的手段。原因是在客户端关闭TCP流不会立即关闭整个TCP连接直到对端客户端。这与TCP的底层体系结构有关。

你需要做的是实现一个应用协议级别的方法来识别消息的长度,或者其他一些其他手段的消息“框架”。要做的最简单的事情可能是在消息的开始处实现一个基本的头文件,它可能只包含四个字节,代表U32消息长度(例如)。

我会再次强调TCP的一个重要的事情是,TCP协议本身,特别是像close()这样的调用,并不提供可靠地指示您通过TCP发送的应用程序消息开始/停止的方式。 TCP必须被认为是协议,因为这正是它的原理;因此,您还必须在该流中放入一些带有长度字段的特殊标题或帧字符,或者其他方式指示接收端在拨打电话时是否已读取足够的内容,以使其具有完整的消息。

我最近创建了一个使用TCP套接字与服务器C#应用程序对话的Android应用程序,即使我只是通过流发送简单且相对较短的消息,我发现实现非常基本的消息成帧和消息头是绝对必要。

信令消息的长度或结束应该在应用协议级完成。

此外,通知两端应关闭TCP连接也应在应用程序协议级别完成。当您搜索StackOverflow时,您经常会遇到许多人在检测TCP连接是否已关闭时遇到问题。问题在于,这是一种固有的错误的方式,任何语言的TCP套接字API都不能可靠地告诉你一个流已经关闭。

如果你看一下HTTP,这是一个使用TCP套接字的流行协议的例子,你将会看到这个协议使用了指示长度的标题,指示连接的标志应该关闭,以及一条消息是碎片化等等。

回到您的特定问题,您应该在Android侧的第一个write()中执行什么操作,然后编写一个包含长度字段的简单消息头。在服务器端,第一个read()应该在文件有效载荷开始之前看到这个标题。然后使用该标题中提供的长度来确定何时有read()所有文件。

您可以稍后扩展您的标题以包含CRC值等内容。