我编写客户端服务器应用程序。客户端将在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循环中中断,但是将来我需要此输出。有人知道如何发送服务器未卡住的文件吗?也许我需要以其他方式发送此文件。谢谢你的帮助。

最佳答案

在客户端使用close()实际上并没有多大帮助,因为诸如close()之类的TCP/IP API方法几乎没有用作为在应用程序层发信号通知消息结束的一种手段。这样做的原因是,在客户端关闭TCP流不会立即关闭整个TCP连接,直到到达相对的客户端为止。这与TCP的基础体系结构有关。

您需要做的是实现应用协议(protocol)级别的方法来标识消息的长度,或者以其他方式实现消息“成帧”。对您而言,最简单的操作可能是在消息的开头实现一个基本 header ,该 header 可以只包含四个字节(代表U32消息长度)(例如)。

我要再次强调的关于TCP的一个非常重要的事情是,TCP协议(protocol)本身(尤其是像close()这样的调用)没有提供可靠的信号来通知正在通过TCP发送的应用程序消息的开始/停止。必须将TCP视为协议(protocol),因为这正是它的含义。因此,您还必须在该流中放入一些特殊的 header ,该 header 具有长度字段,成帧字符或其他指示接收端何时从.read()调用中读取足够的信息的方式,以使其具有完整的消息。

我最近创建了一个Android应用程序,该应用程序使用TCP套接字与服务器C#应用程序进行通信,即使我仅通过流发送简单且相对较短的消息,但我发现实现非常基本的消息框架和消息头绝对是必不可少的。

发出消息的长度或结尾的信号应该在应用程序协议(protocol)级别完成。

同样,也应该在应用程序协议(protocol)级别完成发信号通知TCP连接应该被两端关闭。当您搜索StackOverflow时,经常会遇到许多人在检测TCP连接是否已“关闭”时遇到问题。问题在于,这是内在的错误处理方式。任何语言的TCP套接字API都无法可靠地告诉您流已关闭。

如果查看HTTP(这是使用TCP套接字的流行协议(protocol)的示例),您会看到该协议(protocol)利用了表示长度的 header ,表示连接的标志将关闭以及消息是否被分段等。在。

回到您的特定问题,您应该在Android端的第一个write()中执行的操作是构造并编写一个包含长度字段的简单消息 header 。在服务器端,第一个read()应该期望在文件有效负载开始之前看到此 header 。然后,使用该 header 中提供的长度来确定何时对所有文件进行read()编码。

稍后,您可以扩展 header 以包含CRC值之类的内容。

关于android - Android的Java和套接字,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8111194/

10-12 00:33
查看更多