java socket 多线程 服务器端_java Socket 实现多线程静态文件服务器

关于静态文件服务器,我觉得博文共赏:Node.js静态文件服务器实战写的不错,简单易懂,思路清晰,不过使用Nodejs写的。我本人更熟悉Java,所以就用Java写了一个简易版本。

此版本主要实现以下功能:

1 . 对于请求的资源,若处理成功,返回200

2 . 对于请求的资源,若服务器上不存在,返回404

3 . 多线程处理浏览器发出的请求

4 . MIME类型支持

此项目的完整代码,可以到java-staticfile中download.

先贴项目工程图

7f3585553505

Handler.java

对请求头进行处理

public class Handler implements Runnable {

Functions functions = new Functions();

MIME mime = new MIME();

HashMap type = mime.getMime();

String contentType = null;

public String encoding = "UTF-8";

private Socket client;

PrintWriter out = null;

public Handler(Socket client) {

this.client = client;

}

public void run() {

if (client != null) {

try {

BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));

String header = reader.readLine();

System.out.println("客户端发送的请求信息: >>>>>>>>>>>>>>>>>>>>>>>>>");

System.out.println(header);// 读取所有浏览器发送过来的请求参数头部的所有信息

String resource = (String) header.split(" ")[1];// 获得请求的资源的地址

System.out.println("客户端发送的请求信息结束 <<<<<<<<<<<<<<<<<<<<<<<<<

System.out.println("用户请求的资源resource是:" + resource);

System.out.println();

String suffix = null;

if (resource.equals("/")) {

resource = "/index.html";

String[] names = resource.split("\\.");

suffix = names[names.length - 1];

contentType = type.get(suffix);

} else {

String[] names = resource.split("\\.");

suffix = names[names.length - 1];

contentType = type.get(suffix);

}

String path = "/home/sunyan/code/public/" + resource;

File file = new File(path);

if (file.exists()) {

if (suffix.equals("png") || suffix.equals("jpg") || suffix.equals("jpeg")) {

functions.readImg(file, client, contentType);

} else {

functions.readFile(file, client, contentType);

}

} else {

PrintWriter out = new PrintWriter(client.getOutputStream(), true);

out.println("HTTP/1.0 404 NOTFOUND");// 返回应答消息,并结束应答

out.println("Content-Type:text/html;charset=UTF-8");

out.println();// 根据 HTTP 协议, 空行将结束头信息

out.println("对不起,您寻找的资源在本服务器上不存在");

out.close();

functions.closeSocket(client);

} // file.exists

} catch (Exception e) {

System.out.println("HTTP服务器错误:" + e.getLocalizedMessage());

}

}

}

}

Functions.java

包括三个函数

closeSocket():用于关闭socket

readImg() readFile():用于读取静态文件

若文件存在,则调用方法读取文件,正常状态下则发送读取到的文件给客户端,并返回200状态。

若服务器读取文件出错,则返回500状态。

若文件不存在,则返回404状态。

public class Functions {

public void closeSocket(Socket socket) {

try {

socket.close();

System.out.println(socket + "离开了HTTP服务器");

System.out.println();

System.out.println();

} catch (IOException ex) {

ex.printStackTrace();

}

}

public void readImg(File file, Socket client, String contentType) {

PrintStream out = null;

FileInputStream fis = null;

try {

out = new PrintStream(client.getOutputStream(), true);

fis = new FileInputStream(file);

byte data[] = new byte[fis.available()];

out.println("HTTP/1.0 200 OK");// 返回应答消息,并结束应答

out.println("Content-Type:" + contentType + ";charset=UTF-8");

out.println("Content-Length: " + file.length());

out.println();// 根据 HTTP 协议, 空行将结束头信息

fis.read(data);

out.write(data);

fis.close();

} catch (Exception e) {

out.println("HTTP/1.0 500");// 返回应答消息,并结束应答

out.println("");

out.flush();

} finally {

out.close();

closeSocket(client);

}

}

public void readFile(File file, Socket client, String contentType) {

PrintWriter out = null;

try {

out = new PrintWriter(client.getOutputStream(), true);

FileReader in = new FileReader(file);

BufferedReader breader = new BufferedReader(in);

String s = null;

StringBuffer sbu = new StringBuffer();

out.println("HTTP/1.0 200 OK");// 返回应答消息,并结束应答

out.println("Content-Type:" + contentType + ";charset=UTF-8");

out.println();// 根据 HTTP 协议, 空行将结束头信息

while ((s = breader.readLine()) != null) {

out.println(s);

}

} catch (Exception e) {

out.println("HTTP/1.0 500");// 返回应答消息,并结束应答

out.println("");

out.flush();

} finally {

out.close();

closeSocket(client);

}

}

}

MIME.java

MIME类型支持

因为服务器同时要存放html, css, js, png, gif, jpg等等文件。并非每一种文件的MIME类型都是text/html的。因此需要支持MIME。

支持MIME的话,就需要一张映射表。

public class MIME {

HashMap mime = new HashMap();

public MIME() {

mime.put("css", "text/css");

mime.put("gif", "image/gif");

mime.put("html", "text/html;charset=utf-8");

mime.put("ico", "image/x-icon");

mime.put("jpeg", "image/jpeg");

mime.put("jpg", "image/jpeg");

mime.put("js", "text/javascript");

mime.put("json", "application/json");

mime.put("pdf", "application/pdf");

mime.put("png", "image/png");

mime.put("svg", "image/svg+xml");

mime.put("swf", "application/x-shockwave-flash");

mime.put("tiff", "image/tiff");

mime.put("txt", "text/plain;charset=utf-8");

mime.put("wav", "audio/x-wav");

mime.put("wma", "audio/x-ms-wma");

mime.put("wmv", "video/x-ms-wmv");

mime.put("xml", "text/xml");

}

public HashMap getMime() {

return mime;

}

}

MultiThreadServer.java

监听客户端发出的请求,并创建线程对其进行处理

public class MultiThreadServer {

public static void main(String[] args) throws Exception {

int port = 20012;// 标准HTTP端口

ServerSocket server = new ServerSocket(20012);

Socket client = null;

System.out.println("静态文件服务器正在运行,端口:" + port);

System.out.println();

while (true) {

client = server.accept();

System.out.println(client + "连接到HTTP服务器");

Handler handler = new Handler(client);

new Thread(handler).start();

}

}

}

测试过程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设计一个Java多线程Web服务器大致需要以下步骤: 1. 创建一个ServerSocket对象并绑定端口号,等待客户端连接。 2. 当有客户端连接时,创建一个新的线程来处理该客户端的请求。 3. 在新线程中使用Socket对象获取输入流和输出流,接收客户端的HTTP请求,并返回HTTP响应。 4. 解析HTTP请求,获取请求的URL和请求方法等信息。 5. 根据请求的URL和请求方法,调用相应的处理方法来处理请求。 6. 处理方法可以是静态资源的访问,动态资源的访问或请求的转发等。 7. 处理完请求后,关闭Socket连接。 8. 循环执行步骤2-7,等待下一个客户端连接。 实现一个Java多线程Web服务器的具体步骤如下: 1. 创建一个ServerSocket对象并绑定端口号,等待客户端连接。 ``` ServerSocket serverSocket = new ServerSocket(port); while (true) { Socket socket = serverSocket.accept(); new Thread(new RequestHandler(socket)).start(); } ``` 2. 创建一个RequestHandler类来处理客户端的请求。 ``` public class RequestHandler implements Runnable { private Socket socket; public RequestHandler(Socket socket) { this.socket = socket; } @Override public void run() { try { InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); // 解析HTTP请求,获取请求的URL和请求方法等信息 String request = parseRequest(inputStream); String[] requestLine = request.split(" "); String method = requestLine[0]; String url = requestLine[1]; // 根据请求的URL和请求方法,调用相应的处理方法来处理请求 String response = processRequest(method, url); // 返回HTTP响应 outputStream.write(response.getBytes()); outputStream.flush(); // 关闭Socket连接 socket.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 3. 在RequestHandler类中实现parseRequest方法,解析HTTP请求。 ``` private String parseRequest(InputStream inputStream) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder request = new StringBuilder(); String line; while ((line = reader.readLine()) != null && !line.isEmpty()) { request.append(line).append("\r\n"); } return request.toString(); } ``` 4. 在RequestHandler类中实现processRequest方法,根据请求的URL和请求方法,调用相应的处理方法来处理请求。 ``` private String processRequest(String method, String url) { if ("GET".equals(method)) { if ("/".equals(url)) { // 处理静态资源的访问 return serveFile("index.html"); } else if ("/hello".equals(url)) { // 处理动态资源的访问 return "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello, world!"; } else { // 请求的转发 return forwardRequest(url); } } else { return "HTTP/1.1 405 Method Not Allowed\r\n\r\n"; } } ``` 5. 在RequestHandler类中实现serveFile方法,处理静态资源的访问。 ``` private String serveFile(String fileName) { try { InputStream inputStream = getClass().getClassLoader().getResourceAsStream(fileName); byte[] data = new byte[inputStream.available()]; inputStream.read(data); String contentType = getContentType(fileName); return "HTTP/1.1 200 OK\r\nContent-Type: " + contentType + "\r\n\r\n" + new String(data); } catch (IOException e) { return "HTTP/1.1 404 Not Found\r\n\r\n"; } } ``` 6. 在RequestHandler类中实现forwardRequest方法,请求的转发。 ``` private String forwardRequest(String url) { try { URL forwardUrl = new URL("http://localhost:8080" + url); HttpURLConnection connection = (HttpURLConnection) forwardUrl.openConnection(); connection.setRequestMethod("GET"); BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line).append("\r\n"); } return response.toString(); } catch (IOException e) { return "HTTP/1.1 404 Not Found\r\n\r\n"; } } ``` 7. 在RequestHandler类中实现getContentType方法,根据文件名获取相应的Content-Type。 ``` private String getContentType(String fileName) { if (fileName.endsWith(".html") || fileName.endsWith(".htm")) { return "text/html"; } else if (fileName.endsWith(".jpeg") || fileName.endsWith(".jpg")) { return "image/jpeg"; } else if (fileName.endsWith(".gif")) { return "image/gif"; } else if (fileName.endsWith(".png")) { return "image/png"; } else if (fileName.endsWith(".js")) { return "application/javascript"; } else if (fileName.endsWith(".css")) { return "text/css"; } else { return "application/octet-stream"; } } ``` 这样就完成了一个简单的Java多线程Web服务器的设计与实现。需要注意的是,这只是一个简单的Demo,实际生产环境中需要考虑更多的安全性、可靠性和性能等方面的因素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值