gpt4 book ai didi

java - 使用 Java 1.7 处理套接字的最新技术是什么?

转载 作者:搜寻专家 更新时间:2023-10-30 19:45:36 24 4
gpt4 key购买 nike

我正在寻找使用 Java 1.7 的适当特性(try-with-resources)实现客户端/服务器套接字通信的最佳模式。必须确保所有线程和资源都已关闭并完全释放。 Effective Java/Clean Code应考虑项目以及简单的可调试性(每行中只有一个语句)。

如有任何反馈或讨论,我们将不胜感激。

第一种方法

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import org.junit.Test;

public final class ThreadedServerTest1 {
private static final class ThreadedServer implements Runnable {
private final Socket socket;

ThreadedServer(final Socket socket) {
this.socket = socket;
}

public static void main(final String arguments[]) {
final int port = arguments.length > 0 ? Integer.parseInt(arguments[0]) : 9999;
try (final ServerSocket serverSocket = new ServerSocket(port)) {
while (true) {
final Socket socket = serverSocket.accept();
final ThreadedServer server = new ThreadedServer(socket);
final Thread thread = new Thread(server);
thread.start();
}
} catch (final IOException e) {
e.printStackTrace();
}
}

@Override
public void run() {
// @formatter:off
try (
// See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7027552 and
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7013420:
final Socket socket = this.socket;
final InputStream inputStream = socket.getInputStream();
final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
final OutputStream outputStream = socket.getOutputStream();
final OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
final PrintWriter printWriter = new PrintWriter(outputStreamWriter);
) {
// @formatter:on
final String request = bufferedReader.readLine();
System.out.println(String.format("Received from client: %s", request));
printWriter.println("Hello client!");
printWriter.flush();
} catch (final Exception e) {
e.printStackTrace();
}
}
}

private static final class Client {
public static void main(final String arguments[]) {
final int port = arguments.length > 0 ? Integer.parseInt(arguments[0]) : 9999;
try {
final InetAddress loopbackAddress = InetAddress.getByName(null);
// @formatter:off
try (
final Socket socket = new Socket(loopbackAddress, port);
final OutputStream outputStream = socket.getOutputStream();
final OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
final PrintWriter printWriter = new PrintWriter(outputStreamWriter);
final InputStream inputStream = socket.getInputStream();
final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
final BufferedReader bufferedReader = new BufferedReader(inputStreamReader)
) {
// @formatter:on
printWriter.println("Hello server!");
printWriter.flush();
final String answer = bufferedReader.readLine();
System.out.println(String.format("Answer from server: %s", answer));
} catch (final IOException e) {
e.printStackTrace();
}
} catch (final UnknownHostException e) {
e.printStackTrace();
}
}
}

@Test
public void test() {
final String[] arguments = new String[] { "9999" };
final Thread tread = new Thread() {
@Override
public void run() {
ThreadedServer.main(arguments);
};
};
tread.start();
Client.main(arguments);
}
}

优点:

  • 更少的代码行

缺点:

  • 大型 try-with-resources block (Eclipse 格式化程序不支持)
  • 第二个 Socket 实例需要使用 try-with-resources
  • 由于 InetAddress#getByName(null) 中的 UnknownHostException 导致的深度嵌套

第二种方法

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

import org.junit.Test;

public final class ThreadedServerTest2 {
private static final class Connection implements AutoCloseable {
final Socket socket;
final InputStream inputStream;
final InputStreamReader inputStreamReader;
final BufferedReader bufferedReader;
final OutputStream outputStream;
final OutputStreamWriter outputStreamWriter;
final PrintWriter printWriter;

private Connection(final Socket socket) throws IOException {
this.socket = socket;
inputStream = socket.getInputStream();
inputStreamReader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(inputStreamReader);
outputStream = socket.getOutputStream();
outputStreamWriter = new OutputStreamWriter(outputStream);
printWriter = new PrintWriter(outputStreamWriter);
}

static Connection serverConnection(final Socket socket) throws IOException {
return new Connection(socket);
}

static Connection clientConnection(final String hostname, final int port) throws IOException {
final InetAddress inetAddress = InetAddress.getByName(hostname);
final Socket socket = new Socket(inetAddress, port);
return new Connection(socket);
}

static Connection localhostCientConnection(final int port) throws IOException {
return clientConnection(null, port);
}

@Override
public void close() {
closeAndIgnoreException(printWriter, outputStreamWriter, outputStream, bufferedReader, inputStreamReader, inputStream, socket);
}

private void closeAndIgnoreException(final AutoCloseable... closeables) {
for (final AutoCloseable closeable : closeables) {
try {
closeable.close();
} catch (final Exception ignore) {
}
}
}
}

private static final class ThreadedServer implements Runnable {
private final Socket socket;

private ThreadedServer(final Socket socket) {
this.socket = socket;
}

public static void main(final String arguments[]) {
final int port = arguments.length > 0 ? Integer.parseInt(arguments[0]) : 9999;
try (final ServerSocket serverSocket = new ServerSocket(port)) {
while (true) {
final Socket socket = serverSocket.accept();
final ThreadedServer server = new ThreadedServer(socket);
final Thread thread = new Thread(server);
thread.start();
}
} catch (final IOException e) {
e.printStackTrace();
}
}

@Override
public void run() {
try (Connection connection = Connection.serverConnection(socket)) {
final String request = connection.bufferedReader.readLine();
System.out.println(String.format("Received from client: %s", request));
connection.printWriter.println("Hello client!");
connection.printWriter.flush();
} catch (final Exception e) {
e.printStackTrace();
}
}
}

private static final class Client {
public static void main(final String arguments[]) {
final int port = arguments.length > 0 ? Integer.parseInt(arguments[0]) : 9999;
try (Connection connection = Connection.localhostCientConnection(port)) {
connection.printWriter.println("Hello server!");
connection.printWriter.flush();
final String answer = connection.bufferedReader.readLine();
System.out.println(String.format("Answer from server: %s", answer));
} catch (final IOException e) {
e.printStackTrace();
}
}
}

@Test
public void test() {
final String[] arguments = new String[] { "9999" };
final Thread tread = new Thread() {
@Override
public void run() {
ThreadedServer.main(arguments);
};
};
tread.start();
Client.main(arguments);
}
}

优点:

  • 干净且可读的 try-with-resources block
  • 支持 Eclipse 格式化程序

缺点:

  • 更多代码行
  • 需要自己的 Connection
  • 可能会忘记关闭 Connection 类中的 AutoCloseable 实例(容易出错)

您对优缺点有什么反馈或补充吗?还有更多弱点吗?

第三种方法

这是下面讨论的结果:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

import org.junit.Test;

public final class ThreadedServerTest3 {
private static final class ThreadedServer implements Runnable {
private final Socket socket;

private ThreadedServer(final Socket socket) {
this.socket = socket;
}

public static void main(final String arguments[]) {
final int port = arguments.length > 0 ? Integer.parseInt(arguments[0]) : 9999;
try (final ServerSocket serverSocket = new ServerSocket(port)) {
while (true) {
final Socket socket = serverSocket.accept();
final ThreadedServer server = new ThreadedServer(socket);
final Thread thread = new Thread(server);
thread.start();
}
} catch (final IOException e) {
e.printStackTrace();
}
}

@Override
public void run() {
// @formatter:off
try (
// See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7027552 and
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7013420:
Socket socket = this.socket;
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
) {
// @formatter:on
final String request = bufferedReader.readLine();
System.out.println(String.format("Received from client: %s", request));
printWriter.println("Hello client!");
printWriter.flush();
} catch (final Exception e) {
e.printStackTrace();
}
}
}

private static final class Client {
public static void main(final String arguments[]) {
final int port = arguments.length > 0 ? Integer.parseInt(arguments[0]) : 9999;
// @formatter:off
try (
Socket socket = new Socket(InetAddress.getByName(null), port);
PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()))
) {
// @formatter:on
printWriter.println("Hello server!");
printWriter.flush();
final String answer = bufferedReader.readLine();
System.out.println(String.format("Answer from server: %s", answer));
} catch (final IOException e) {
e.printStackTrace();
}
}
}

@Test
public void test() {
final String[] arguments = new String[] { "9999" };
final Thread tread = new Thread() {
@Override
public void run() {
ThreadedServer.main(arguments);
};
};
tread.start();
Client.main(arguments);
}
}

优点:

  • 更少的代码行
  • 不使用复杂且大部分可读的 try-with-resources block
  • 没有被忽略的异常(exception)

缺点:

  • 不支持 Eclipse 格式化程序
  • 一些违反规则“每行只有一个语句”(简单的可调试性)

最佳答案

  • final 修饰符在 try-with-resources 中是多余的,如规范 writes :

    A resource declared in a ResourceSpecification is implicitly declared final (§4.12.4) if it is not explicitly declared final.

  • 关闭读取器也会关闭底层流,与关闭写入器相同。因此没有必要将中间流声明为资源。
  • 您的第二种方法错误地忽略了关闭资源时抛出的异常。关闭流会刷新它,如果不成功,则并非所有数据都已发送,这显然需要抛出异常。相反,try-with-resources 语句确实会传播关闭时抛出的异常(可能是被抑制的异常,请参阅 details 的规范)。

因此,我建议:

try (
Socket socket = this.socket;
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()))
) {

关于java - 使用 Java 1.7 处理套接字的最新技术是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15041832/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com