DNS는 도메인 이름으로, IP를 등록하는 저장소이다. 대중에게 서비스를 제공하는 대부분의 컴퓨터는 다음과 같이 도메인 이름으로 IP를 DNS에 미리 등록한다.
InetAddress ia = InetAddress.getLocalHost();
컴퓨터의 도메인 이름을 알고 있다면 아래 두 개의 메소드를 사용하여 UnetAddress객체를 얻을 수 있다.
InetAddress ia = InetAddress.getByName(String domainName);
InetAddress[] iaArr = InetAddress.getAllByName(String domainName);
이 메소드들로부터 얻은 InetAddress 객체에서 IP주소를 얻으려면 getHostAddress() 메소드를 아래와 같이 호출하면 된다. 리턴값은 문자열로 된 IP 주소이다.
String ip = InetAddress.getHostAddress();
아래는 50001번 Port에 바인딩하는 ServerSocket을 생성하는 코드이다.
ServerSocket serverSocket = new ServerSoket(50001);
또 다른 방법으로는 기본 생성자로 객체 생성후 Port바인딩을 위해 bind() 메소드를 사용하는 것이다.
ServerSocket serverSocket = new ServerSoket();
serverSocket.bind(new InetSoketAddress(50001));
만약 서버 컴퓨터에 여러 개의 IP할당시, 특정 IP에서만 서비스를 하고 싶다면 InetSocketAddress의 첫 번째 매개값으로 해당 IP를 주면 된다.
ServerSocket serverSoket = new ServerSocket();
serverSocket.bind( new InetSoketAddress("첫번째 아이피", 50001));
ServerSocket이 생성되었다면 연결 요청 수락을 위해 accept() 메소드를 실행해야 한다. accept()는 클라이언트가 연결 요청하기 전까지 블로킹된다. 클라이언트의 연결 요청이 들어오면 블로킹이 해제되고 통신용 Socket을 리턴
Socket socket = serverSocket.accept();
만약 리턴된 Socket을 통해 연결된 클라이언트의 IP 주소와 Port 번호를 얻고 싶다면 방법은 getRemoteSocketAddress() 메소드를 호출해서 InetSocketAddress를 얻은 다음 getHostName(), getPort() 메소드를 호출하면 된다.
Socket socket = new Socket( "IP", 50001 );
UnknownHostExeception은 IP 주소가 잘못 표기되었을 때 발생하고,
IOException은 제공된 IP와 Port 번호로 연결할 수 없을 때 발생한다. 따라서 두 가지 예외를 모두 처리해야 한다 .
//Socket으로부터 InputStream과 OutputStream을 얻는 코드
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
문자열을 좀 더 간편하게 보내고 싶다면 DataOutputStream 보조 스트림을 연결 사용
속도가 중요하면 UDP, 데이터 전달의 신뢰성이 중요하다면 TCP를 사용
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
datagramSocket.receive(receivePacket);
첫 번째 매개값은 수신된 데이터를 저장할 배열이고 두 번째 매개값은 수신할 수 있는 최대 바이트 수이다.
receive() 메소드 실행 후 수신된 데이터 바이트 수를 얻는 방법
byte[] bytes = receivePacket.getData();
int num = receivePacket.getLength();
이제 반대로 UDP 서버가 클라이언트에게 처리 내용을 보내려면 클라이언트 IP주소와 Port번호가 필요한데, DatagramPacket에서 얻을 수 있다. 그리고 getScoketAddress() 메소드를 호출하면 정보가 담긴 SocketAddress 객체를 얻을 수 있다.
이렇게 얻은 Socket Address 객체는 클라이언트로 보낼 DatagramPacket을 생성할 때 네 번째 매개값으로 사용된다. DatagramPacket 생성자의 첫 번째 매개값은 바이트 배열이고 두 번째는 인덱스, 세 번째는 보낼 바이트 수이다.
String data = "처리 내용";
byte[] bytes = data.getBytes("UTF-8");
DatagramPacket sendPacket = new DatagramPacket ( bytes, 0 , bytes.length, socketAddress );
DatagramPacket을 클라이언트로 보낼 때는 DatagramSocket의 send() 메소드를 이용한다.
datagramSocket.send( sendPacket);
요청 내용을 보내기 위한 DatagramPacket을 생성하는 방법
String data = "요청 내용";
byte[] bytes = data.getBytes("UTF-8");
DatagramPacket sendPacket = new DatagramPacket(
bytes, bytes.length, new InetSocketAddress("localhost", 50001)
);
첫 번째 매개값은 바이트 배열, 두 번째 매개값은 바이트 배열에서 보내고자 하는 바이트 수이다. 세 번째 매개값은 UDP 서버의 IP와 Port 정보를 가지고 있는 InetSocketAddress 객체이다.
accept(), receive()를 제외한 요청 처리 코드를 별도의 스레드에서 작업하는 것이 좋은데, 스레드를 처리할 때 주의할 점은 클라이언트의 폭증으로 인한 서버의 과도한 스레드 생성을 방지해야 한다는 것이다. 그래서 스레드풀을 사용하는 것이 바람직하다.
//회원 정보를 JSON으로 표기하면 다음과 같다.
{
"id" : "Winter",
"name" : "한겨울"
"age" : 25,
"student" : true,
"tel" : { "home" : 02-123-1234, "mobile : "010-123-1234" },
"skill" : { "java", "C", "C++" }
}
JSON을 문자열로 직접 작성 할 수 있지만 대부분은 라이브러리를 이용해서 생성한다.
채팅 서버와 클라이언트에서 사용할 클래스 이름
new Socket("localhost", 5001);
serverSocket.accept()
InputStream / OutputStream
OutputStream / InputStream
DatagramSocket // DatagramPacket // DatagramSocket // DatagramPacket // DatagramPacket
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
private int no;
private String name;
private int price;
private int stock;
}
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.json.JSONArray;
import org.json.JSONObject;
public class ProductServer {
private ServerSocket serverSocket;
private ExecutorService threadPool;
private List<Product> products;
private int sequence;
public void start() throws IOException {
serverSocket = new ServerSocket(50001);
threadPool = Executors.newFixedThreadPool(100);
products = new Vector<Product>();
System.out.println("[서버] 시작됨");
while (true) {
Socket socket = serverSocket.accept();
SocketClient sc = new SocketClient(socket);
}
}
public void stop() {
try {
serverSocket.close();
threadPool.shutdownNow();
System.out.println("[서버] 종료됨 ");
} catch (IOException e1) {
}
}
public class SocketClient {
private Socket socket;
private DataInputStream dis;
private DataOutputStream dos;
public SocketClient(Socket socket) {
try {
this.socket = socket;
this.dis = new DataInputStream(socket.getInputStream());
this.dos = new DataOutputStream(socket.getOutputStream());
receive();
} catch (IOException e) {
close();
}
}
public void receive() {
threadPool.execute(() -> {
try {
while (true) {
String receiveJson = dis.readUTF();
JSONObject request = new JSONObject(receiveJson);
int menu = request.getInt("menu");
switch (menu) {
case 0 -> list(request);
case 1 -> create(request);
case 2 -> update(request);
case 3 -> delete(request);
}
}
} catch (IOException e) {
close();
}
});
}
public void list(JSONObject request) throws IOException {
JSONArray data = new JSONArray();
for (Product p : products) {
JSONObject product = new JSONObject();
product.put("no", p.getNo());
product.put("name", p.getName());
product.put("price", p.getPrice());
product.put("stock", p.getStock());
data.put(product);
}
JSONObject response = new JSONObject();
response.put("status", "success");
response.put("data", data);
dos.writeUTF(response.toString());
dos.flush();
}
public void create(JSONObject request) throws IOException {
JSONObject data = request.getJSONObject("data");
Product product = new Product();
product.setNo(++sequence);
product.setName(data.getString("name"));
product.setPrice(data.getInt("price"));
product.setStock(data.getInt("stock"));
products.add(product);
JSONObject response = new JSONObject();
response.put("status", "success");
response.put("data", new JSONObject());
dos.writeUTF(response.toString());
dos.flush();
}
public void update(JSONObject request) throws IOException {
JSONObject data = request.getJSONObject("data");
int no = data.getInt("no");
for (int i = 0; i < products.size(); i++) {
Product product = products.get(i);
if (product.getNo() = =no){
product.setName(data.getString("name"));
product.setPrice(data.getInt("price"));
product.setStock(data.getInt("stock"));
}
} JSONObject response = new JSONObject();
response.put("status", "success");
response.put("data", new JSONObject());
dos.writeUTF(response.toString());
dos.flush();
}
public void delete(JSONObject request) throws IOException {
JSONObject data = request.getJSONObject("data");
int no = data.getInt("no");
Iterator<Product> iterator = products.iterator();
while (iterator.hasNext()) {
Product product = iterator.next();
if (product.getNo() = =no){
iterator.remove();
}
} JSONObject response = new JSONObject();
response.put("status", "success");
response.put("data", new JSONObject());
dos.writeUTF(response.toString());
dos.flush();
}
public void close() {
try {
socket.close();
} catch (Exception e) {
}
}
}
public static void main(String[] args) {
ProductServer productServer = new ProductServer();
try {
productServer.start();
} catch (IOException e) {
System.out.println(e.getMessage());
productServer.stop();
}
}
}
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
import org.json.JSONArray;
import org.json.JSONObject;
public class ProductClient {
private Socket socket;
private DataInputStream dis;
private DataOutputStream dos;
private Scanner scanner;
public void start() throws IOException {
socket = new Socket("localhost", 50001);
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
System.out.println("[클라이언트] 서버에 연결됨");
scanner = new Scanner(System.in);
list();
}
public void stop() {
try {
socket.close();
scanner.close();
} catch (Exception e) {
}
System.out.println("[클라이언트] 종료됨");
}
public void menu() throws IOException {
System.out.println();
System.out.println("---------------------------------------------------------------");
System.out.println("메뉴: 1.Create | 2.Update | 3.Delete | 4.Exit");
System.out.print("선택: ");
String menuNo = scanner.nextLine();
System.out.println();
switch (menuNo) {
case "1" -> create();
case "2" -> update();
case "3" -> delete();
case "4" -> exit();
}
}
public void list() throws IOException {
System.out.println();
System.out.println("[상품 목록]");
System.out.println("---------------------------------------------------------------");
System.out.printf("%-6s%-30s%-15s%-10s\n", "no", "name", "price", "stock");
System.out.println("---------------------------------------------------------------");
JSONObject request = new JSONObject();
request.put("menu", 0);
request.put("data", new JSONObject());
dos.writeUTF(request.toString());
dos.flush();
JSONObject response = new JSONObject(dis.readUTF());
if (response.getString("status").equals("success")) {
JSONArray data = response.getJSONArray("data");
for (int i = 0; i < data.length(); i++) {
JSONObject product = data.getJSONObject(i);
System.out.printf("%-6d%-30s%-15d%-10d\n", product.getInt("no"), product.getString("name"), product.getInt("price"), product.getInt("stock"));
}
}
menu();
}
public void create() throws IOException {
System.out.println("[상품 생성]");
Product product = new Product();
System.out.print("상품 이름: ");
product.setName(scanner.nextLine());
System.out.print("상품 가격: ");
product.setPrice(Integer.parseInt(scanner.nextLine()));
System.out.print("상품 재고: ");
product.setStock(Integer.parseInt(scanner.nextLine()));
JSONObject data = new JSONObject();
data.put("name", product.getName());
data.put("price", product.getPrice());
data.put("stock", product.getStock());
JSONObject request = new JSONObject();
request.put("menu", 1);
request.put("data", data);
dos.writeUTF(request.toString());
dos.flush();
JSONObject response = new JSONObject(dis.readUTF());
if (response.getString("status").equals("success")) {
list();
}
}
public void update() throws IOException {
System.out.println("[상품 수정]");
Product product = new Product();
System.out.print("상품 번호: ");
product.setNo(Integer.parseInt(scanner.nextLine()));
System.out.print("이름 변경: ");
product.setName(scanner.nextLine());
System.out.print("가격 변경: ");
product.setPrice(Integer.parseInt(scanner.nextLine()));
System.out.print("재고 변경: ");
product.setStock(Integer.parseInt(scanner.nextLine()));
JSONObject data = new JSONObject();
data.put("no", product.getNo());
data.put("name", product.getName());
data.put("price", product.getPrice());
data.put("stock", product.getStock());
JSONObject request = new JSONObject();
request.put("menu", 2);
request.put("data", data);
dos.writeUTF(request.toString());
dos.flush();
JSONObject response = new JSONObject(dis.readUTF());
if (response.getString("status").equals("success")) {
list();
}
}
public void delete() throws IOException {
System.out.println("[상품 삭제]");
System.out.print("상품 번호: ");
int no = Integer.parseInt(scanner.nextLine());
JSONObject data = new JSONObject();
data.put("no", no);
JSONObject request = new JSONObject();
request.put("menu", 3);
request.put("data", data);
dos.writeUTF(request.toString());
dos.flush();
JSONObject response = new JSONObject(dis.readUTF());
if (response.getString("status").equals("success")) {
list();
}
}
public void exit() {
stop();
}
public static void main(String[] args) {
ProductClient productClient = new ProductClient();
try {
productClient.start();
} catch (IOException e) {
System.out.println(e.getMessage());
productClient.stop();
}
}
}
솔직히 마지막 답지 없으면 절대 못함 2시간하고 그냥 내다 던짐 나중엔 할 수 있겠지