[英]What is the state of the art in socket handling with Java 1.7?
I'm searching for the best pattern to implement client/server socket communication using appropriate features of Java 1.7 ( try-with-resources ). 我正在寻找使用Java 1.7的适当功能( try-with-resources )实现客户端/服务器套接字通信的最佳模式。 It must be assured all threads and resources are closed and released completely. 必须确保所有线程和资源都已完全关闭和释放。 Effective Java / Clean Code items should be considered as well as simple debugability (only one statement in each line). 应考虑有效的Java / Clean代码项以及简单的可调试性(每行中只有一个语句)。
Any feedback or discussion would be appreciated. 任何反馈或讨论将不胜感激。
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);
}
}
Pros: 优点:
Cons: 缺点:
Socke
t instance needed to use try-with-resources 第二个Socke
t实例需要使用try-with-resources UnknownHostException
from InetAddress#getByName(null)
由于InetAddress#getByName(null)
的UnknownHostException
导致深度嵌套InetAddress#getByName(null)
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);
}
}
Pros: 优点:
Cons: 缺点:
Connection
class needed 需要自己的Connection
类 AutoCloseable
instances in the Connection
class may be forgotten (error prone) 关闭Connection
类中的AutoCloseable
实例可能会被遗忘(容易出错) Do you have feedback or additions to the pros and cons? 您对优缺点有反馈或补充吗? Are there more weaknesses? 还有更多的弱点吗?
That's the result of the discussion below: 这是以下讨论的结果:
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);
}
}
Pros: 优点:
Cons: 缺点:
A resource declared in a ResourceSpecification is implicitly declared final (§4.12.4) if it is not explicitly declared final. 如果未明确声明为final,则在ResourceSpecification中声明的资源将被隐式声明为final(第4.12.4节)。
Therefore, I recommend: 因此,我建议:
try (
Socket socket = this.socket;
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()))
) {
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.