1. 클라이언트 요청 정보 출력
프로젝트를 만들고 'WASMain'이라는 Class를 만들고 소스를 아래와 같이 작성한다서버에 8080포트를 열고 기다리는 Socket을 생성하고 클라이언트에서 전송한 정보를 출력하는 소스를 작성한다. 아래와 같이 작성 후 Main 메소드를 실행한다.
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class WASMain {
public static void main(String[] args){
ServerSocket listener = null;
try{
//특정 port에서 기다린는 ServerSocket을 생성한다.
listener = new ServerSocket(8080);
System.out.println("client를 기다립니다.");
// 소켓서버 종료될때까지 무한루프
while(true){
// 클라이언트가 접속할때까지 기다린다.
Socket client = listener.accept(); // 블러킹 메소드.
System.out.println(client);
handleSocket(client);
}
}catch(Exception ex){
ex.printStackTrace();
}finally { // finally부분에서 서버소켓을 close한다.
try {
listener.close();
}catch(Exception e){}
}
}
private static void handleSocket(Socket client) throws IOException {
InputStream in = client.getInputStream(); //클라이언트에게서 받은 데이터를 처리를 위한 작업
BufferedReader br = new BufferedReader(new InputStreamReader(in));
//1. btye로 한번에 읽어서 출력하기
/*byte[] buffer = new byte[1024];
int count = 0;
while((count = in.read(buffer)) != -1){
System.out.write(buffer, 0 ,count);
}*/
//2. String변수에 담아서 출력 하기
String line = "";
while ((line = br.readLine()) != null){
System.out.println(line);
}
in.close();
client.close(); // 클라이언트와 접속이 close 된다.
}
}
브라우저에서 'http://localhost:8080'에 접속한다. IDE 툴로 돌아가서 콘솔을 보면 아래와 같이 GET방식으로 요청이 온 정보들이 보일 것이다.(주소창에서 입력해서 접속하는 방식은 GET방식이다.
2. Thead 처리 지원하는 WAS
listener.accept() 부분이 블로킹 메소드라서 요청이 올때 Blocking되는 문제가 있다. Thread처리가 가능한 WAS로 변경하자.Bolcking vs Nonbolcking
public class WASMain {
public static void main(String[] args){
ServerSocket listener = null;
try{
//특정 port에서 기다린는 ServerSocket을 생성한다.
listener = new ServerSocket(8080);
System.out.println("client를 기다립니다.");
// 소켓서버 종료될때까지 무한루프
while(true){
// 클라이언트가 접속할때까지 기다린다.
Socket client = listener.accept(); // 블러킹 메소드.
System.out.println(client);
new Thread(() -> { //jdk 1.8 Lamd형식
try{
handleSocket(client);
}catch (Exception ex){
ex.printStackTrace();
}
}).start();
}
}catch(Exception ex){
ex.printStackTrace();
}finally { // finally부분에서 서버소켓을 close한다.
try {
listener.close();
}catch(Exception e){}
}
}
private static void handleSocket(Socket client) throws IOException {
InputStream in = client.getInputStream(); //클라이언트에게서 받은 데이터를 처리를 위한 작업
BufferedReader br = new BufferedReader(new InputStreamReader(in));
//String변수에 담아서 출력 하기
String line = "";
while ((line = br.readLine()) != null){
System.out.println(line);
}
in.close();
client.close(); // 클라이언트와 접속이 close 된다.
}
}
3. 파일 및 이미지 파일 만들기
브라우저에 출력하기 위해 파일과 이미지를 업로드 한다.mac 기준으로 터미널에서 /tmp/wasroot/ 디렉토리를 생성한다.(tmp폴더는 재부팅시 초기화)
index.html을 만들고 아래와 같이 입력하고
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>index.html</title>
</head>
<body>
Hello World!
<img src="hello.png" >
</body>
</html>
/tmp/wasroot/ 경로에 이미지 파일을 복사한다.hello.png 라는 이미지 파일이 /Users/mac/Downloads/ 경로에 있다고 가정하면 터미널에서 다음과 같이 명령어를 실행한다.
cp /Users/mac/Downloads/hello.png /tmp/wasroot/hello.png
4. 원하는 정보만 출력하기
HttpRequest라는 Class를 만들과 출력할 정보에 관한 set, get 메소드를 생성한다.
public class HttpRequest {
private String method; //GET, POST, PUT, DELETE ....
private String path;
private String host; // host
private int contentLength; //COntent-Length : body 길이
private String userAgent; // User-Agent : 브라우저 정보
private String contentType; // Content-Type : 사용자가 요청한 컨텐츠의 타입
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getContentLength() {
return contentLength;
}
public void setContentLength(int contentLength) {
this.contentLength = contentLength;
}
public String getUserAgent() {
return userAgent;
}
public void setUserAgent(String userAgent) {
this.userAgent = userAgent;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
@Override
public String toString() {
return "HttpRequest{" +
"method='" + method + '\'' +
", path='" + path + '\'' +
", host='" + host + '\'' +
", contentLength='" + contentLength + '\'' +
", userAgent='" + userAgent + '\'' +
", contentType='" + contentType + '\'' +
'}';
}
}
WASMain 클래스도 변경한다.
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class WASMain {
public static void main(String[] args){
ServerSocket listener = null;
try{
listener = new ServerSocket(8080);
System.out.println("client를 기다립니다.");
while(true) {
Socket client = listener.accept(); // 블러킹 메소드.
System.out.println(client);
new Thread(() -> {
try {
handleSocket(client);
} catch (Exception ex) {
ex.printStackTrace();
}
}).start();
}
}catch(Exception ex){
ex.printStackTrace();
}finally { // finally부분에서 서버소켓을 close한다.
try {
listener.close();
}catch(Exception e){}
}
}
private static void handleSocket(Socket client) throws IOException {
OutputStream out = client.getOutputStream(); //클라이언트에게 데이터를 보내기 위한 작업
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
InputStream in = client.getInputStream(); //클라이언트에게서 받은 데이터를 처리를 위한 작업
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = null;
HttpRequest request = new HttpRequest();
line = br.readLine();
String[] firstLineArgs = line.split(" ");
request.setMethod(firstLineArgs[0]);
request.setPath(firstLineArgs[1]);
while((line = br.readLine()) != null){
if("".equals(line)){ // 헤더를 읽고 빈줄을 만나면
break;
}
String[] headerArray = line.split(" ");
if(headerArray[0].startsWith("Host:")){
request.setHost(headerArray[1].trim());
}else if(headerArray[0].startsWith("Content-Length:")){
int length = Integer.parseInt(headerArray[1].trim());
request.setContentLength(length);
}else if(headerArray[0].startsWith("User-Agent:")){
request.setUserAgent(line.substring(12));
}else if(headerArray[0].startsWith("Content-Type:")){
request.setContentType(headerArray[1].trim());
}
}
System.out.println(request);
String baseDir = "/tmp/wasroot";
String fileName = request.getPath();
if("/".equals(fileName)){
fileName = "/index.html";
}else if(fileName.endsWith(".png")){ //png 이미지일때
fileName = request.getPath();
}else{ //잘못된 경로 처리
fileName = "/error.html";
}
fileName = baseDir + fileName;
String contentType = "text/html; charset=UTF-8";
if(fileName.endsWith(".png")){
contentType = "image/png";
}
File file = new File(fileName); // java.io.File
long fileLength = file.length();
if(file.isFile()){
pw.println("HTTP/1.1 200 OK");
pw.println("Content-Type: " + contentType);
pw.println("Content-Length: " + fileLength);
pw.println();
}else{
pw.println("HTTP/1.1 404 OK");
pw.println("Content-Type: " + contentType);
pw.println("Content-Length: " + fileLength);
pw.println();
}
pw.flush(); // 헤더와 빈줄을 char형식으로 출력
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
int readCount = 0;
while((readCount = fis.read(buffer)) != -1){
out.write(buffer,0,readCount);
}
out.flush();
out.close();
in.close();
client.close(); // 클라이언트와 접속이 close된다.
}
}
5. 브라우저 접속
브라우저에서 'http://localhost:8080'에 접속한다.콘솔과 브라우저에 화면에 아래와 같이 나오면 정상이다.
POST 방식은 크롬 웹 어플레케이션 'Restlet Client - REST API Testing'을 통해 TEST할수 있다.
6. 프로젝트 구조
client에서 서버로 요청하면 accpet()가 실행되고 작업을 thread에게 넘긴후 다시 대기 상태로 돌아간다.
0 개의 댓글:
댓글 쓰기