7

我必须将一个短字符串作为文本从客户端发送到服务器,然后再发送一个二进制文件。

如何使用相同的套接字连接发送二进制文件和字符串?

服务器是 java 桌面应用程序,客户端是 Android 平板电脑。我已经将其设置为在客户端和服务器之间双向发送短信。我还没有完成二进制文件发送部分。

一种想法是设置两个同时运行的独立服务器。我认为如果我使用两个不同的端口号并在应用程序中的两个不同线程上设置服务器,这是可能的。而且我必须在 Android 应用程序的两个服务上设置两个并发客户端。

另一个想法是以某种方式使用 if else 语句来确定正在发送两种类型的文件中的哪一种,无论是二进制文本,并使用适当的方法来接收正在发送的文件类型的文件。

发送文本的示例代码

 PrintWriter out;
 BufferedReader in;

out = new PrintWriter(new BufferedWriter
(new OutputStreamWriter(Socket.getOutputStream())) true,);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

out.println("test out");
String message = in.readLine();

发送二进制文件的示例代码

 BufferedOutputStream out;
 BufferedInputStream in;
 byte[] buffer = new byte[];
 int length = 0;

 out = new BufferedOutputStream(new FileOutputStream("test.pdf));
 in = new BufferedInputStream(new FileOutputStream("replacement.pdf"));

 while((length = in.read(buffer)) > 0 ){
 out.write(buffer, 0, length);
 }
4

3 回答 3

6

我认为在您的情况下不需要使用两个线程。发送短信后,只需使用socket'sInputStream和即可发送二进制数据。OutputStream

服务器代码

OutputStream stream = socket.getOutputStream();
PrintWriter out = new PrintWriter(
    new BufferedWriter(
        new OutputStreamWriter(stream)
    )
);
out.println("test output");
out.flush(); // ensure that the string is not buffered by the BufferedWriter

byte[] data = getBinaryDataSomehow();
stream.write(data);

客户代码

InputStream stream = socket.getInputStream();
String message = readLineFrom(stream);

int dataSize = getSizeOfBinaryDataSomehow();
int totalBytesRead = 0;
byte[] data = new byte[dataSize];

while (totalBytesRead < dataSize) {
    int bytesRemaining = dataSize - totalBytesRead;
    int bytesRead = stream.read(data, totalBytesRead, bytesRemaining);

    if (bytesRead == -1) {
        return; // socket has been closed
    }

    totalBytesRead += bytesRead;
}

为了确定dataSize客户端的正确性,您必须以某种方式传输二进制块的大小。您可以在服务器代码之前将其作为字符串发送,out.flush()或者将其作为二进制数据的一部分。在后一种情况下,前四个或八个字节可以保存二进制数据的实际长度(以字节为单位)。

希望这可以帮助。


编辑

正如@EJP 正确指出的那样,BufferedReader在客户端使用 a 可能会导致二进制数据损坏或丢失,因为BufferedReader“窃取”二进制数据中的一些字节以填充其缓冲区。相反,您应该自己读取字符串数据,然后查找分隔符或通过其他方式传输字符串数据的长度。

/* Reads all bytes from the specified stream until it finds a line feed character (\n).
 * For simplicity's sake I'm reading one character at a time.
 * It might be better to use a PushbackInputStream, read more bytes at
 * once, and push the surplus bytes back into the stream...
 */
private static String readLineFrom(InputStream stream) throws IOException {
    InputStreamReader reader = new InputStreamReader(stream);
    StringBuffer buffer = new StringBuffer();

    for (int character = reader.read(); character != -1; character = reader.read()) {
        if (character == '\n')
            break;
        buffer.append((char)character);
    }

    return buffer.toString();
}
于 2013-09-06T07:53:12.890 回答
0

您可以阅读 HTTP 协议的工作原理,它本质上发送“ascii 和人类可读”标头(可以这么说),然后可以使用适当的编码(例如 base64)添加任何内容。你可以自己创造类似的东西。

于 2013-09-06T07:30:20.140 回答
0

您需要先发送字符串,然后是字节数组的大小,然后是字节数组,使用String.startsWith()方法检查正在发送的内容。

于 2014-02-16T11:49:31.703 回答