使基本 Java 文件服务器成为多线程
Making a basic Java file server multi-threaded
我有一个服务器,它向客户端发送一个文本文件的内容。
'server' 包有一个 'Main'(从 cmd 行参数获取端口号并解析它),'Server' 和 'FileHandler' class 我想我已经以某种方式(使用线程池)获得了它们,以便服务器能够同时服务给两个客户。
现在我正在尝试构建一个带有启动和停止服务器选项的 CLI。我希望实现 2 个线程,其中一个线程将侦听输入,另一个线程将侦听 'accept()' 调用。
到目前为止,我的尝试是创建一个新的 class 'Commander.java' 并接受一个 AtomicBoolean在构造函数中,然后将其存储在对象中,用作停止服务器线程的标志。
我希望正在侦听 'accept()' 调用的线程定期检查是否已发出停止请求 - 如何使用我的 'Commander' class 执行此操作?
包括一些代码片段(a.k.a。到目前为止我的尝试)以便您更好地理解:
class Server implements Runnable
{
Socket sock;
ExecutorService executor;
private int port ;
public Server(int p) {
port = p ;
executor = Executors.newFixedThreadPool(2);
}
public void startServer() {
ServerSocket s = new ServerSocket(port);
...
while (true)
{
Socket temp = s.accept();
sock = temp;
executor.execute(new FileHandler(sock));
// serveFile(temp) ;
}
public void run() {
startServer();
}
}
public class Main {
public static void main(String[] args) {
while(true) {
System.out.println("Main menu:\n" +
" 1 - Start server\n"+
" 2 - Stop Server\n"+
" 0 - Exit");
int in = Integer.parseInt(scanner.nextLine());
switch(in) {
case 1:
// start server
System.out.println("Starting server...");
Thread th1 = new Thread(new Server(port));
th1.start();
System.out.println("Case continuity...");
// server.startServer() ;
break;
case 2:
// stop server
System.out.println("Server stopped.\n");
break;
case 0:
// exit
System.exit(0);
break;
}
}
}
}
class FileHandler implements Runnable {
Socket socket;
public FileHandler(Socket socket) {
this.socket = socket;
}
private void serveFile() {
...code for serving file...
}
public void run() {
serveFile();
}
}
public class Commander implements Runnable
{
private AtomicBoolean bool;
public Commander(AtomicBoolean bool) {
this.bool = new AtomicBoolean(bool);
}
public boolean value() {
return bool.get();
}
你的做法是错误的。在 accept()
上阻塞的线程除了等待并在建立连接后启动新线程(或提交新任务)外不应执行任何操作。
当您想关闭服务器时,在 ServerSocket
上调用 close()
(当然是从不同的线程)。 accept()
上阻塞的线程将抛出 SocketException
,然后您可以清理并退出。
基于@Kayaman :
A- 在您的服务器上 class:
1- 让 ServerSocket
成为 class 成员范围:
ServerSocket s = new ServerSocket(port);
2-添加方法shutdown()
:
public void shutdown(){
try{
s.close();
}catch(Exception e){
e.printStacktrace();
}
}
3- 添加 try/catch
来处理套接字关闭(执行干净关闭):
while (true)
{
try{
Socket temp = s.accept();
sock = temp;
executor.execute(new FileHandler(sock));
// serveFile(temp) ;
}catch(SocketException ex){
doAcleanShutdown();
}
}
B- 在你的 Main class:
1-让Server
实例成为class成员范围
Server myServer = new Server(port);
2- 在 switch (case 1:
) 中使用 myServer
instance
case 1:
// start server
System.out.println("Starting server...");
Thread th1 = new Thread(myServer);
th1.start();
System.out.println("Case continuity...");
// server.startServer() ;
break;
3- 停止服务器,case 2:
case 2:
// stop server
myServer.shutdown();
System.out.println("Server stopped.\n");
break;
我有一个服务器,它向客户端发送一个文本文件的内容。
'server' 包有一个 'Main'(从 cmd 行参数获取端口号并解析它),'Server' 和 'FileHandler' class 我想我已经以某种方式(使用线程池)获得了它们,以便服务器能够同时服务给两个客户。
现在我正在尝试构建一个带有启动和停止服务器选项的 CLI。我希望实现 2 个线程,其中一个线程将侦听输入,另一个线程将侦听 'accept()' 调用。
到目前为止,我的尝试是创建一个新的 class 'Commander.java' 并接受一个 AtomicBoolean在构造函数中,然后将其存储在对象中,用作停止服务器线程的标志。
我希望正在侦听 'accept()' 调用的线程定期检查是否已发出停止请求 - 如何使用我的 'Commander' class 执行此操作?
包括一些代码片段(a.k.a。到目前为止我的尝试)以便您更好地理解:
class Server implements Runnable
{
Socket sock;
ExecutorService executor;
private int port ;
public Server(int p) {
port = p ;
executor = Executors.newFixedThreadPool(2);
}
public void startServer() {
ServerSocket s = new ServerSocket(port);
...
while (true)
{
Socket temp = s.accept();
sock = temp;
executor.execute(new FileHandler(sock));
// serveFile(temp) ;
}
public void run() {
startServer();
}
}
public class Main {
public static void main(String[] args) {
while(true) {
System.out.println("Main menu:\n" +
" 1 - Start server\n"+
" 2 - Stop Server\n"+
" 0 - Exit");
int in = Integer.parseInt(scanner.nextLine());
switch(in) {
case 1:
// start server
System.out.println("Starting server...");
Thread th1 = new Thread(new Server(port));
th1.start();
System.out.println("Case continuity...");
// server.startServer() ;
break;
case 2:
// stop server
System.out.println("Server stopped.\n");
break;
case 0:
// exit
System.exit(0);
break;
}
}
}
}
class FileHandler implements Runnable {
Socket socket;
public FileHandler(Socket socket) {
this.socket = socket;
}
private void serveFile() {
...code for serving file...
}
public void run() {
serveFile();
}
}
public class Commander implements Runnable
{
private AtomicBoolean bool;
public Commander(AtomicBoolean bool) {
this.bool = new AtomicBoolean(bool);
}
public boolean value() {
return bool.get();
}
你的做法是错误的。在 accept()
上阻塞的线程除了等待并在建立连接后启动新线程(或提交新任务)外不应执行任何操作。
当您想关闭服务器时,在 ServerSocket
上调用 close()
(当然是从不同的线程)。 accept()
上阻塞的线程将抛出 SocketException
,然后您可以清理并退出。
基于@Kayaman
A- 在您的服务器上 class:
1- 让 ServerSocket
成为 class 成员范围:
ServerSocket s = new ServerSocket(port);
2-添加方法shutdown()
:
public void shutdown(){
try{
s.close();
}catch(Exception e){
e.printStacktrace();
}
}
3- 添加 try/catch
来处理套接字关闭(执行干净关闭):
while (true)
{
try{
Socket temp = s.accept();
sock = temp;
executor.execute(new FileHandler(sock));
// serveFile(temp) ;
}catch(SocketException ex){
doAcleanShutdown();
}
}
B- 在你的 Main class:
1-让Server
实例成为class成员范围
Server myServer = new Server(port);
2- 在 switch (case 1:
) 中使用 myServer
instance
case 1:
// start server
System.out.println("Starting server...");
Thread th1 = new Thread(myServer);
th1.start();
System.out.println("Case continuity...");
// server.startServer() ;
break;
3- 停止服务器,case 2:
case 2:
// stop server
myServer.shutdown();
System.out.println("Server stopped.\n");
break;