Continuous Challenge

[Java의 정석_연습문제 풀이] Chapter16. 네트워킹 본문

Study/Java의 정석

[Java의 정석_연습문제 풀이] Chapter16. 네트워킹

응굥 2019. 11. 13. 09:22
728x90
728x90

[16-1] ip주소가 192.168.10.100이고 서브넷 마스크(subnet mask)가 255.255.255.0일 때, 네트워크 주소와 호스트 주소를 계산하여 화면에 출력하는 프로그램을 작성하시오. 단, 비트연산자를 사용해서 계산해야 한다.

[실행결과]

네트워크 주소 : 192.169.10.0.

호스트 주소 : 0.0.0.100.

public class Exercise16_1 {


public static void main(String[] args) {

byte[] ip = { (byte) 192, (byte) 168, (byte) 10, (byte) 100 };

byte[] subnet = { (byte) 255, (byte) 255, (byte) 255, (byte) 0 };


byte[] nwAddress = new byte[4]; // 네트워크 주소

byte[] hostAddress = new byte[4]; // 호스트 주소


System.out.println("네트워크 주소");


for (int i = 0; i < ip.length; i++) {

nwAddress[i] = (byte) (ip[i] & subnet[i]); // &연산을 수행한다.

System.out.print(nwAddress[i] >= 0 ? nwAddress[i]

: nwAddress[i] + 256);

System.out.print(".");

}


System.out.println();

System.out.println("호스트 주소 : ");


for (int i = 0; i < ip.length; i++) {

hostAddress[i] = (byte) (ip[i] & ~subnet[i]); // &연산을 수행한다.

System.out.print(hostAddress[i] >= 0 ? hostAddress[i]

: hostAddress[i] + 256);

System.out.print(".");

}

System.out.println();

}

}

해설 : 바이트 배열에 ip주소와 서브넷 마스크를 저장한 다음에 반복문을 이용해서 1byte씩 &연산을 하면 호스트 주소를 얻을 수 있다. 그리고 서브넷 마스크에 '~' 연산을 취한 다음에 ip와 &연산을 취하면 네트워크 주소를 얻을 수 있다.

 모든 bit의 값이 1인 1byte의 데이터가 있다고 할 때, 왼쪽에서 첫 번째 비트를 부호로 인식하지 않으면 부호없는 1byte가 되어 범위는 0~255이므로 이 값은 최대값이 255가 되지만, 부호로 인식하는 경우 범위는 -128~127이 되고, 이 값은 0보다 1 작은 값인 -1이 된다. 

 결국 같은 데이터이지만 자바의 자료형인 byte의 범위가 부호있는 1byte 정수의 범위인 -128~127이기 때문에 -1로 인식한다는 것이다. 그래서 이 값을 0~255사이의 값으로 변환하려면 256을 더해주어야 한다.


[16-2] 다음 중 TCP의 특징이 아닌 것은?

a. 전화와 같은 1:1 연결기반의 프로토콜이다.

b. 데이터의 전송순서가 보장된다.

c. UDP보다 전송속도가 빠르다.

d. 데이터의 수신여부를 확인한다.

답 : c

 

 TCP

UDP 

 연결방식

 연결기반(connection-oriented)

 - 연결 후 통신 (전화기)

 - 1:1 통신방식

 비연결기반(connectionless-oriented)

 - 연결없이 통신(소포)

 - 1:1, 1:n, n:n 통신방식

 특징

 데이터의 경계를 구분안함 (byte-stream)

 신뢰성있는 데이터 전송

 - 데이터의 전송순서가 보장됨

 - 데이터의 수신여부를 확인함

   (데이터가 손실되면 재전송됨)

 - 패킷을 관리할 필요가 없음

 UDP보다 전송속도가 느림

 데이터의 경계를 구분함 (datagram)

 신뢰성없는 데이터 전송

 - 데이터의 전송순서가 바뀔 수 있음

 - 데이터의 수신여부를 확인 안 함

   (데이터가 손실되어도 알 수 없음)

 - 패킷을 관리해주어야 함

 TCP보다 전송속도가 빠름

 관련 클래스

 Socket

 ServerSocket

 DatagramSocket

 DatagramPacket

 MulticastSocket 



[16-3] TextField에 URL을 입력하고 Enter키를 누르면 해당 페이지의 소스를 보여주는 'Source Viwer' 프로그램이다. 예제 15-4를 참고해서 (1)에 알맞은 코드를 넣어 완성하시오.

import java.net.*;

import java.io.*;

import java.awt.*;

import java.awt.event.*;


class SourceViewer extends Frame {

TextField tf = new TextField();

TextArea ta = new TextArea();


SourceViewer(String title) {

super(title);

add(tf, "North");

add(ta, "Center");

tf.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent ae) {

displaySource();

}

});


addWindowListener(new WindowAdapter() {

public void windowClosing(WindowEvent we) {

System.exit(0);

}

});

setBounds(500, 200, 500, 300);

setVisible(true);

}


void displaySource() {

URL url = null;

BufferedReader input = null;

String address = tf.getText().trim();

String line = "";

ta.setText("");

try {

if (!address.startsWith("http://"))

address = "http://" + address;

/* 

* (1) 알맞은 코드를 넣어 완성하시오. 

*/ 

input.close();

} catch (Exception e) {

ta.setText("유효하지 않은 URL입니다.");

}

} // displaySource()


public static void main(String[] args) {

SourceViewer mainWin = new SourceViewer("Source Viewer");

}

}

url = new URL(address);

input = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));


while((line=input.readLine()) != null) {

ta.append(line);

ta.append("\n");

}

해설 : URL클래스를 이용해서 해당 URL으로부터 데이터를 읽어오는 문제이다. 


[16-4] 다음의 코드는 TCP통신을 하는 예제16-6, 16-7을 결합하여 GUI채팅프로그램을 작성한 것이다. (1)~(4)에 알맞은 코드를 넣어 프로그램을 완성하시오.

import java.net.*;

import java.io.*;

import java.awt.*;

import java.awt.event.*;


class ChatServer extends Frame {

String nickname = "";


DataOutputStream out;

DataInputStream in;


Panel p = new Panel();

TextArea ta = new TextArea();

TextField tf = new TextField();


ChatServer(String nickname) {

super("Chatting");

this.nickname = nickname;


p.setLayout(new BorderLayout());

p.add(tf, "Center");


add(ta, "Center");

add(p, "South");


addWindowListener(new WindowAdapter() {

public void windowClosing(WindowEvent e) {

System.exit(0);

}

});

EventHandler handler = new EventHandler();

ta.addFocusListener(handler);

tf.addFocusListener(handler);

tf.addActionListener(handler);

ta.setEditable(false);

setBounds(200, 200, 300, 200);

setVisible(true);

tf.requestFocus();

}


void startServer() {

ServerSocket serverSocket = null;

Socket socket = null;

try {

/*

* (1) 아래의 로직에 맞게 코드를 작성하시오. 

* 1. 서비소켓을 생성하여 7777번 포트와 결합시킨다. 

* 2. ta에 "서버가 준비되었습니다." 라고 보여준다. 

* 3. 상대방의 연결을 기다린다. 

* 4. ta에 "상대방과 연결되었습니다." 라고 보여준다. 

*    ta.append("\r\n" +"상대방과 연결되었습니다.");

* 5. 반복문을 이용해서 입력스트림이 null이 아닌 동안 

*     입력스트림으로부터 데이터를 읽어서 변수 msg에 저장한다.

*/ 

ta.append("\r\n" + msg);

} catch (Exception e) {

e.printStackTrace();

}

}


public static void main(String[] args) {

if (args.length != 1) {

System.out.println("USAGE : java ChatServer NICKNAME");

System.exit(0);

}


ChatServer chatWin = new ChatServer(args[0]);

chatWin.startServer();

} // main


class EventHandler extends FocusAdapter implements ActionListener {

public void actionPerformed(ActionEvent ae) {

String msg = tf.getText();

if ("".equals(msg))

return;

/*

* (2) 알맞은 코드를 넣어 완성하시오.

*/

ta.append("\r\n" + nickname + ">" + msg);

tf.setText("");

}


public void focusGained(FocusEvent e) {

tf.requestFocus();

}

} // class EventHandler

} // class

(1)

serverSocket = new ServerSocket(7777);

ta.setText("서버가 준비되었습니다.");

socket = serverSocket.accept();

ta.append("\r\n" +"상대방과 연결되었습니다.");


in = new DataInputStream(socket.getInputStream());

out = new DataOutputStream(socket.getOutputStream());


while(in!=null) {

try {

String msg = in.readUTF();

ta.append("\r\n" + msg);

} catch(IOException e) {}

}


(2)

if(out!=null) {

try{

out.writeUTF(nickname+">"+msg);

}catch(IOException e) {}

}


import java.net.*;

import java.io.*;

import java.awt.*;

import java.awt.event.*;


class ChatClient extends Frame {

String nickname = "";

String serverIp = "";

int serverPort = 0;

DataOutputStream out;

DataInputStream in;

Panel p = new Panel();

TextArea ta = new TextArea();

TextField tf = new TextField();


ChatClient(String nickname, String serverIp, String serverPort) {

super("Chatting with " + serverIp + ":" + serverPort);

this.nickname = nickname;

this.serverIp = serverIp;

this.serverPort = Integer.parseInt(serverPort);

setBounds(600, 200, 300, 200);

p.setLayout(new BorderLayout());

p.add(tf, "Center");

add(ta, "Center");

add(p, "South");

addWindowListener(new WindowAdapter() {

public void windowClosing(WindowEvent e) {

System.exit(0);

}

});

EventHandler handler = new EventHandler();

ta.addFocusListener(handler);

tf.addFocusListener(handler);

tf.addActionListener(handler);

ta.setEditable(false);

setVisible(true);

tf.requestFocus();

}


void startClient() { 

try { 

/* (3) 아래의 로직에 맞게 코드를 작성하시오. 

* 1. 소켓을 생성하여 serverIp의 serverPort에 연결한다.

* 2. ta에 "상대방과 연결되었습니다."라고 보여준다   

*   ta.setText("상대방과 연결되었습니다."); 

* 3. 연결된 상대방 소켓의 입력스트림과 출력스트립을 얻어온다. 

* 4. 반복문을 이용해서 입력스트림이 null이 아닌 동안

*     입력스트림으로부터 데이터를 읽어서 변수 msg에 저장한다.

*/ 

ta.append("\r\n" + msg); 

} catch(ConnectException ce) { 

ta.setText("상대방과 연결할 수 없습니다."); 

ce.printStackTrace(); 

} catch(IOException ie) { 

ie.printStackTrace(); 

} catch(Exception e) { 

e.printStackTrace(); 

}

}


public static void main(String[] args) {

if (args.length != 3) {

System.out.println("USAGE : java ChatClient NICKNAME SERVER_IP SERVER_PORT");

System.exit(0);

}

ChatClient chatWin = new ChatClient(args[0], args[1], args[2]);

chatWin.startClient();

} // main 

class EventHandler extends FocusAdapter implements ActionListener {

public void actionPerformed(ActionEvent ae) {

String msg = tf.getText();

if ("".equals(msg))

return;

/* 

* (4) 알맞은 코드를 넣어 완성하시오. 

*/ 

ta.append("\r\n" + nickname + ">" + msg);

tf.setText("");

}


public void focusGained(FocusEvent e) {

tf.requestFocus();

}

} // class EventHandler

} // class

(3)

Socket socket = new Socket(serverIp, serverPort);

ta.setText("상대방과 연결되었습니다.");


in = new DataInputStream(socket.getInputStream());

out = new DataOutputStream(socket.getOutputStream());


while(in!=null){

try{

String msg = in.readUTF();

ta.append("\r\n"+msg);

}catch(IOException e) {}

}


(4)

if(out!=null){

try{

out.writeUTF(nickname+">"+msg);

}catch(IOException e) {}

}


728x90
728x90
Comments