我试图从发送到套接字的输入流中检索字节值。我用了很多方法,但它总是给我打印字节数组的地址,而不是它的内容。下面是我的客户端和服务器代码。当一个包从客户端发送到服务器时,服务器实例化一个新的线程来处理连接。所以slaveSocket是我想要使用的套接字。
public class TCPClient {
public static void main(String[] args) throws IOException{
Socket socket;
String address;
int port;
String userInput;
String serverResponse;
PrintWriter out;
BufferedReader in;
//read characters from user
BufferedReader stdIn;
if (args.length != 2) {
System.err.println("Usage: java EchoClient <address> <port>");
System.exit(1);
}
byte[] mode = "octet".getBytes(Charset.forName("UTF-8"));
address = args[0];
port = Integer.parseInt(args[1]);
try{
//connect socket to server
socket = new Socket(address, port);
//Construct PrintWriter to write objects to the socket
out = new PrintWriter(socket.getOutputStream(), true);
//Construct BufferedReader to read input from the socket
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//Another reader to read characters typed by the user
stdIn = new BufferedReader(new InputStreamReader(System.in));
//scanner for menu option
Scanner scanner = new Scanner(System.in);
int menuOption;
System.out.println("Press 1 to read from file or 2 to write to file");
menuOption = scanner.nextInt();
if (menuOption == 1){
String filename = "";
String text = "";
System.out.println("Enter file name");
filename = scanner.next();
byte[] packet = new byte[512];
//Constructing the RRQ Packet
//Ading the OPCODE
packet[0] = 1;
//adding the filename
filename.getBytes(Charset.forName("UTF-8"));
byte[] filenameB = filename.getBytes(Charset.forName("UTF-8"));
System.arraycopy(filenameB,0,packet,1, filenameB.length);
//adding a 0
packet[filenameB.length +1] = 0;
//adding the mode
System.arraycopy(mode,0,packet,1+filenameB.length+1,mode.length);
//adding the last 0
packet[1+filenameB.length+1+mode.length+1] = 0;
out.println(packet);
}else if(menuOption == 2){
}
socket.close();
}catch(UnknownHostException e){
System.err.println("Dont know about host" + address);
System.exit(1);
}catch(IOException e){
System.err.println("Couldnt get I/O for the connection to " + address);
System.exit(1);
}
}
}
public class TCPServer {
public static void main(String[] args) throws IOException{
//port of the server
int port = 10000;
//Socket objects
ServerSocket masterSocket;
Socket slaveSocket;
//instantiate the server socket
masterSocket = new ServerSocket(port);
System.out.println("Server Started");
boolean flag1 = true;
while(true){
slaveSocket = masterSocket.accept();
System.out.println("Accepted TCP connection from: " +
slaveSocket.getInetAddress() + ", " + slaveSocket.getPort() + "...");
System.out.println("Initialising new Thread...");
new TCPServerThread(slaveSocket).start();
}
}
}
public class TCPServerThread extends Thread{
private Socket slaveSocket = null;
public TCPServerThread(Socket socket){
super("TCPServerThread");
this.slaveSocket = socket;
}
public void run(){
byte[] ClientPacket = new byte[512];
PrintWriter socketOutput;
InputStream socketInput;
try{
//send packet to client
socketOutput = new PrintWriter((slaveSocket.getOutputStream()), true);
//read packet from client
socketInput = new DataInputStream(slaveSocket.getInputStream());
ClientPacket = socketInput.readAllBytes();
System.out.println(new String(ClientPacket, StandardCharsets.UTF_8));
}catch (IOException e){
System.err.println(e);
}
}
}
你无可救药地夸大了这一点。
Writer
和Reader
进行字符输入和输出<代码>输入流和输出流
执行字节输入和输出。
你把基于字节的东西(最后,网络端口是基于字节的,而不是基于字符的)以危险的方式变成基于字符的东西,然后试图读写基于字符的东西。
解决办法很简单。别再这样了。你有基于字节的东西,绝对没有必要涉及到读写器。
一堆引起问题的行:
out.println(packet);
PrintStreams是调试辅助工具。你不能用它们来做这些。例如,这一行将打印换行符(在基于字节的流系统中绝对不是你想要的东西!),并将打印“对象”——它通过调用来实现。toString()
方法,而数组的toString方法基本上是无用的。这就解释了为什么你看到了你所看到的。这不是发送字节的方式。你不能将字节发送到打印流
(这是一个混乱的混乱,因为它试图让你将字符发送到基于字节的系统。正如我所说,你使用它进行调试,而不是其他。你不应该在这里使用它)。
new InputStreamReader(socket.getInputStream())
这很危险。你正在把一个基于字节的系统(InputStream
)变成一个基于字符的系统(Reader
),这总是意味着有人在对字符集编码做出明确的“带外”(不是基于该流中的数据)决定。在这种情况下,根据InputStreamReader的文档,你会得到“平台默认值”。幸运的是,从JDK18开始,它肯定是UTF-8,但在那之前,谁知道它是什么。你永远不想调用这个构造函数来避免混淆。新输入流读取器(socket.get输入流,标准字符集。UTF_8)
。
不过,最重要的是,首先不要成为一个读者。你对读取字符流毫无兴趣,你只需要字节。
如果字符串较小,并且关于它们“结束”的信息是“带外”完成的(例如:首先发送字节(而不是字符)的大小,然后发送字符串的X字节,UTF_8编码),您可以将其读取为字节,然后在此基础上生成字符串,绕过对Readers和Writer的任何需求。Reader和Writer只有在整个流都是基于字符的情况下才有用,或者如果您有巨大的字符串(数百兆字节),则只能通过首先将数据解释为字符来猜测它们的结束。(大多数情况下,这些协议都很糟糕,不应该使用)。
//Construct PrintWriter to write objects to the socket
不,不能将对象写入套接字。对象不是字节。您可以将字节写入套接字;有些对象会让自己变成ByTestStream,但这绝对不是一件小事,PrintWriter
根本做不到。
catch (IOException e) { System.err.println(e);
大多数代码都没有合理的途径来“处理”它们,但解决方法是继续使用它们。为了不抓住例外,打印一张绝望的便条,然后像什么都没发生一样继续下去。正确的做法也会减少代码,因此,双赢。
stdIn = new BufferedReader(new InputStreamReader(System.in));
//scanner for menu option
Scanner scanner = new Scanner(System.in);
你在用两种不同的方式读取标准输入。这没有意义。选一个。
我试着帮你修好它:
public class TCPClient {
public static void main(String[] args) throws Exception { // always throw Exception from `main`.
if (args.length != 2) {
System.err.println("Usage: java EchoClient <address> <port>");
System.exit(1);
return; // Always return after System.exit.
}
byte[] mode = "octet".getBytes(Charset.forName("UTF-8"));
String address = args[0];
int port = Integer.parseInt(args[1]);
Scanner scanner = new Scanner(System.in);
scanner.useDelimiter("\\R"); // split on newlines, not spaces. So much more logical.
// resources need to be safe-closed - use try-with!
try (var socket = new Socket(address, port);
var out = new BufferedOutputStream(socket.getOutputStream());
var in = socket.getInputStream()) {
System.out.println("Press 1 to read from file or 2 to write to file");
int menuOption = scanner.nextInt();
if (menuOption == 1) {
System.out.println("Enter file name");
String filename = scanner.next();
//Constructing the RRQ Packet
//Adding the OPCODE
out.write(1);
out.write(filename.getBytes(StandardCharsets.UTF_8));
out.write(0);
// The above is dangerous; NUL (0) is actually a valid char.
// A proper way to send strings is to send length in bytes
// first. I'll leave it to you to fix your protocol.
// If it can't be fixed, scan for `\0` chars and get rid of em.
//adding the mode
out.write(mode);
out.write(0);
}else if (menuOption == 2) {
}
}
}
一次发送一个字节可能很慢(因为它最终发送了整个包),但也可能很有用——数据只是被发送,而不是等待更多数据的很长时间。在你的情况下,你一次发送所有数据,所以非常快地发送所有数据不是一个好主意。因此,为什么输出流被包装在BufferedOutputStream中,它可以修复这个问题。如果你想保持连接打开,你可以随时使用flush()
强制发送(关闭()
,自然,也刷新)。
如果您想使用byte[]包
,这很好,但是在这里看起来很复杂,也不必要。out.write(某个ByteArray)
,其中out
是某种类型的输出流,工作正常。out.println(byteArray)
,其中out是某种类型的Writer,或PrintStream-根本不工作。(它需要数组,调用它不有用的toString(),然后使用未知的字符集转换这些字节并发送它,这些都不是您想要的)。
您同样需要从服务器代码中删除PrintStream等。
问题内容: 我在React中有一个表单,可以动态添加新的输入元素。这似乎 工作正常,但我似乎无法访问此 屏幕截图中所示的输入值… console.log数组 我尝试了以下 console.log(this.state.telephone.name) 和… console.log(this.state.telephone.tidx.name) 其中tidx是唯一键。 这是构造函数… and this
我想访问来自该对象数组的ends\u数据。。。但我不能让它工作。输出未定义。请帮帮我。
问题内容: 在Java中,如何获取byte []数组并从数组中删除前16个字节?我知道我可能必须通过将阵列复制到新阵列中来执行此操作。任何例子或帮助将不胜感激。 问题答案: 参见Java库中的类:
问题内容: 我正在尝试减少分段数据的锁定对象的内存使用量。这里看到我的问题。或者只是假设您有一个字节数组,并且每16个字节可以(反)序列化为对象。让我们将其称为行长度为16个字节的“行”。现在,如果您从写程序线程中修改这样的行并从多个线程中读取,则需要锁定。如果字节数组大小为1MB(1024 * 1024),则意味着65536行和相同数量的锁。 这有点太多,而且我需要更大的字节数组,并且我想将其减
我正在编写一个程序,处理两个原型消息,我需要处理从不同来源发送的字节[],这些来源发送foo消息或bar消息。由于我无法弄清楚它属于哪个消息,我使用任何类(附带的协议)来解析字节数组并找到它属于哪个类,但遇到了编译时错误。如果我将来添加更多的原型消息类,我可以使用其他方法来检测吗? 第二个原型 代码: 尝试调用any时if语句出错。is(): 方法是(类
问题内容: 所以-我有一个需要a 作为输入的第三方库。我有一个。 我不想将字节写入磁盘..我想将其保留在内存中。我如何从提供的内容创建一个想法(无需写入磁盘)? 问题答案: 抱歉,不可能。除非您具有RAM磁盘,否则File本质上是磁盘上的实体-但这不是您可以用Java创建的东西。 这正是API不应该基于File对象(或过载以接受InputStream)的原因。