我编写了以下连接到客户端的服务器:
ServerSocket server = null;
try
{
server = new ServerSocket(4040);
while (isServerListening)
{
Socket clientSocket = server.accept();
// Send bytes to the Client
ServerOutputStream = clientSocket.getOutputStream();
byte[] bytes = "I am a Server".getBytes();
ServerOutputStream.write(bytes);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
// close socket here
}
此服务器在line.accept()行停止,并等待下一个客户端连接。同时我想阅读从客户端收到的消息。
几年前我用不同的语言通过事件处理程序完成了这个套接字编程,但似乎我需要一个不同的方法。
我的问题是:我需要另一个线程来执行此任务吗?有没有替代方案,例如非阻塞模式?
答案 0 :(得分:1)
我的问题是:我是否需要另一个线程来执行此任务?
一种方法是为每个客户端连接使用一个线程。应用程序方法在监听端口的无限循环中运行服务器。当请求连接时,它会生成一个新线程来进行服务并立即返回监听。
ServerSocket listener = new ServerSocket(9898);
try {
while (true) {
new Handler(listener.accept(), clientNumber++).start();
}
} finally {
listener.close();
}
处理特定套接字上的请求的线程。
private static class Handler extends Thread {
private Socket socket;
private int clientNumber;
public Handler(Socket socket, int clientNumber) {
this.socket = socket;
this.clientNumber = clientNumber;
}
public void run() {
try {
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while (true) {
String input = in.readLine();
...
}
} catch (IOException e) {
} finally {
try {
socket.close();
} catch (IOException e) {
log("Couldn't close a socket, what's going on?");
}
}
}
}
是否有替代方案,例如非阻塞模式?
对于非阻塞套接字通道,服务器套接字必须向选择器注册才能执行某些操作。默认情况下,服务器套接字通道是阻塞通道。要使其成为非阻塞通道,请进行以下设置。
channel.configureBlocking(false);
非阻塞服务器程序看起来像......
InetAddress hostIPAddress = InetAddress.getByName("localhost");
int port = 19000;
Selector selector = Selector.open();
ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false);
channel.socket().bind(new InetSocketAddress(hostIPAddress, port));
channel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
Set keys = selector.selectedKeys();
...
}
非阻塞客户端程序看起来像......
InetAddress serverIPAddress = InetAddress.getByName("localhost");
InetSocketAddress serverAddress = new InetSocketAddress(
serverIPAddress, 19000);
Selector selector = Selector.open();
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(serverAddress);
int operations = SelectionKey.OP_CONNECT | SelectionKey.OP_READ
| SelectionKey.OP_WRITE;
channel.register(selector, operations);
while (true) {
if (selector.select() > 0) {
Set keys = selector.selectedKeys();
...
}
}
channel.close();
答案 1 :(得分:0)
您可以创建一个线程池并将clientSocket作为新任务提交给ThreadPool
Socket clientSocket = serverSocket.accept();
threadPool.submit(new ClientTask(clientSocket));
您可以在互联网上找到多线程服务器的多种实现,请查看此one