본문 바로가기
Java 강의

자바 소켓 프로그래밍 / 자바 네트워크 프로그래밍

by 자유코딩 2017. 10. 12.

네트워크의 개요

네트워크는 여러 대의 컴퓨터를 통신회선으로 연결한 것을 말합니다. 만약 여러분의 집에 방마다 컴퓨터가 있고, 이 컴퓨터들을 유선,무선 등의  통신 회선으로 연결했다면 홈네트워크(home network)가 형성된 것입니다. 지역 네트워크는 회사, 건물, 특정 영역에 존재하는 컴퓨터를 통신 회선으로 연결한 것을 말합니다. 인터넷(internet)은 지역 네트워크를 통신 회선으로 연결한 것을 말합니다.

출처 : [책] 이것이 자바다 1052p - 신용권 지음

 

기본적인 네트워크의 개요는 이렇습니다.

그리고 네트워크는 서버와 클라이언트로 구성되어 있습니다.

그림으로 보겠습니다.

 

네트워크는 그림처럼 연결이나 처리를 요청하는 클라이언트와 요청에 응답해서 결과를 보내는 서버로 구성되어 있습니다.

 

클라이언트는 서버에 연결과 처리를 요청합니다.

서버는 클라이언의 요청에 응답해서 결과를 보냅니다.

 

ip 주소와 포트(Port)

ip주소 : 컴퓨터가 네트워크에서 갖는 고유한 주소

포트 : 한 대의 서버 컴퓨터가 가지고 있는 서버 프로그램들에 매겨둔 고유 번호. 이 고유번호를 통해서 요청이 들어왔을때 서버를 선택하고 실행한다.

 

포트

ip번호는 컴퓨터의 주소입니다.

물류배송에 비유하면 서울과 부산의 위치입니다.

그리고 포트는 각 도시에 있는 물건이 저장될 창고 또는 항구 입니다.

가구는 가구를 전문으로 받아주는 항구에 배송되어야 하고 , 식료품은 식료품을 전문으로 받아주는 항구에 배송된다고 해보겠습니다.

 

자바 코드로 ip주소 출력하기

 

프로그램으로 ip 주소를 확인해보겠습니다.

 

소스코드입니다.

1
2
3
4
5
6
7
8
9
package Network;
import java.net.InetAddress;//InetAddress를 import 해줍니다
import java.net.UnknownHostException;//UnknownHostException을 import 해줍니다
public class InetAddressExample {
    public static void main(String[] args) throws UnknownHostException {
        InetAddress local = InetAddress.getLocalHost();//변수 local을 InetAddress.getLocalHost();로 초기화 합니다.
        System.out.println(local.getHostAddress());//local.getHostAddress()로 현재 자신의 컴퓨터의 ip를 알 수 있습니다
    }
}
cs

 

출력화면입니다.

 

이렇게 컴퓨터의 ip를 확인 할 수 있습니다.

InetAddress.getLocalHost();를 사용해서 local에 ip객체를 저장합니다.

local.getHostAddress();를 사용해서 객체에 저장된 컴퓨터의 ip를 출력합니다.

 

UDP 네트워킹

 

UDP = User Datagram Protocol 비연결 지향적 프로토콜

데이터를 주고 받을때 연결 절차를 거치지 않고 발신자가 일방적으로 데이터를 발신하는 방식

연결 절차가 없어서 TCP보다 빠른 전송이 가능합니다.

 

UDP 프로그래밍 - 채팅 프로그램 예제

 

UDP 네트워크 - 채팅 프로그램 코드가 데이터를 수신하는 과정

 

UDP 네트워크 - 채팅 프로그램 코드가 데이터를 송신하는 과정

 

예제 코드입니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
 
/*
 * 송신1 udp 소켓 이용해서 상대방에게 데이터 보내기
 * 수신1 udp 소켓 이용해서 특정 포트로 들어오는 메세지를 수신
 * 
 * 송신2 사용자로부터 입력 받아서 데이터 보내기
 * 송신2를 특정 상황이 올때까지 반복
 * 
 * 수신2 메세지를 반복해서 수신하기
 */
class listen extends Thread{//데이터를 받는쪽
    @Override
    public void run() {
        try {
            DatagramSocket socket = new DatagramSocket(5000);
            //DatagramSocket , DatagramPacket은 자바에서 UDP 통신을 위해서 제공합니다.
            //DatagramPacket 생성 : 데이터를 수신할 그릇이 되는 DatagramPacket 생성
            
            
            while (true) {
                byte[] socketarr= new byte[512];//수신할 데이터가 저장될 빈 바이트 배열 선언
                
                DatagramPacket packet = new DatagramPacket(socketarr, socketarr.length);
                
                socket.receive(packet);
                System.out.println("메세지 받음");
                System.out.println(new String(socketarr));
            
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class send extends Thread{//데이터를 보내는쪽
    @Override
    public void run(){
        
        Scanner input = new Scanner(System.in);
        String msg = "";
        try {
            InetAddress ip = InetAddress.getByName("10.10.10.134");
            DatagramSocket datagramsocket = new DatagramSocket();
            while (true) {
    
                msg = input.next();
                System.out.println("메세지 보냄");
                //getByte 문자열을 바이트 단위로 쪼개서 가지고 있는다
                byte[] send = msg.getBytes("UTF-8");
                
                DatagramPacket packet = new DatagramPacket(send, send.length,ip,5000);
                datagramsocket.send(packet);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
public class UdpChat {
    public static void main(String[] args) {
        listen l1 = new listen();
        send s1 = new send();
        
        l1.start();
        s1.start();
        
    }
}
cs

 

 

 

 

 

TCP 네트워킹

 

TCP의 개요

TCP는 연결지향적 프로토콜 입니다. 연결 지향 프로토콜이란 클라이언트와 서버가 연결된 상태에서 데이터를 주고 받는 프로토콜을 말합니다.

 

클라이언트가 연결 요청을 하고,

서버가 연결을 수락하면 통신 선로가 고정되고,

모든 데이터는 고정된 통신 선로를 통해서 순차적으로 전달된다.

 

그렇기 때문에 TCP는 데이터를 정확하고 안정적으로 전달한다.

TCP의 단점은 데이터를 보내기 전에 반드시 연결이 형성되어야 하고(가장 시간이 많이 걸리는 작업),

고정된 통신 선로가 최단선(네트워크 길이 측면)이 아닐 경우 상대적으로 UDP(User Datagram Protocol)보다 데이터 전송 속도가 느릴 수 있다.

자바는 TCP네트워킹을 위해 java.net.ServerSocket과 java.net.Socket클래스를 제공하고 있습니다.

 

ServerSocket 과 Socket

 

 

이제 이 그림 속의 구조를 자바 코드로 작성해보겠습니다.

 

 

예제 실시간 입출력 프로그램

 

서버 코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package TCPServer;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
 
class TCPServerSenderThread implements Runnable{
    private Socket socket;
    public TCPServerSenderThread(Socket socket) {
        this.socket = socket;
        // TODO Auto-generated constructor stub
    }
    @Override
    public void run() {
        Scanner scan = new Scanner(System.in);
        try {
            while (true) {
                //write함수를 가지고 있는 OutputStream 클래스를 사용할 것이다
                OutputStream out = socket.getOutputStream();
                //메인으로부터 socket을 전달 받았다
                //여기 이 socket에는 포트 5000번이 담겨있다
                out.write(scan.next().getBytes());
                //scan.next();를 가지고 String을 입력한다 그리고 이것을 byte로 변환했다
                //out.write에 이것을 실어서 보냈다
                //out은 지금 socket.getOutputStream();과 이어져있다
                //포트 번호 5000번을 타고 적은 내용을 보낸다                
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}
class TCPServerReceiverThread implements Runnable{
    private Socket socket;
    public TCPServerReceiverThread(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            while (true) {
                //입력을 받아올 읽는 함수 read가 들어있는 InputStream을 사용 할 것이다
                //main함수로부터 받은 socket의 getInputStream();을 활용한다
                //socket.getInputStream();은 InputStream 타입이기 때문에
                //InputStream에 저장된다
                InputStream input = socket.getInputStream();
                //System.out.println()을 사용해서 읽은 내용을 출력한다
                System.out.println(input.read());//input은 socket의 inputStream과 연결되어 있다
                //socket으로부터 들어온 InputStream을 read로 읽어서 
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class TCPServerThread {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(5000);
            //1.서버니까 서버소켓을 일단 만든다
            //이쪽으로 클라이언트가 요청을 보낼것이다
            //통로를 하나 만든다고 생각하면된다
            Socket socket = serverSocket.accept();
            //그리고 serverSocket이라는 그 통로에 통과장치 같은 함수 accept();를 호출한다
            //이 결과를 socket에 저장한다 socket에 실어서 Thread에 보낼 것이다            
 
            Thread thread1 = new Thread(new TCPServerReceiverThread(socket));
            //이 부분이 중요하다
            //지금 이 코드는 메인에서 수행되는 것이 아니라 스레드라는 다른 클래스에서 작업을 수행한다
            //main 함수안에 정의된 socket이라는 변수를 스레드는 모른다
            //그래서 Thread에 socket을 전달한다
            Thread thread2 = new Thread(new TCPServerSenderThread(socket));
            //thread2에도 socket을 전달한다
            thread1.start();
            //thread1을 실행한다
            thread2.start();
            //thread2를 실행한다
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
 
cs

 

 

서버쪽 코드를 조금 더 다시 보겠다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class TCPServerSenderThread implements Runnable{
    private Socket socket;
    public TCPServerSenderThread(Socket socket) {
        this.socket = socket;
        // TODO Auto-generated constructor stub
    }
    @Override
    public void run() {
        Scanner scan = new Scanner(System.in);
        try {
            while (true) {
                socket.getOutputStream().write(scan.next().getBytes());
                //코드의 구조를 보기 위해서 이렇게 작성했다
                //main으로부터 받은 socket의outputStream
                //그리고 outputStream의 write함수에 사용자가 입력한 내용을 적어보낸다
            }
        } catch (Exception e) {
            
        }
    }
}
cs

 

클라이언트 코드

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package TCPServer;
 
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
 
class TCPClientSenderThread implements Runnable{
    private Socket socket;
    public TCPClientSenderThread(Socket socket) {
        this.socket = socket;
    }
    @Override
    public void run() {
        Scanner scan = new Scanner(System.in);
        try {
            while (true) {
                OutputStream out = socket.getOutputStream();
                out.write(scan.next().getBytes());
            }
        } catch (Exception e) {
        }
    }
}
class TCPClientReceiverThread implements Runnable{
    private Socket socket;
    public TCPClientReceiverThread(Socket socket) {
        this.socket = socket;
 
    }
    @Override
    public void run() {
        try {
            while (true) {
                InputStream input = socket.getInputStream();
                System.out.println(input.read());                
            }
        } catch (Exception e) {
        }
    }
}
public class TCPClientThread {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("10.10.10.134"5000);
            //클라이언트측의 소켓을 만든다
            //그리고 이 소켓을 통해서 요청을 보낼곳의 주소와 포트번호를 입력한다
            Thread thread1 = new Thread(new TCPClientReceiverThread(socket));
            //Thread에 socket정보를 전달한다
            Thread thread2 = new Thread(new TCPClientSenderThread(socket));
            //Thread에 socket정보를 전달한다
            thread1.start();
            thread2.start();
        } catch (Exception e) {
        }
    }
}
cs

댓글