서버는 응답을
연결이 끊어진다.
package webserver;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
// 클라이언트가 접속할 때까지 대기할때 필요한 객체가 ServerSocket;
ServerSocket serverSocekt = new ServerSocket(10000);
System.out.println("1");
Socket clientSocket = serverSocekt.accept();
System.out.println("2");
}
}
serverSocekt.accept()
는 Socket을 반환한다.
package webserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
// 클라이언트가 접속할 때까지 대기할때 필요한 객체가 ServerSocket;
ServerSocket serverSocekt = new ServerSocket(10000);
System.out.println("1");
Socket clientSocket = serverSocekt.accept();
System.out.println("2");
InputStream inputStream = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
System.out.println(br.readLine());
}
}
클라이언트가 위와 같이 요청한다면, 아래와 같은 응답을 한다.
System.out.println(br.readLine());
package webserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
// 클라이언트가 접속할 때까지 대기할때 필요한 객체가 ServerSocket;
ServerSocket serverSocekt = new ServerSocket(10000);
System.out.println("1");
Socket clientSocket = serverSocekt.accept();
System.out.println("2");
InputStream inputStream = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
System.out.println(br.readLine());
String line = null;
line = br.readLine();
if(!line.equals("")) // 빈 줄이 아니라면
System.out.println(line);
line = br.readLine();
if(!line.equals("")) // 빈 줄이 아니라면
System.out.println(line);
line = br.readLine();
if(!line.equals("")) // 빈 줄이 아니라면
System.out.println(line);
line = br.readLine();
if(!line.equals("")) // 빈 줄이 아니라면
System.out.println(line);
line = br.readLine();
if(!line.equals("")) // 빈 줄이 아니라면
System.out.println(line);
line= br.readLine();
if(!line.equals("")) // 빈 줄이 아니라면
System.out.println(line);
line= br.readLine();
if(!line.equals("")) // 빈 줄이 아니라면
System.out.println(line);
line= br.readLine();
if(!line.equals("")) // 빈 줄이 아니라면
System.out.println(line);
}
}
결과는,
package webserver;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
// 클라이언트가 접속할 때까지 대기할때 필요한 객체가 ServerSocket;
ServerSocket serverSocekt = new ServerSocket(10000);
System.out.println("1");
Socket clientSocket = serverSocekt.accept();
System.out.println("2");
InputStream inputStream = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
System.out.println(br.readLine());
String line = null;
while(!(line = br.readLine()).equals("")){
System.out.println(line);
}
// 빈줄까지 읽어들이면 끝
System.out.println("3 - 응답을 한다.");
}
}
훨씬 깔끔해 졌다..!
응답 메세지로 첫 줄에는 위와 같은 메세지가 있다.
OutputStream outputStream = clientSocket.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream));
System.out.println("3- 응답을 한다.");
pw.println("HTTP/1.1 200 OK");
pw.println("name: kim");
pw.println("email:urstory@gmail.com");
pw.println();
pw.println("hello world");
pw.println("</html>");
pw.flush();
br.close();
pw.close();
clientSocket.close();
serverSocket.close();
package webserver;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
// 클라이언트가 접속할 때까지 대기할때 필요한 객체가 ServerSocket;
ServerSocket serverSocekt = new ServerSocket(10000);
System.out.println("1");
Socket clientSocket = serverSocekt.accept();
System.out.println("2");
InputStream inputStream = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
OutputStream outputStream = clientSocket.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream));
// System.out.println(br.readLine());
String line = null;
while(!(line = br.readLine()).equals("")){
System.out.println(line);
}
// 빈줄까지 읽어들이면 끝
System.out.println("3 - 응답을 한다.");
pw.println("HTTP/1.1 200 OK"); // 응답
pw.println("name : kim"); // 응답
pw.println("email:eoho115@naver.com"); // 응답
pw.println();
pw.println("<html>"); // 응답
pw.println("hello world"); // 응답
pw.println("</html>"); // 응답
pw.flush();
br.close();
pw.close();
clientSocket.close();
serverSocekt.close();
}
}
/
뒤에 있는 부분이 클라이언트가 서버에게 요청하는 요청 정보이다.
서버는 클라이언트의 요청정보에 따라 다른 정보를 주어야한다...!!
어떻게 해야할까?
String msg = "";
if(firstLine.indexOf("/hello") >= 0)
msg = "hello";
else if(firstLine.indexOf("/hi") >= 0)
msg = "hi";
package webserver;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
// 클라이언트가 접속할 때까지 대기할때 필요한 객체가 ServerSocket;
ServerSocket serverSocekt = new ServerSocket(10000);
System.out.println("1");
Socket clientSocket = serverSocekt.accept();
System.out.println("2");
InputStream inputStream = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
OutputStream outputStream = clientSocket.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream));
// System.out.println(br.readLine());
String firstLine = br.readLine();
String msg = "";
if(firstLine.indexOf("/hello") >= 0)
msg = "hello";
else if(firstLine.indexOf("/hi") >= 0)
msg = "hi";
String line = null;
while(!(line = br.readLine()).equals("")){
System.out.println(line);
}
// 빈줄까지 읽어들이면 끝
System.out.println("3 - 응답을 한다.");
pw.println("HTTP/1.1 200 OK"); // 응답
pw.println("name : kim"); // 응답
pw.println("email:eoho115@naver.com"); // 응답
pw.println();
pw.println("<html>"); // 응답
pw.println( msg + "world"); // 응답
pw.println("</html>"); // 응답
pw.flush();
br.close();
pw.close();
clientSocket.close();
serverSocekt.close();
}
}
위와 같이 연속해서 클라이언트가 서버에 요청할 경우, 연결이 되지 않는다.!!
어떻게 해야할까?
while문을 이용해 무한루프를 해주자.
package webserver;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
// 클라이언트가 접속할 때까지 대기할때 필요한 객체가 ServerSocket;
ServerSocket serverSocekt = new ServerSocket(10000);
System.out.println("1");
try{
while (true) {
Socket clientSocket = serverSocekt.accept();
System.out.println("2");
InputStream inputStream = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
OutputStream outputStream = clientSocket.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream));
// System.out.println(br.readLine());
String firstLine = br.readLine();
String msg = "";
if (firstLine.indexOf("/hello") >= 0)
msg = "hello";
else if (firstLine.indexOf("/hi") >= 0)
msg = "hi";
String line = null;
while (!(line = br.readLine()).equals("")) {
System.out.println(line);
}
// 빈줄까지 읽어들이면 끝
System.out.println("3 - 응답을 한다.");
pw.println("HTTP/1.1 200 OK"); // 응답
pw.println("name : kim"); // 응답
pw.println("email:eoho115@naver.com"); // 응답
pw.println();
pw.println("<html>"); // 응답
pw.println(msg + "world"); // 응답
pw.println("</html>"); // 응답
pw.flush();
br.close();
pw.close();
clientSocket.close();
}
}finally {
serverSocekt.close();
}
}
}
클라이언트가 서버에게 연속으로 요청해도 끊기지 않고 정보를 보내준다.
package webserver;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
// 클라이언트가 접속할 때까지 대기할때 필요한 객체가 ServerSocket;
ServerSocket serverSocekt = new ServerSocket(10000);
System.out.println("1");
try{
while (true) {
Socket clientSocket = serverSocekt.accept();
System.out.println("2");
run(clientSocket);
}
}finally {
serverSocekt.close();
}
}
private static void run(Socket clientSocket) throws IOException {
InputStream inputStream = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
OutputStream outputStream = clientSocket.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream));
// System.out.println(br.readLine());
String firstLine = br.readLine();
String msg = "";
if (firstLine.indexOf("/hello") >= 0)
msg = "hello";
else if (firstLine.indexOf("/hi") >= 0)
msg = "hi";
String line = null;
while (!(line = br.readLine()).equals("")) {
System.out.println(line);
}
// 빈줄까지 읽어들이면 끝
System.out.println("3 - 응답을 한다.");
pw.println("HTTP/1.1 200 OK"); // 응답
pw.println("name : kim"); // 응답
pw.println("email:eoho115@naver.com"); // 응답
pw.println();
pw.println("<html>"); // 응답
pw.println(msg + "world"); // 응답
pw.println("</html>"); // 응답
pw.flush();
br.close();
pw.close();
clientSocket.close();
}
}
ClientThread
클래스를 만들고 Thread
를 상속받자.
Client Thread
클래스에서는 Socket형태의 clientSocket 변수를 가지고 있고, 이를 생성자를 이용해 초기화 해준다.
ClientThread
클래스에서 위에서 Refactor 했던 run() 메소드의 내용을 붙이자.
완성된 ClientThread
코드
class ClientThread extends Thread{
private Socket clientSocket;
public ClientThread(Socket clientSocket){
this.clientSocket = clientSocket;
}
public void run(){
try{
InputStream inputStream = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
OutputStream outputStream = clientSocket.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream));
// System.out.println(br.readLine());
String firstLine = br.readLine();
String msg = "";
if (firstLine.indexOf("/hello") >= 0)
msg = "hello";
else if (firstLine.indexOf("/hi") >= 0)
msg = "hi";
String line = null;
while (!(line = br.readLine()).equals("")) {
System.out.println(line);
}
// 빈줄까지 읽어들이면 끝
System.out.println("3 - 응답을 한다.");
pw.println("HTTP/1.1 200 OK"); // 응답
pw.println("name : kim"); // 응답
pw.println("email:eoho115@naver.com"); // 응답
pw.println();
pw.println("<html>"); // 응답
pw.println(msg + "world"); // 응답
pw.println("</html>"); // 응답
pw.flush();
br.close();
pw.close();
clientSocket.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
}
ClientThread
객체를 만들고, 객체.start()를 이용해 스레드를 작동시키자.
ClientThread ct = new ClientThread(clientSocket);
ct.start();
전체 코드
package webserver;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class WebServer {
public static void main(String[] args) throws IOException {
// 클라이언트가 접속할 때까지 대기할때 필요한 객체가 ServerSocket;
ServerSocket serverSocekt = new ServerSocket(10000);
System.out.println("1");
try {
while (true) {
Socket clientSocket = serverSocekt.accept();
System.out.println("2");
ClientThread ct = new ClientThread(clientSocket);
ct.start();
}
} finally {
serverSocekt.close();
}
}
}
class ClientThread extends Thread{
private Socket clientSocket;
public ClientThread(Socket clientSocket){
this.clientSocket = clientSocket;
}
public void run(){
try{
InputStream inputStream = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
OutputStream outputStream = clientSocket.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream));
// System.out.println(br.readLine());
String firstLine = br.readLine();
String msg = "";
if (firstLine.indexOf("/hello") >= 0)
msg = "hello";
else if (firstLine.indexOf("/hi") >= 0)
msg = "hi";
String line = null;
while (!(line = br.readLine()).equals("")) {
System.out.println(line);
}
// 빈줄까지 읽어들이면 끝
System.out.println("3 - 응답을 한다.");
pw.println("HTTP/1.1 200 OK"); // 응답
pw.println("name : kim"); // 응답
pw.println("email:eoho115@naver.com"); // 응답
pw.println();
pw.println("<html>"); // 응답
pw.println(msg + "world"); // 응답
pw.println("</html>"); // 응답
pw.flush();
br.close();
pw.close();
clientSocket.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
}
실행 결과
위와 같이 world 계속 출력 되는 것을 알 수 있다.
만약 클라이언트가 GET / hello HTTP/1.1
의 요청을 보냈다면 서버는 /hello
에 대한 파일을 읽어서 출력해야 한다. 하지만 파일의 형태가 무엇인지는 알 수 없다.
이미지 파일을 요청하면 이미지파일을 출력해줘야 한다.
위의 그림과 같이 네이버 도메인의 이미지들은 각각 content-length
와 content-type
을 가지고 있다.
클라이언트의 이미지 요청이 오면, 이미지의 파일의 크기를 읽어들여서 Header부분에서 content-length
, content-type
을 읽고 우리의 브라우저는 서버가 요청해준 만큼만 준비를 하면 된다!
위에서 우리는 좋은 웹 서버를 만들기 위해서는 이미지나 파일들의 크기와 타입들을 클라이언트에게 전달을 해주어야 한다고 했다. 이 역할은 flush();
메소드를 통해 이루어 진다.
즉 위의 코드의 문제점은 flush();
를 firstList()
을 출력하고나서 전달을 한다는 것이다.
flush()
를 앞에서 한번 더 사용해 미리 정보를 클라이언트에게 전달해 주자!