http://www.hanbit.co.kr/store/books/look.php?p_code=E1064947038
웹 프로그래머를 위한 서블릿 컨테이너의 이해
JSP/서블릿은 웹 개발에 많이 사용하고 있지만 서블릿을 제대로 알고 사용하는 개발자는 많지 않습니다. 이는 대부분의 웹 개발자가 웹 애플리케이션 서버에서 제공하는 실행 환경 위에서 동작하는 코드를 작성하기 때문입니다. 그래서 웹 관련 문제가 발생하였을 때, 문제의 원인조차 파악하지 못하는 경우가 많아졌습니다. 이 책은 웹을 개발하면서 겪어 봤을 서블릿 컨테이너 관련 문제점과 궁금증을 속 시원하게 풀어줍니다. 서블릿의 동작원리, 개발 시 겪게 되는 문제
www.hanbit.co.kr
위 책에서 나오는 예제소스입니다.
주요 keyPoint는 Body length를 헤더의 ContentLength를 참고하는것.
Todo. 해당 코드를 분석한 후 C로 옮깁시다.
작년에 고생했었던 애증의 HTTP Server를 깨부숩시다
vim따윈 쓰지않는다 VScode쓸거다
public class Server2 {
public static void main(String[] args) throws IOException {
Server2 server = new Server2();
server.boot();
}
public static final byte CR = '\r';
public static final byte LF = '\n';
private ServerSocket serverSocket;
private void boot() throws IOException {
serverSocket = new ServerSocket(8000);
Socket socket = serverSocket.accept();
InputStream in = socket.getInputStream();
int oneInt = -1;
byte oldByte = (byte)-1;
StringBuilder sb = new StringBuilder();
int lineNumber = 0;
boolean bodyFlag = false;
String method = null;
String requestUrl = null;
String httpVersion = null;
int contentLength = -1;
int bodyRead = 0;
List<Byte> bodyByteList = null; //message Body에 해당
Map<String, String> headerMap = new HashMap<String, String>();
while(-1 != (oneInt = in.read())) {// TCP단에서 커넥션이 끊길경우(-1반환) stream에서 읽어오기를 중단한다.
byte thisByte = (byte)oneInt;
//message Body에 해당.
if(bodyFlag) {
bodyRead++;
bodyByteList.add(thisByte);
if(bodyRead >= contentLength) {
break;
}
}
else {
if(thisByte == Server2.LF && oldByte == Server2.CR) { //한행의 마지막 체크
String oneLine = sb.substring(0, sb.length()-1);
lineNumber++;
//첫번째 행. HTTP MEthod, 요청 URL, 버전을 알아낸다. 예를들어..
//GET / HTTP/1.1 첫번째라인의 첫번째 글자부터 ~ 첫번째 공백까지는 'Method'에 해당하게 된다.
if(lineNumber == 1) {
int firstBlank = oneLine.indexOf(" ");
int secondBlank = oneLine.lastIndexOf(" ");
method = oneLine.substring(0, firstBlank); //GET OR POST에 해당.
requestUrl = oneLine.substring(firstBlank + 1, secondBlank); // 첫번째 공백 다음글자 + 두번째 공백 까지는 Url에 해당.
httpVersion = oneLine.substring(secondBlank + 1); // httpVersion은 두번째 공백을 시작으로 마지막 글자까지.
}
else {
//Message Body가 시작되기 전에 있는 빈공백줄을 읽음. 즉, header가 끝났음을 의미.
if(oneLine.length() <= 0) {
bodyFlag = true;
if("GET".equals(method)) {
//GET방식이면 Body가 없으므로, read를 멈춘다.
break;
}
String contentLengthValue = headerMap.get("Content-Length");
if(contentLengthValue != null) {
contentLength = Integer.parseInt(contentLengthValue.trim());
bodyFlag = true;
bodyByteList = new ArrayList<Byte>();
}
continue; // content-length값을 얻어 온 후, '
}
//header를 key와 value로 읽어서 headerMap에 넣기.
int indexOfColon = oneLine.indexOf(":");
String headerName = oneLine.substring(0, indexOfColon);
String headerValue = oneLine.substring(indexOfColon + 1);
headerMap.put(headerName, headerValue);
}
sb.setLength(0);//읽어온 한줄에대한 작업이 끝났다.
}
else { // 그 행의 마지막이 아니라면,(LF&CR) string builder에 붙인다.
sb.append((char)thisByte);
}
}
oldByte = (byte)oneInt;
}//while
in.close();
socket.close();
System.out.printf("METHOD: %s REQ: %s HTTP VER. %s\n", method, requestUrl, httpVersion);
System.out.println("headerList");
Set<String> keySet = headerMap.keySet();
Iterator<String> keyIter = keySet.iterator();
while(keyIter.hasNext()) {
String headerName = keyIter.next();
System.out.printf("Key :%s Value:%s\n",headerName, headerMap.get(headerName));
}
if(bodyByteList != null) {
System.out.print("Message Body -->");
for(byte oneByte : bodyByteList) {
System.out.print(oneByte);
}
System.out.println("<--");
}
System.out.println("end of HTTP Messate.");
}//boot()
}//Class
'Today I learned' 카테고리의 다른 글
iamroot 오리엔테이션 (0) | 2019.05.20 |
---|---|
MyBuilder 1일차 교육 정리 (0) | 2019.04.25 |
객체지향 자바스크립트. 그리고 프로토타입 (0) | 2019.04.10 |
sql 회귀학습 (0) | 2019.04.10 |
컬렉션 프레임워크 그리고 Iterator, Enumeration (0) | 2019.04.05 |
댓글