Kosta DevOps 과정 280기/Java
네트워크 프로그램
롯슈83
2024. 6. 4. 10:54
- 서로 떨어져있는 컴퓨터끼리 통신하기 위한 프로그램
- 자바에서는 네트워크 프로그래밍을 위하여 java.net패키지에 관련 인터페이스와 클래스를 제공한다.
- ip Address
- 네트워크 상에 있는 특정한 컴퓨터를 식별하기 위한 주소
- 내 컴퓨터에 있는 IP 주소를 알고싶으면 ipconfig 명령어를 치면 된다.
Microsoft Windows [Version 10.0.19045.4412]
(c) Microsoft Corporation. All rights reserved.
C:\Users\WD>ipconfig
Windows IP 구성
이더넷 어댑터 이더넷:
연결별 DNS 접미사. . . . :
링크-로컬 IPv6 주소 . . . . : fe80::61f9:7774:88ae:34%8
IPv4 주소 . . . . . . . . . : 172.30.1.58
서브넷 마스크 . . . . . . . : 255.255.255.0
기본 게이트웨이 . . . . . . : 172.30.1.254
C:\Users\WD>
- port 번호
- 하나의 컴퓨터에서 여러 개의 네트워크 프로그램이 동시에 실행될 수 있다.
- 특정 프로그램의 식별자의 역할을 해준다.
- 통신하는 방식(서로 데이터를 주고 받는 방식)
- TCP 방식
- 현실 세계의 전화와 비슷하게 통신하는 방식
- 통신을 할 상대방 컴퓨터와 연결이 이루어지고 난 다음에 그 연결된 회선을 통해서 데이터를 주고 받는 방식
- 장점 : 데이터를 잃어버릴 일이 없어서 신뢰성이 높다
- 단점 : 항상 연결되어있어야해서 네트워크 부담이 높다.
- Java가 TCP 방식을 위하여 제공하는 클래스 - ServerSocket, Socket
- UDP 방식
- 현실 세계의 편지와 비슷하게 통신하는 방식
- 통신을 할 상대방컴퓨터와 연결을 맺지 않고 덮어놓고 데이터를 보내는 방식
- 장점 : 네트워크 부담이 낮다
- 단점 : 신뢰성이 떨어진다.
- Java가 UDP 방식을 위하여 제공하는 클래스 - DategramSocket, DategeamPacket
- ping 보내기
C:\Users\WD>ipconfig
Windows IP 구성
이더넷 어댑터 이더넷:
연결별 DNS 접미사. . . . :
링크-로컬 IPv6 주소 . . . . : fe80::61f9:7774:88ae:34%8
IPv4 주소 . . . . . . . . . : 172.30.1.58
서브넷 마스크 . . . . . . . : 255.255.255.0
기본 게이트웨이 . . . . . . : 172.30.1.254
C:\Users\WD>ping 172.30.1.58
Ping 172.30.1.58 32바이트 데이터 사용:
172.30.1.58의 응답: 바이트=32 시간<1ms TTL=128
172.30.1.58의 응답: 바이트=32 시간<1ms TTL=128
172.30.1.58의 응답: 바이트=32 시간<1ms TTL=128
172.30.1.58의 응답: 바이트=32 시간<1ms TTL=128
172.30.1.58에 대한 Ping 통계:
패킷: 보냄 = 4, 받음 = 4, 손실 = 0 (0% 손실),
왕복 시간(밀리초):
최소 = 0ms, 최대 = 0ms, 평균 = 0ms
- URL
- 인터넷 상에 있는 문서를 긁어올 수 있다.
- 소스보기 해서 그 URL 을 복사한다.
- InputStream
- URL 은 서버 컴퓨터 상에서 문서들을 연결 짓는 역할 정도를 한다. 내가 문서를 읽어오기 위해서는 해당 글자들이 순서대로 읽어오게끔 해야한다. 그 역할을 해주는 것이 InputStream 이다.
- read()
- 읽으면 읽은 byte수를 , 다읽으면 -1 을 반환
package com.kosta.exam01;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
public class URLTest {
public static void main(String[] args){
byte []data = new byte[200];
try {
URL url = new URL("https://www.hanbit.co.kr/store/books/new_book_list.html");
InputStream is = url.openStream();
System.out.println(url);
System.out.println(is);
String str = "";
//내용이 너무 많아서 계속 받으라는 신호
while(is.read(data) != -1) {
str += new String(data);
Arrays.fill(data,(byte)0);
}
System.out.println(str);
is.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- Server : 네트워크 상에서 서비스를 제공하는 컴퓨터 혹은 프로그램
- Client : 네트워크 상에서 서비스를 제공받는 컴퓨터 혹은 프로그램
- TCP 방식의 프로그래밍 절차
- 일단 Server 와 Clinent가 있어야 한다. 또한 먼저 연결을 해놓고 그 회선으로 통신을 주고 받는 방식이다.
- Server
- 1. ServerSocket을 생성한다.
- 2. Client의 접속을 무한 대기 상태로 기다린다.
- 4.accept 메소드가 호출되어 통신을 수락한다.(이 때, Socket을 반환한다. 이 소켓을 통해서 Client 소켓과 함께 통신한다)
- Client
- 3. Socket 객체를 생성하여 통신을 요청한다.(상대방 IP 주소와 포트 번호를 통해 접속해야하는데 그것을 소켓을 이용하는 것)
- Server 와 Client
- 5. 각각의 소켓을 통하여 서버와 클라이언트가 각각의 소켓을 통하여 Stream 을 생성한다.
- 6. 그 Stream을 통하여 데이터를 주고 받는다
- 7. 사용했던 자원을 닫아준다.
package com.kosta.tcp01;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer01 {
public static void main(String[] args) {
try {
//여기서의 9001 포트번호로 마음대로 정할 수 있다.
ServerSocket server = new ServerSocket(9001);
//포트번호를 생성하여 통신할 준비를 완료한 것이므로 아래 출력
System.out.println("통신 준비 완료!");
while (true) {
//통신을 받은 순간accept 가 동작되므로
Socket socket = server.accept();
//통신을 수락하면 소켓을 반환하여 Client 소켓과 통신한다.
System.out.println("클라이언트가 연결하였습니다.");
//데이터를 내보내기 위한 스트림으로 소켓을 통해서 Out스트림을 받아오는것
OutputStream os = socket.getOutputStream();
//난수 10개를 클라이언트에 보내는 코드.
for(int i = 0; i < 10; i++) {
int r = (int)(Math.random()* 100);
//하나씩 정수를 차례대로 보내야 하므로 Stream을 이용해야 하므로 os를 이용.
os.write(r);
Thread.sleep(200);//0.2초 대기
}
System.out.println("데이터 전송 완료");
//사용했던 리소스 닫기
os.close();
socket.close();
server.close();
}
} catch (Exception e) {
System.out.println("예외 발생:"+e.getMessage());
}
}
}
package com.kosta.tcp01;
import java.io.InputStream;
import java.net.Socket;
public class TCPClient01 {
public static void main(String[] args) {
try {
//서버컴퓨터의 ip 주소와 약속된 포트번호를 매개변수로 준다.
Socket socket = new Socket("172.30.1.58", 9001);
//데이터를 받기 위한 스트림으로 소켓을 통해서 In스트림을 받아오는것.
InputStream is = socket.getInputStream();
for(int i = 1; i<=10; i++) {
int n = is.read();
System.out.println("서버로부터 수신된 데이터 : "+n);
}
//사용했던 리소스 닫기
is.close();
socket.close();
} catch (Exception e) {
System.out.println("예외 발생 "+e.getMessage());
}
}
}
- UDP 방식의 프로그래밍 절차
- 데이터를 받는 쪽(Receiver)
- 1. DatagramSocket 을 생성
- 2. DatagramPacket 을 생성
- 3. receive를 통해서 데이터를 수신
- 4. 사용했던 자원을 닫아준다.
- 데이터를 보내는 쪽(Sender)
- 1. DatagramScoket 을 생성
- 2. DatagramPacket 을 생성
- 3. send를 통해 데이터를 전송
- 4. 사용했던 자원을 닫아준다.
- 길이 닦여있지 않고, 연결이 되어있지 않다 따라서 packet 안에 포트번호 등이 있어야한다. 그래서 아래의 두 메소드도 packet을 원하는 것이다.
- 데이터를 주고 받는 단위: packet -> 보내려는 데이터 + 목적지의 주소 + 포트 번호 등이 포함됨
- 받는 쪽이 켜져 있지 않아도 데이터가 전송되지만 데이터가 소실된다.
- 데이터를 받는 쪽(Receiver)
void receive(DatagramPacket p)
Receives a datagram packet from this socket.
void send(DatagramPacket p)
Sends a datagram packet from this socket.
- 메아리 프로그램(1: 1 채팅)
package com.kosta.chat01;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
public class TCPChatServer {
public static void main(String[] args) {
//클라이언트로부터 수신된 데이터를 받기 위한 배열을 만든다.
byte []data = new byte[100];
try {
//1. 서버 소켓을 생성한다.
//2. 포트번호 (9003)생성한다.
ServerSocket server = new ServerSocket(9003);
//3. 무한 대기 상태로 클라이언트의 접속을 기다린다.(반복문)
while(true) {
//4. 클라이언트의 접속을 수락한다.
Socket socket = server.accept();
//5. 연결된 클라이언트와 데이터를 주고 받기 위한 입출력 스트림을 생성한다.
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
//6. 연결된 클라이언트와 계속 통신하기 위하여 계속 통신한다.(통신을 위한 반복)
//여러 명이서 통신하려면 Thread를 이용한다.
while(true) {
is.read(data);
os.write(data);
String msg = new String(data);
System.out.println("수신된 데이터 : "+msg);
Arrays.fill(data,(byte)0);
}
}
} catch (Exception e) {
System.out.println("예외 발생 : "+e.getMessage());
}
}
}
package com.kosta.chat01;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class TCPChatClient extends JFrame {
JTextArea jta;
JTextField jtf;
//1. 클라이언트의 멤버변수로 소켓, InputStream, Output Stream을 생성
Socket socket;
InputStream is;
OutputStream os;
TCPChatClient(){
//통신
try {
//1. 서버와 통신하기 위한 소켓을 생성한다.
socket = new Socket("172.30.1.58", 9003);
//2.생성된 소켓을 통해서 Stream을 생성한다.
is = socket.getInputStream();
} catch (Exception e) {
System.out.println("예외 발생 : "+e.getMessage());
}
//GUI
jta = new JTextArea();
jtf = new JTextField(50);
JScrollPane jsp = new JScrollPane(jta);
JButton btnSend = new JButton("전송");
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
p.add(jtf, BorderLayout.CENTER);
p.add(btnSend, BorderLayout.EAST);
add(jsp, BorderLayout.CENTER);
add(p, BorderLayout.SOUTH);
//서버로부터 수신된 데이터를 받기위한 쓰레드를 받는다.
class ClientThread extends Thread{
byte[] data = new byte[200];
@Override
public void run() {
try {
while(true) {
is.read(data);
jta.append(new String(data));
jta.append("\n");
Arrays.fill(data, (byte)0);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
ClientThread ct = new ClientThread();
ct.start();
//전송 버튼 액션
btnSend.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//보낼 데이터를 바이트 형의 배열로 만든다.
try {
//텍스트 필드에 써진 글자를 바이트 배열로 갖고온다.
byte[] data = jtf.getText().getBytes();
//서버로 데이터 보내기
os = socket.getOutputStream();
os.write(data);
} catch (Exception e1) {
System.out.println("예외 발생 : "+e1.getMessage());
}
jtf.setText("");
}
});
setVisible(true);
setSize(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new TCPChatClient();
}
}
- 여러 명의 채팅을 열 수 있도록 하기(에코시스템)
package com.kosta.chat02;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
class ServerThread extends Thread{
//Socket socket;
InputStream is;
OutputStream os;
//클라이언트가 접속을 요청했을 때, 생성한다.
//소켓을 매개변수로 받아 Stream을 생성한다.
public ServerThread(Socket socket) {
//5. 연결된 클라이언트와 데이터를 주고 받기 위한 입출력 스트림을 생성한다.
try {
is = socket.getInputStream();
os = socket.getOutputStream();
} catch (Exception e) {
System.out.println("예외 발생"+e.getMessage());
}
System.out.println("쓰레드 생성");
}
@Override
public void run() {
try {
//클라이언트로부터 수신된 데이터를 받기 위한 배열을 만든다.
byte []data = new byte[100];
//6. 연결된 클라이언트와 계속 통신하기 위하여 계속 통신한다.(통신을 위한 반복)
//여러 명이서 통신하려면 Thread를 이용한다.
while(true) {
is.read(data);
os.write(data);
String msg = new String(data);
System.out.println("수신된 데이터 : "+msg);
Arrays.fill(data,(byte)0);
}
} catch (Exception e) {
System.out.println("예외 발생"+e.getMessage());
}
}
}
public class TCPChatServer {
public static void main(String[] args) {
try {
//1. 서버 소켓을 생성한다.
//2. 포트번호 (9003)생성한다.
ServerSocket server = new ServerSocket(9003);
//3. 무한 대기 상태로 클라이언트의 접속을 기다린다.(반복문)
while(true) {
//4. 클라이언트의 접속을 수락한다.
Socket socket = server.accept();
//연결한 클라이언트를 상대하여 계속 통신할 쓰레드를 생성한다.
if(socket != null) {
ServerThread st = new ServerThread(socket);
//쓰레드를 가동시킨다.
st.start();
}
}
} catch (Exception e) {
System.out.println("예외 발생 : "+e.getMessage());
}
}
}
- 여러 명의 클라이언트에게 방송하기