학교 과제로 냈었던-_-a Java로 구현한 멀티쓰레드 웹서버입니다. Java로 구현할 수 있는 가장 기본적인 형태의 소켓 프로그래밍을 이용하여 구현하였습니다. 그냥 요청 받으면 해당 파일을 읽어서 내용을 보내는 단순한 어플리케이션입니다. Thread safe한 설계는 하지 않았습니다. 그냥 공부용으로만 사용해주세요.
* WebServer.java
class WebServer
{
public static void main(String argv[]) throws Exception
{
// 서버소켓을 생성한다. 웹서버는 기본적으로 80번 포트를 사용한다.
ServerSocket listenSocket = new ServerSocket(80);
System.out.println("WebServer Socket Created");
Socket connectionSocket;
ServerThread serverThread;
// 순환을 돌면서 클라이언트의 접속을 받는다.
// accept()는 Blocking 메서드이다.
while((connectionSocket = listenSocket.accept()) != null)
{
// 서버 쓰레드를 생성하여 실행한다.
serverThread = new ServerThread(connectionSocket);
serverThread.start();
}
}
}
* ServerThread.java
public class ServerThread extends Thread
{
// 파일 요청이 없을 경우의 기본 파일
private static final String DEFAULT_FILE_PATH = "index.html";
// 클라이언트와의 접속 소켓
private Socket connectionSocket;
/**
* <pre>
* 기본 생성자
* </pre>
*
* @param connectionSocket 클라이언트와의 통신을 위한 소켓
*/
public ServerThread(Socket connectionSocket)
{
this.connectionSocket = connectionSocket;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run()
{
System.out.println("WebServer Thread Created");
BufferedReader inFromClient = null;
DataOutputStream outToClient = null;
try
{
// 클라이언트와 통신을 위한 입/출력 2개의 스트림을 생성한다.
inFromClient = new BufferedReader(
new InputStreamReader(connectionSocket.getInputStream()));
outToClient = new DataOutputStream(
connectionSocket.getOutputStream());
// 클라이언트로의 메시지중 첫번째 줄을 읽어들인다.
String requestMessageLine = inFromClient.readLine();
// 파싱을 위한 토큰을 생성한다.
StringTokenizer tokenizedLine = new StringTokenizer(
requestMessageLine);
// 첫번째 토큰이 GET으로 시작하는가? ex) GET /green.jpg
if(tokenizedLine.nextToken().equals("GET"))
{
// 다음의 토큰은 파일명이다.
String fileName = tokenizedLine.nextToken();
// 기본적으로 루트(/)로부터 주소가 시작하므로 제거한다.
if(fileName.startsWith("/") == true)
{
if(fileName.length() > 1)
{
fileName = fileName.substring(1);
}
// 파일명을 따로 입력하지 않았을 경우 기본 파일을 출력한다.
else
{
fileName = DEFAULT_FILE_PATH;
}
}
File file = new File(fileName);
// 요청한 파일이 존재하는가?
if(file.exists())
{
// 존재하는 파일의 MIME타입을 분석한다.
String mimeType = new MimetypesFileTypeMap()
.getContentType(file);
// 파일의 바이트수를 찾아온다.
int numOfBytes = (int) file.length();
// 파일을 스트림을 읽어들일 준비를 한다.
FileInputStream inFile = new FileInputStream(fileName);
byte[] fileInBytes = new byte[numOfBytes];
inFile.read(fileInBytes);
// 정상적으로 처리가 되었음을 나타내는 200 코드를 출력한다.
outToClient.writeBytes("HTTP/1.0 200 Document Follows \r\n");
outToClient.writeBytes("Content-Type: " + mimeType + "\r\n");
// 출력할 컨텐츠의 길이를 출력
outToClient.writeBytes("Content-Length: " + numOfBytes + "\r\n");
outToClient.writeBytes("\r\n");
// 요청 파일을 출력한다.
outToClient.write(fileInBytes, 0, numOfBytes);
}
else
{
// 파일이 존재하지 않는다는 에러인 404 에러를 출력하고 접속을 종료한다.
System.out.println("Requested File Not Found : " + fileName);
outToClient.writeBytes("HTTP/1.0 404 Not Found \r\n");
outToClient.writeBytes("Connection: close\r\n");
outToClient.writeBytes("\r\n");
}
}
else
{
// 잘못된 요청임을 나타내는 400 에러를 출력하고 접속을 종료한다.
System.out.println("Bad Request");
outToClient.writeBytes("HTTP/1.0 400 Bad Request Message \r\n");
outToClient.writeBytes("Connection: close\r\n");
outToClient.writeBytes("\r\n");
}
connectionSocket.close();
System.out.println("Connection Closed");
}
// 예외 처리
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
* index.html
<html> <head> <title>웹서버 테스트</title> </head> <body> <p>http://theeye.pe.kr</p> <img src="sooji.jpg" /> </body> </html>

테스트를 해보니 정상적으로 파일을 전송하고 해당 html에 딸려있는 객체들역시 정상적으로 전송됨을 알 수 있습니다. 잘 되네요~^^b