socket编程 java多线程web服务器设计与实现

相信很多人在socket编程学习过程中,都会遇到类似的web服务器的设计案例,可是对于刚接触socket的新手来说,往往难以迈出第一步,于是在此分享一个多线程的web服务器代码(参考计算机网络课程的代码框架),便于各位网友参考学习使用!

 

一、理解多线程

多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立。

线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。

多个线程的执行是并发的,也就是在逻辑上同时,而不管是否是物理上的同时。如果系统只有一个单核CPU,那么真正的同时是不可能的。不过,由于CPU的处理速度非常快,用户感觉好像自己的程序连续运行一样。

多线程和传统的单线程在程序设计上最大的区别在于,由于各个线程的控制流彼此独立,使得各个线程之间的代码是乱序执行的

二、案例需求

以JDK为开发工具,利用Socket通信机制实现一个多线程的WEB服务器,该服务器具有以下功能:

  1. 能够并行服务于多个请求。
  2. 对于每个请求,显示接收到的HTTP请求报文的内容,并产生适当的响应(若找到用户请求对象,则返回该对象。否则发送一个包含适当提示信息的响应消息,从而可以在浏览器窗口中显示差错信息。

三、代码部分



import java.io.*;
import java.net.*;
import java.util.*;

public final class WebServer {
	public static void main(String argv[]) throws Exception {
		int port = 6666;//定义端口号
		ServerSocket welcomeSocket = new ServerSocket(port);
		while (true) {
			Socket connectionSocket = welcomeSocket.accept();
			HttpRequest request = new HttpRequest(connectionSocket);
			Thread thread = new Thread(request);
			thread.start();
		}
	}
}

final class HttpRequest implements Runnable {
	final static String CRLF = "\r\n";
	Socket socket;

	public HttpRequest(Socket socket) throws Exception {
		this.socket = socket;
	}

	public void run() {
		try {
			processRequest();

		} catch (Exception e) {
			System.out.println(e);
		}
	}

	private void processRequest() throws Exception {
		InputStream is = socket.getInputStream();
		DataOutputStream os = new DataOutputStream(socket.getOutputStream());

		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		String requestLine = br.readLine();
		System.out.println();
		System.out.println(requestLine);
		String headerLine = null;
		while ((headerLine = br.readLine()).length() != 0) {
			System.out.println(headerLine);
		}
		
		// 从请求行中提取出文件名
		StringTokenizer tokens = new StringTokenizer(requestLine);
		tokens.nextToken(); // 跳过method
		String fileName = tokens.nextToken();
		fileName = "." + fileName;//构造请求文件名
		

		FileInputStream fis = null;
		boolean fileExists = true;
		// 判断请求对象是否存在
		try {
			fis = new FileInputStream(fileName);
		} catch (FileNotFoundException e) {
			fileExists = false;
		}
		String statusLine = null;
		String contentTypeLine = null;
		String entityBody = null;

		if (fileExists) {// 请求文件存在构造响应的status 和 contentType
			statusLine = "HTTP/1.1 200 OK" + CRLF;
			contentTypeLine = "Content-type: " + contentType(fileName) + CRLF;
		} else {// 请求文件不存在
			statusLine = "HTTP/1.1 404" + CRLF;
			contentTypeLine = "Content-type: " + contentType(fileName) + CRLF;
			entityBody = "<!DOCTYPE html><HTML>" + "<HEAD><TITLE>Not Found</TITLE></HEAD>" + "<BODY>Not Found</BODY></HTML>";
		}
		os.writeBytes(statusLine);
		os.writeBytes(contentTypeLine);
		os.writeBytes(CRLF);
		if (fileExists) {
			sendBytes(fis, os);
			fis.close();
		} else {
			os.writeBytes(entityBody);
		}
		os.close();
		br.close();
		socket.close();
	}

	private static void sendBytes(FileInputStream fis, OutputStream os) throws Exception {
		byte[] buffer = new byte[1024];
		int bytes = 0;
		while ((bytes = fis.read(buffer)) != -1) {
			os.write(buffer, 0, bytes);
		}

	}

	private static String contentType(String fileName)

	{
                //根据文件名返回相应的contentType
		if (fileName.endsWith(".htm") || fileName.endsWith(".html")) {
			return "text/html";
		}
		if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
			return "image/jpeg";
		}
		if (fileName.endsWith(".png")) {
			return "image/png";
		}
		if (fileName.endsWith(".css")) {
			return "text/css";
		}
		if (fileName.endsWith(".gif")) {
			return "image/gif";
		}
		if (fileName.endsWith(".png")) {
			return "image/png";
		}
		return "application/octet-stream";
	}

}

四、代码测试

测试时使用浏览器访问localhost:port,本例为127.0.0.1:6666,测试用的文件放在项目根目录即可,如使用eclipse编写的项目则需要将文件放在项目名称的目录下(有bin和src的那个目录)

测试截图如下

请求成功时正确返回请求文件

请求失败时给出提示

  • 12
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值