ネットワーク

8874 ワード

index.htmlファイルを作成して、コードを実行して、住所を書いて実行することができます!
package ex07.network.simpleWebServer06;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/*
 * https://www.naver.com
 * https://www.naver.com/index.html
 * 
https://   => http프로토콜에 secure를 적용했다
www.naver.com   => 주소 (DNS Server에서 요청하면 ip를 알려준다)
index.html   => 나 이 페이지 다운로드해줘
브라우저 내부의 렌더링 엔진 : 화면을 구성
*/

public class SimpleWebServer {
	public final static int PORT = 80; // http 포트

	public static void main(String[] args) {
		try {
			ServerSocket server = new ServerSocket(PORT);
			while (true) {
				System.out.println("[서버] 브라우저 접속 대기...");
				Socket sock = server.accept();
				System.out.println("[서버] 새로운 스레드 생성...");
				HttpThread ht = new HttpThread(sock);
				ht.start();
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}
}

class HttpThread extends Thread {
	Socket sock;
	BufferedReader br;
	PrintWriter pw;

	public HttpThread(Socket sock) {
		this.sock = sock;
		try {
			// 읽기 객체
			br = new BufferedReader(new InputStreamReader(sock.getInputStream()));
			// 쓰기 객체
			pw = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}

	public void run() {
		BufferedReader fbr = null;
		
		try {
			// 1. 브라우저가 보내는 데이터를 얻는다
			// 원하는 파일이름을 추출한다
			String line = br.readLine();
			System.out.println("-----<브라우저 데이터>-----");
			System.out.println(line);
			System.out.println("-------------------------");
			// 파일이름이 있으면 추출하자
			int start = line.indexOf(" ") + 2;
			int end = line.lastIndexOf("HTTP") - 1;
			String filename = line.substring(start, end);
			// 명시적인 파일이름이 있으면 그 파일을 전달하고,
			// 파일 이름을 명시하지 않으면 그냥 index.html로 정해주겠다
			if(filename.equals(""))
				filename = "index.html";
			System.out.println("브라우저가 " + filename + "을 요청");

			// 2. 파일에서 데이터를 읽는다
			// 파일을 읽기 위해 객체와 연결시키자
			fbr = new BufferedReader(new FileReader(filename));

			// 3. 브라우저에 전송한다
			// 파일을 읽어서 브라우저(클라이언트)에 전송하자
			System.out.println("-----<서버 전송>-----");
			while(true) {
				// 요청 파일을 읽어서 1줄씩 전달하자
				String fline = fbr.readLine();
				if(fline==null)	// 더 이상 읽을 것이 없으면 탈출
					break;
				System.out.println(fline);
				pw.println(fline);
				pw.flush();
			}
			System.out.println("------------------------");
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}finally {
			try {
				if(fbr!=null) fbr.close();
				if(br!=null) br.close();
				if(pw!=null) pw.close();
				if(sock!=null) sock.close();
			}catch(Exception e) {
				e.printStackTrace();
				System.out.println(e.getMessage());
			}
		}
	}
}

サーバー

package ex07.network.cmdPacketServer07;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

//서버는 서비스를 제공하는 프로그램을 일컫는다.
//1) 고정된 주소를 가진다(주소를 부여)
//2) 접속 요청하는 클라이언트를 받아줘야 한다(accept)
//3) 요청을 받아들이면 내부에서는 2개 스트림이 형성된다
//4) 스트림이 형성되면 송수신이 가능하다
//5) 작업이 완료되면 close를 통해 스트림을 해제한다
//
//EchoServer : 클라이언트가 보내온 데이터를 그래도 돌려주는
//                    서버

public class CmdPacketServer {
	public static String[] parsePacket(String line) {
		String[] params = line.split("\\|");  //이 글자를 기준으로 자르겠다 
		return params;
	}
	public static String runCmd(String cmd, int num0, int num1) {
		int result = 0;
		switch(cmd) {	//cmd의 종류에 따라 값0과 값1의 처리를 다르게.
		case "+": result = num0 + num1;	break;
		case "-": result = num0 - num1; break;
		case "*": result = num0 * num1; break;
		case "/": result = num0 / num1; break;
		}
		return result + "";
	}
	public static void main(String[] args) {
		try {
//		1) 소켓 객체 생성한다
//          : tcp/udp와 연결하기 위한 소켓 객체 생성
//          : 소켓에는 클라이언트가 찾아오기 위한 주소 부여

			// 소켓 객체 생성,
			// 주소 : ip, port
			// ip: Host(PC)를 찾기 위한 주소
			// port: 프로세스들이 상대방과 통신하려고 약속된
			// 번호
			// 192.168.0.13 9000이렇게 지정한 Client만
			// 이 서버와 통신 가능
			// ip는 따로 설정하지 않아도 Host의 주소를 사용
			// port : 9000
			ServerSocket server = new ServerSocket(9000);

			// 클라이언트가 접속하기를 대기(여기서 멈춰있음)
			// 클라이언트와 연결되면 연결 소켓을 반환
			// 이 연결소켓으로 통신을 할 수 있다

			// ex)VIPS를 방문하면 입구에 안내직원(server)
			// 이 대기하라고 하고 서비스 직원(sock)을 연결시켜준
			System.out.println("클라이언트 접속 대기...");
			Socket sock = server.accept();

			// 연결이 되면 상대방의 주소를 알 수 있다
			InetAddress inetAddr = sock.getInetAddress();
			System.out.println(inetAddr.getHostAddress() + "로부터 접속");

			// 연결이 되었으니까 통신을 하자
			// 통신하는 스트림객체를 얻어오자
			OutputStream out = sock.getOutputStream();
			OutputStreamWriter outW = new OutputStreamWriter(out);
			PrintWriter pw = new PrintWriter(outW);

			InputStream in = sock.getInputStream();
			InputStreamReader inR = new InputStreamReader(in);
			BufferedReader br = new BufferedReader(inR);

			while (true) {
				// 클라이언트가 보내는 데이터를 기다리자
				String line = br.readLine();
				if (line == null) {
					System.out.println("클라이언트와 연결 X");
					break;
				}
				System.out.println("클라이언트로부터 수신 : " + line);
				String[] params = parsePacket(line);
				String result = runCmd(params[0], 
						Integer.parseInt(params[1]),
						Integer.parseInt(params[2]));
				System.out.printf("%s %s %s = %s",
						params[1], params[0],
						params[2], result);
				pw.println(result); // 클라이언트에 결과값 전송
				pw.flush(); // 버퍼에 남기지 말고 즉시
			}
			System.out.println("클라이언트-서버 연결 종료");
			pw.close();
			br.close();
			sock.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}
}

クライアント

package ex07.network.cmdPacketClient08;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

/*
클라이언트 프로그램
1) 서버의 주소(ip, port)를 가지고 서버에 접속(connect)
2) 접속 후에 통신이 가능
3) 접속중단은 close

[서버와 클라이언트 간에는 약속이 필요하다 ]
==> 약속 == 프로토콜 
cmd|값0|값1
cmd의 종류에 따라 값0과 값1의 처리를 다르게 한다
cmd : 처리를 결정 

ex)
A|코로나 조심하세요 => Alarm 메시지
I|진황의 검|물약|물약|포션|단검 => Information
P|I|253.34|345.23|345.56 => 위도 경도 고도 position Interval 전송 
P|E|253.34|345.23|345.56 => 위도 경도 고도 position Emergency 전송 (정해주기나름) 

*/

public class CmdPacketClient {
	public static void main(String[] args) {
		try {
			// 127.0.0.1 : 현재 나의 Host의 주소, loop 주소
			// Socket sock = new Socket("192.168.0.13", 9000);
			// Socket생성자에서 내부적으로 connect를 진행
			// 객체가 만들어지면 서버와 이미 연결 상태
			Socket sock = new Socket("127.0.0.1", 9000);
			// 키보드 데이터 입력 객체 생성
			InputStreamReader inK = 
					new InputStreamReader(System.in);
			BufferedReader keyboard = 
					new BufferedReader(inK);
			
			// 통신 스트림 객체
			OutputStream out = sock.getOutputStream();
			OutputStreamWriter outW = 
					new OutputStreamWriter(out);
			PrintWriter pw = new PrintWriter(outW);
			
			InputStream in = sock.getInputStream();
			InputStreamReader inR = 
					new InputStreamReader(in);
			BufferedReader br = new BufferedReader(inR);
			
			while(true) {
				System.out.print("연산자 입력(+ - * / quit) >> ");
				String cmd = keyboard.readLine();
				if(cmd.equals("quit")) {
					System.out.println("클라이언트 종료");
					break;
				}
				System.out.print("첫번째 숫자 입력 >> ");
				int num0 = Integer.parseInt(keyboard.readLine());
				System.out.print("두번째 숫자 입력 >> ");
				int num1 = Integer.parseInt(keyboard.readLine());
				
				
				//약속대로 패킷 구성 
				String line = String.format("%s|%d|%d",	//이런식으로 보낸다. 연산자(문자열,숫자,숫자) 
									cmd, num0, num1);
				System.out.println("서버로 패킷 전송 : " + line);
				pw.println(line);
				pw.flush();
				// 서버가 echo하는 것을 받아서 출력
				String echo = br.readLine();
				System.out.println("서버로부터 수신 : " + echo);
			}
			pw.close();
			outW.close();
			out.close();
			br.close();
			inR.close();
			in.close();
			sock.close();	
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}
	}
}