Java 套接字流的可靠性如何';s flush()是什么?
考虑一下这段(简化的)代码:Java 套接字流的可靠性如何';s flush()是什么?,java,android,networking,tcp,Java,Android,Networking,Tcp,考虑一下这段(简化的)代码: public class Test { // assigned elsewhere InetSocketAddress socketAddress; String socketHost; int socketPort; Socket socket; int COMMAND = 10; int CONNECTION_TIMEOUT = 10 * 1000; int SOCKET_TIMEOUT = 30
public class Test {
// assigned elsewhere
InetSocketAddress socketAddress;
String socketHost;
int socketPort;
Socket socket;
int COMMAND = 10;
int CONNECTION_TIMEOUT = 10 * 1000;
int SOCKET_TIMEOUT = 30 * 1000;
DataOutputStream dos;
DataInputStream dis;
protected void connect() throws IOException, InterruptedException {
socket.connect(socketAddress != null ? socketAddress : new InetSocketAddress(socketHost, socketPort), CONNECTION_TIMEOUT);
socket.setSoTimeout(SOCKET_TIMEOUT);
socket.setTcpNoDelay(true);
}
void initializeDataStreams() throws IOException {
dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(), socket.getSendBufferSize()));
dis = new DataInputStream( new BufferedInputStream( socket.getInputStream(), socket.getReceiveBufferSize()));
}
void run() {
try {
connect();
initializeDataStreams();
sendCommand(COMMAND, true);
sendIdAndUsername(true);
sendSyncPreference(true);
sendBlockedIds(true);
sendHeaders();
// reading from 'dis' here
// ...
} catch (InterruptedException | IOException e){
/* ... */
}
}
void sendCommand(int command, boolean buffered) throws IOException {
dos.write(command);
if (!buffered) {
dos.flush();
}
}
void sendIdAndUsername(boolean buffered) throws IOException {
sendId(true); // always buffered
String username = "user name";
dos.writeBoolean(username != null);
if (username != null) {
dos.writeUTF(username);
}
if (!buffered) {
dos.flush();
}
}
void sendId(boolean buffered) throws IOException {
dos.writeUTF("user id");
if (!buffered) {
dos.flush();
}
}
void sendSyncPreference(boolean buffered) throws IOException {
boolean fullSync = true;
dos.writeBoolean(fullSync);
if (!buffered) {
dos.flush();
}
}
void sendBlockedIds(boolean buffered) throws IOException {
Set<String> blockedCrocoIds = new HashSet<>();
ObjectOutputStream oos = new ObjectOutputStream(dos);
oos.writeObject(blockedCrocoIds);
if (!buffered) {
oos.flush();
}
}
private void sendHeaders() throws IOException {
dos.writeUTF("some string");
dos.writeInt(123);
// some other writes...
// this should flush everything, right?
dos.flush();
}
}
然后:
public class ListeningThread extends Thread {
private ServerSocket serverSocket;
public ListeningThread() {
try {
// unbound server socket
serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(NetworkUtil.APP_SERVER_PORT));
} catch (IOException e) {
log(e);
}
}
@Override
public void run() {
log("run");
while (serverSocket.isBound() && !isInterrupted()) {
try {
Socket socket = serverSocket.accept();
new CommandThread(socket).start();
} catch (IOException e) {
log(e);
}
}
try {
serverSocket.close();
} catch (IOException e) {
log(e);
}
}
}
最后:
public class CommandThread extends Thread {
private final Socket socket;
public CommandThread(Socket socket) {
log("CommandThread");
this.socket = socket;
}
@Override
public void run() {
log("run");
try {
socket.setSoTimeout(NetworkUtil.SOCKET_TIMEOUT);
socket.setTcpNoDelay(true);
InputStream is = socket.getInputStream();
int cmd = is.read(); // <========= so actually this is failing
switch (cmd) {
// handling of the command
case COMMAND:
new DownloadMessagesThread(socket).start();
break;
}
} catch (IOException | SQLException e) {
log(e);
}
}
}
public类CommandThread扩展线程{
专用终端插座;
公共命令线程(套接字){
日志(“命令线程”);
this.socket=socket;
}
@凌驾
公开募捐{
日志(“运行”);
试一试{
socket.setSortimeout(NetworkUtil.socket\u超时);
socket.setTcpNoDelay(true);
InputStream=socket.getInputStream();
int cmd=is.read();//您应该验证在sendblockedds
中创建的ObjectOutputStream
不是罪魁祸首。
在混合数据流和ObjectStreams时,我已经遇到了一些协议“死锁”,因为ObjectStreams的编写器/读取器对的创建意味着一种握手,在混合这些流时可能会失败
编辑:当再次阅读您的问题时,我意识到我没有回答它。因此,是的,它是可靠的。EJP答案为+1。要回答您标题中的问题,它是100%可靠的,因为它不做任何事情。只有flush()
缓冲流的方法实际上可以做任何事情,并且只包括ObjectOutputStream
和BufferedOutputStream
,以及PrintStream
,这取决于您如何构造它。不是DataOutputStream
,也不是套接字本身的输出流
因此,在本例中,唯一可以执行任何操作的flush方法是缓冲输出流,您当然可以依赖它,因为它只是代码,已经工作了20年
如果这影响了accept()
的速度,那么您的accept循环肯定有一些奇怪的地方,您没有告诉我们:通常,在accept循环中而不是在启动的线程中执行I/O
您当然不应该在连接的中间创建<代码> ObjutOutsStudio。在开始时创建它,并将其用于所有的内容,另一方面使用<代码> ObjutsPosivsStuts
注意:将缓冲区大小分别设置为套接字缓冲区大小实际上是毫无意义的。默认值是足够的。我建议使用JSON之类的表示,而不是发送二进制对象。我知道你的意思,我也有同样的痛苦。然而,ObjectOutputStream的构造函数只是通过str发送几个字节eam,仅此而已。因此,即使有一些可怕的错误,它至少会到达accept()在服务器端,不是吗?如果这几个字节没有刷新,那么服务器端ObjectInputStream的构造函数将不会在超时时间内退出。我们可能需要服务器代码来进一步帮助您。@Xvolks:100%同意,这可能会导致问题的出现。但是正如前面提到的,服务器端甚至没有达到ac之外的点cept(),因此,无论发生什么,它都没有机会这样做,就像传输在22秒后才在客户端发生一样(我有来自服务端的完整日志,所以我可以看到它当时到达了侦听器…).为了安全起见,我添加了服务器代码。缓冲区大小设置不是我想出来的,我在Esmond Pitt的Java基本网络中看到了它,所以我认为他知道自己在做什么。知道什么会导致发送过程中出现如此严重的延迟吗?如果我在FNIJ中写下,我会收回它。什么页面?延迟只能由网络c造成条件或效果,而不是你的代码。大多数发送应该只需要一两秒钟,除非接收者非常备份和落后。第42页,第331页,也在书中提供的可用示例源代码中。哇。我在想什么?在大约2001-2年写了这篇文章:从那时起,我必须通过Obj“完善”我的想法。”只有当您调用writeObject()
时,才会分配数KBs的“数KBs”才是真的,它不是“数KBs”,而是哈希映射中的一个插槽。如果您调用writeUTF()
,writeInt()
等,则根本没有内存使用。发布非真实代码的代码是徒劳的。
public class CommandThread extends Thread {
private final Socket socket;
public CommandThread(Socket socket) {
log("CommandThread");
this.socket = socket;
}
@Override
public void run() {
log("run");
try {
socket.setSoTimeout(NetworkUtil.SOCKET_TIMEOUT);
socket.setTcpNoDelay(true);
InputStream is = socket.getInputStream();
int cmd = is.read(); // <========= so actually this is failing
switch (cmd) {
// handling of the command
case COMMAND:
new DownloadMessagesThread(socket).start();
break;
}
} catch (IOException | SQLException e) {
log(e);
}
}
}