【发布时间】:2018-08-16 21:55:47
【问题描述】:
我在输入/输出流方面遇到了另一个问题。在这里,我将数据从服务器发送到客户端。在发送数据之前,服务器会发送一个小字符串来告诉客户端他将发送什么,这样客户端就知道他应该使用哪个函数来接收。
我很好地接收了第一个字符串,但是我没有得到好的整数,之后我收到的第二个字符串是“null”。
此外,如果我在将 DataOutputStream 与 dos.writeInt 一起使用之前执行 System.out.println,则一切正常。 我不明白。这是代码:
服务器:
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.SecureRandom;
public class Server {
private static OutputStream out;
static byte[] generateRandomBytes(int len) {
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[len];
random.nextBytes(bytes);
return bytes;
}
public static void sendType(String type) {
PrintWriter textWriter = new PrintWriter(out);
textWriter.println(type);
textWriter.flush();
}
public static void sendKeyNumber(int keyNumber) {
sendType("keyNumber");
try {
DataOutputStream dos = new DataOutputStream(out);
//System.out.println("Sending key number: " + keyNumber);
dos.writeInt(keyNumber);
//dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void sendKey(byte[] key) {
sendType("key");
try {
DataOutputStream dos = new DataOutputStream(out);
//System.out.println("key length to send: " +key.length);
dos.writeInt(key.length); // write length of the byte array
//dos.flush();
dos.write(key);
//dos.flush();
System.out.println("key send: " +key);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Socket clientSocket ;
System.out.println("ouverture du server");
try {
ServerSocket serverSocket = new ServerSocket(2004);
clientSocket = serverSocket.accept();
out = clientSocket.getOutputStream();
sendKeyNumber(0);
byte[] keyBytes = generateRandomBytes(32);
sendKey(keyBytes);
clientSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
客户:
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.crypto.spec.SecretKeySpec;
public class Main {
static InputStream in;
public static int receiveKeyNumber() {
DataInputStream dis = new DataInputStream(in);
int keyNumber = 0;
try {
keyNumber = dis.readInt();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return keyNumber;
}
public static SecretKeySpec receiveKey() {
DataInputStream dIn = new DataInputStream(in);
int length;
byte[] keyBytes = null;
try {
length = dIn.readInt(); // read length of incoming message
System.out.println("key length: " + length);
if(length!=32) {
System.err.println("Incorrect size for key: "+ length);
}
else {
keyBytes = new byte[length];
dIn.readFully(keyBytes, 0, keyBytes.length);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SecretKeySpec aesKey = new SecretKeySpec(keyBytes, "AES");
return aesKey;
}
public static void main(String[] args) {
Socket clientSocket;
try {
clientSocket = new Socket(InetAddress.getLocalHost(),2004);
in = clientSocket.getInputStream();
while(!clientSocket.isClosed()) {
BufferedReader textReader = new BufferedReader(new InputStreamReader(in));
String type = textReader.readLine();
System.out.println(type);
if(type.equals("keyNumber")) {
int KN = receiveKeyNumber();
System.out.println(KN);
}
if(type.equals("key")) {
SecretKeySpec key = receiveKey();
System.out.println(key);
}
}
clientSocket.close();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这是我在不执行 System.out.println 时得到的结果(在客户端控制台中):
keyNumber
1801812234
null
我总是得到同一个奇怪的数字;我尝试将其转换为 ASCII,但它不可读。
有什么建议吗?
【问题讨论】:
-
BufferedReader的原理是什么?它的 javadoc 说什么?调用 readLine() 会发生什么?
-
嗯,有人告诉我,当我在一端使用 PrintWriter 时,我应该在另一端使用 BufferedReader。但我也读到 BufferedReader 有点危险,因为他们可以阅读比我们希望他们阅读的内容更多的内容。啊,通常我总是在输出的末尾打印“\r\n”;在此处添加它会导致 keyNumber 被正确接收,第二个字符串也是如此。但是我的“receiveKey”函数的“readInt”行仍然出错。
-
我还读到 BufferedReader 有点危险,因为它们可以读取比我们希望它们读取的更多的内容。对,就是这样。它设计就是为了做到这一点:你要求一行,它会将 8096 个字符(或任何大小的缓冲区)读入 缓冲区 以加快处理速度。所以,在你读完这一行之后,实际上你从输入流中读到的不仅仅是一行。因此,您接下来读取的 int 实际上是这 8096 个字符之后的 4 个字节,而不是您编写的 int。
-
最简单的解决方法是更改协议。对类型使用单个字节(这会产生 256 种可能的类型,这可能比您需要的要多得多),并且只在一侧使用 DataOutputSTream,在另一侧使用 DataInputStream。
-
我以后还要使用 ObjectInputStream。这也会是个问题吗?
标签: java system.out dataoutputstream