자바의 정석 공부 노트-Cheapter16 네트워킹

인삼주·2021년 9월 19일
0

0부터Java

목록 보기
1/1

이 글은 [자바의 정석] 및 [모두의 네트워크]를 참조하여 기술하였다.

네트워크 계층 중 전송 계층은 데이터를 제대로 전달하기 위한 역할을 한다.
전송 계층의 특징은 신뢰성/정확성과 효율성으로 구분된다.
신뢰할 수 있는 정확한 데이터를 전달하는 통신을 연결형 통신이라 하고, 효율적으로 데이터를 전달하는 통신을 비연결형 통신이라고 한다.
전송 계층의 연결형 통신 프로토콜에는 TCP가 사용되고, 비연결형 통신 프로토콜에는 UDP가 사용된다.
아래는 자바의 정석에 수록된 TCP소캣을 기반으로 하는 통신 코드에 주석등을 추가한 코드이다.

1.TCP소캣 프로그램
1)서버

package javasStandard.Network.organaize;
import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;

public class TcpIpServer {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        try {
            //서버 소캣을 생성하여 7777번 포트와 결합한다.
            serverSocket = new ServerSocket(7777);

            //현재 시간과 서버 준비과 완료됬다는 메세지를 출력한다.
            System.out.println(getTime() + "서버준비가 완료되었습니다.");

        } catch (IOException ioException) {
            ioException.printStackTrace();
        }


        try {
            //현재시간 출력 연결을 기다리는 중이라는 메세지를 출력한다.
            System.out.println(getTime() + "연결 요청 기다리는 중");
            //클라이언트의 접속 요청을 대기하고 받아들인다.
            Socket socket= serverSocket.accept();
            //상대편 소켓의 포트 번호와 자신의 포트번호를 출력한다.
            System.out.println("클라이언트 소켓의 포트번호: "+socket.getPort()+",서버 소켓의 포트번호: "+socket.getLocalPort());
            //소켓의 출력 스트림을 얻는다.
            OutputStream os = socket.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);

            //원격 소켓에 데이터를 보낸다.
            dos.writeUTF("data:소켓 연결 테스트");

            //스트림과 소켓을 닫아준다.
            os.close();
            socket.close();
        }catch (IOException ie){
            ie.printStackTrace();
        }

    }

    public static String getTime(){
        String dataFormat = "[hh:mm:ss]";
        return new SimpleDateFormat(dataFormat).format(new Date());
    }
}

출력결과

[02:28:55]서버준비가 완료되었습니다.

[02:28:55]연결 요청 기다리는 중

클라이언트 소켓의 포트번호: 53166,서버 소켓의 포트번호: 7777

Tip: 포트 번호는 어떤 애플리케이션인지 구분하는 역할을 한다.
포트번호는 0~655535를 사용한다.
0~1023 잘 알려진 포트 번호: 주요 프로토콜이 사용하도록 예약되어있다.
1024 예약은 되어있지만 사용되지 않는 포트
1025 이후는 랜덤 포트. 클라이언트측의 송신 포트로 사용된다.

2)클라이언트

package javasStandard.Network.organaize;
import java.net.*;
import java.io.*;

public class TcpIpClient {
    public static void main(String[] args) {
        try {
            //로컬 서버의 IP를 획득한다.
            //InetAddress -> IP주소를 다루기 위한 클래스
            //getLocalHost() -> 지역호스트의 IP주소를 InetAddress타입으로로 반환한다.
            //getHostAddress() -> 호스트의 ip주소를 스트링 타입으로 반환한다.
            String serverIp = InetAddress.getLocalHost().getHostAddress();

            //소캣을 생성하여 연결을 요청합니다.
            Socket socket = new Socket(serverIp,7777);

            //소켓 입력스트림을 얻습니다.
            InputStream is = socket.getInputStream();
            DataInputStream dis = new DataInputStream(is);
            //소켓에서 받은 데이터를 출력합니다.
            System.out.println(dis.readUTF());

            //스트림과 소켓을 닫습니다.
            is.close();
            socket.close();



        }catch(UnknownHostException ue){
            ue.printStackTrace();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }
}

출력결과

data:소켓 연결 테스트

출력결과를 보면 소켓의 스트림을 통해 서버에서 전달한 메세지가, 클라이언트 에서 수신되어 있는 것을 알 수 있다.

다음은 상기 코드에 쓰레드를 통해 데이터의 송수신이 동시에 가능하도록 한 채팅 프로그램의 코드이다.

2.쓰레드를 통한 Tcp 송수신 채팅 프로그램
1)서버

package javasStandard.Network.organaize;
import java.io.*;
import java.net.*;
import java.lang.*;
import java.util.Scanner;


public class TcpIpThreadServer {


    public static void main(String[] args)  {
        //멤버
        ServerSocket serverSocket;
        Socket socket;
        String name;

        //대화에 사용할 유저명을 입력받는다.
        Scanner scanner = new Scanner(System.in);
        System.out.print("유저명을 입력해 주세요.");
        name= scanner.nextLine();

        try {
            //서버소켓을 생성하여 7777번 포트와 결합시킨다.
            serverSocket = new ServerSocket(7777);
            System.out.println("서버가 준비 되었습니다.");
            //클라이언트의 접속요구를 대기하고 받아들인다.
            socket = serverSocket.accept();

            //센더, 리시버 객체를 생성한다.
            Sender sender = new Sender(socket,name);
            Receive receive = new Receive(socket);

            sender.start();
            receive.start();
        }catch(IOException ie){
            ie.printStackTrace();
        }
    }
}

//아웃풋 스트림으로 송신을 컨트롤 하기 위한 클래스
class Sender extends Thread{
    //멤버
    Socket socket;
    String name;
    DataOutputStream dos;

    //생성자
    Sender(Socket socket, String name) {
        //socket과 name을 set한다.
        this.socket = socket;
        this.name = name;

        try {
            //소켓에서 아웃풋 스트림을 받아온다.
            this.dos = new DataOutputStream(socket.getOutputStream());
        }catch(IOException ie){
            ie.printStackTrace();
        }
    }

    @Override
    public void run(){
        Scanner scanner = new Scanner(System.in);
        //반복해서 스캐너를 입력받아 문자열 베이스의 출력 스트림을 적어넣는다.
        while (dos != null){
            try {
                String chat = name + " : ";
                chat += scanner.nextLine();
                dos.writeUTF(chat);
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }
}

class Receive extends Thread{
    //멤버
    Socket socket;
    DataInputStream dis;

    //생성자
    Receive(Socket socket)  {
        //소켓을 Set한다.
        this.socket = socket;
        try{
            dis = new DataInputStream(socket.getInputStream());
        }catch(IOException ie){
            ie.printStackTrace();
        }
    }

    @Override
    public void run() {
        while(dis != null){
            try {
                System.out.println(dis.readUTF());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

출력결과

유저명을 입력해 주세요.인삼주

서버가 준비 되었습니다.

산삼주 : ㅎㅇ

안녕

산삼주 : 머해?

운동

2)클라이언트

package javasStandard.Network.organaize;
import java.net.*;
import java.io.*;
import java.util.Scanner;

public class TcpIpThreadClient {
    public static void main(String[] args){
    //멤버
    String name;
    Socket socket;

        try {
            //이름을 입력받는다.
            //대화에 사용할 유저명을 입력받는다.
            Scanner scanner = new Scanner(System.in);
            System.out.print("유저명을 입력해 주세요.");
            name= scanner.nextLine();

            //로컬서버IP를 획득한다
            String serverIp = InetAddress.getLocalHost().getHostAddress();
            socket = new Socket(serverIp,7777);
            System.out.println("서버에 연결되었습니다.");

            //센더, 리시브 객체 생성
            Sender sender = new Sender(socket, name);
            Receive receive = new Receive(socket);

            sender.start();
            receive.start();

        }catch(UnknownHostException uhe){
            uhe.printStackTrace();
        } catch (IOException ie) {
            ie.printStackTrace();
        }
    }
}

출력결과

유저명을 입력해 주세요.산삼주

서버에 연결되었습니다.

ㅎㅇ

인삼주 : 안녕

머해?

인삼주 : 운동

Tcp통신은 데이터를 보내기 전에 여러번 확인을 해야 하기때문에, 일반 데이터 전송에는 적합하지만, 동영상 등의 일부 데이터가 유실되더라도 속도가 중요시되는 분야에서는 적합하지 않다. 그럴때 사용되는게 Utp 통신이다. 아래는 Utp통신 프로그래밍의 예이다.

3.Utp통신 프로그램
1)서버

package javasStandard.Network.organaize;

import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.text.SimpleDateFormat;

public class UdpServer {
    public static void main(String[] args) throws IOException, SocketException {
        //멤버
        //7777번 포트를 사용하는 소캣 생성
        DatagramSocket socket = new DatagramSocket(7777);
        DatagramPacket inPacket, outPacket;

        byte[] inMsg = new byte[10];
        byte[] outMsg;

        while(true){
            //데이터 수신을 위한 패킷 생성
            inPacket = new DatagramPacket(inMsg, inMsg.length);
            //소켓을 통해 데이터를 수신한다.
            socket.receive(inPacket);
            //수신한 패킷에서 Ip주소와 포트를 습득한다.
            InetAddress address = inPacket.getAddress();
            int port = inPacket.getPort();

            //서버 현재 시간을 시분초 형태로 담는다.
            String time = new SimpleDateFormat("[hh:mm:ss]").format(new Date());
            //현재시간을 바이트로 변환해서 outMsg에 담는다.
            outMsg = time.getBytes();

            //패킷을 생성해서 클라이언트에 전송한다.
            outPacket = new DatagramPacket(outMsg,outMsg.length,address,port);
            socket.send(outPacket);


        }

    }
}

2)클라이언트

package javasStandard.Network.organaize;
import java.net.*;
import java.io.*;

public class UdpClient {
    public static void main(String[]args) throws IOException {
        //데이터그램 소캣을 생성한다.
        //UDP데이터 그램은 UDP헤더가 붙은 데이터를 의미한다.
        DatagramSocket ds = new DatagramSocket();
        //로컬의 서버어드레스를 획득한다.
        String serverAddress = InetAddress.getLocalHost().getHostAddress();

        //데이터가 저장될 공간으로 byte배열을 생성한다.
        byte[] msg = new byte[100];

        //데이터그램의 패킷을 생성한다.
        //패킷이란 네트워크를 통해 전송되는 데이터의 작은 조각
        //길이가 1인 패키지를 로컬호스트의 7777번 포트로 송신하기 위한 데이터그램 패킷을 작성한다.
        DatagramPacket outPacket = new DatagramPacket(msg,1, InetAddress.getByName(serverAddress),7777);
        //길이가 1인 패키지를 수신하기 위한 데이터그램 패킷을 작성한다.
        DatagramPacket inPacket = new DatagramPacket(msg, msg.length);

        //데이터 그램 소켓에 아웃 패킷 송신
        ds.send(outPacket);
        //데이터 그램 소켓에 인 패킷 수신
        ds.receive(inPacket);

        //inPacket에서 획득한 서버타임 출력
        System.out.println("current server time"+(new String(inPacket.getData())).trim());

        //데이터 소켓 클로즈
        ds.close();


    }
}

출력결과

current server time[07:24:12]

이상 Tcp, Udp 통신 프로그램에 대한 요약을 마친다.

profile
일신일우신

0개의 댓글