我在Java中使用套接字编程时遇到问题。 有一个像python这样的服务器,我不应该改变它。
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send('from server\nnewline\0')
data = s.recv(BUFFER_SIZE)
s.close()
现在我想用Java编写一个从服务器读取字符串的代码。像这样:
public static String readStr(Socket client) throws IOException {
InputStreamReader inStream = new InputStreamReader(
client.getInputStream());
BufferedReader inBuff = new BufferedReader(inStream);
String answer = new String();
String str = inBuff.readLine();
while (str!=null) {
answer = answer.concat(str + "\n");
str = inBuff.readLine();
}
answer = answer.substring(0, answer.length() - 1);
System.out.println("answer:\n "+answer);
return answer;
}
但它似乎在消息的最后一行阻止了str = inBuff.readLine();
行。我尝试了read()
方法,但它也被阻止了。
答案 0 :(得分:0)
这可能是因为服务器发送的最后一行没有结束,readLine()方法只在到达行尾时返回。因为您更改了服务器的代码。我建议您使用另一种方法从流中读取。您也可以使用InputStreamReader类。
答案 1 :(得分:0)
在tcp上设计协议时,最好的方法是包含某种成帧器。这是通过使用 NUL 字节在当前协议中完成的。
从套接字读取数据时,在解析各个块之前,应先通过某些操作将其划分为块/帧。
将数据包分成块的粗略方法是读取,直到找到 NUL 字节,然后将该块作为字节数组返回。 (这不是最有效的实现)
public byte[] readPacket(InputStream in) throws IOException {
ByteArrayOutputStream tempStr = new ByteArrayOutputStream();
int read;
read=in.read();
while(read > 0){
tempStr.write(read);
read=in.read();
}
if(read == -1)
throw new EOFException();
return tempStr.toByteArray();
}
因为您现在拥有适当的数据框架,所以现在可以轻松读取数据:
byte[] frame = readPacket(in);
String[] lines = new String(frame, StandardCharsets.UTF8).split("\n");
// Do something with the lines
答案 2 :(得分:0)
除了已经提到的不一致的消息/行结束 - 一次使用\n
,第二次使用\0
,在服务器上没有检测到消息的结束。因此,只要套接字未在客户端关闭(或关闭以进行写入),服务器就会循环。因为你在关闭套接字之前有这一行:
data = s.recv(BUFFER_SIZE)
换句话说,客户端正在等待来自服务器的一些响应。但是服务器永远停留在循环中从客户端读取消息。
因此,您需要在recv
调用之前关闭套接字或发送一些消息(如空行)并在服务器上检测并最终退出循环。