728x90
네트워크
- 네트워크 : 여러 컴퓨터들을 통신 회선으로 연결한 것
- LAN(Local Area Network) : 가정, 회사, 건물, 특정영역에 존재하는 컴퓨터 들을 연결 하는것,
- 근거리 통신 : 스위치, 게이트웨이, 모뎀, 허브, NIC(LAN카드), 브리지
- WAN(Wild Area Network) : LAN을 연결한 것 = 인터넷
- 장거리 통신 : 라우터

PC에 네트워크 설정
- IP : pc의 네트워크 연결을 위한 고유 주소
- 사설 IP : 공유기에서 내부적으로 쓰이는 IP
- ex) 192.168.x.x
- 172.16.x.x
- 10.x.x.x
- 공인 IP : 실질적인 통신을 위한 IP : 인터넷 연결
- PC: 사설IP -> 내부 통신간에 사설 IP로 통신, 외부(인터넷)통신 할때는 사설 IP -> 공인 IP로 변환시켜 통신
- Subnet Mask : 네트워크 영역 확인
- IP주소에 subnet mask 값을 씌우면 (네트워크 영역 주소) : 네트워크 공유를 할수있는 영역
- 네트워크 영역 : 내부 통신할 그룹.
- Subnet Mask : 네트워크 영역 확인
- PC: 사설IP -> 내부 통신간에 사설 IP로 통신, 외부(인터넷)통신 할때는 사설 IP -> 공인 IP로 변환시켜 통신
- 사설 IP : 공유기에서 내부적으로 쓰이는 IP
- GateWay : 라우터 장비가 PC로 연결된 인터페이스의 IP 주소
- 모든 PC는 라우터 장비를 통해서 나갑니다.(Gate Way)
- DNS(Domain Name Service) : 도메인(영문)주소를 공인 IP로 변환시켜 주는 서비스
- KT : 168.126.63.1
- 구글 : 8.8.8.8
서버와 클라이언트
- 서버 : 서비스를 제공하는 프로그램
- 웹서버, DBMS, FTP서버
- 클라이언트 : 서비스를 요청하는 프로그램
- 먼저 클라이언트가 서비스를 요청하고, 서버는 처리 결과를 응답으로 제공합니다.

IP주소
- IP주소 : 네트워크 어댑터 (LAN카드) 마다 할당 되는 컴퓨터의 고유한 주소
- IP(Internet Protocol) : 인터넷 규약. 형식.
- IPv4 : 32bit 크기를 가지고 4개부분(옥텟)으로 8bit(0~255) 씩 나누어 사용
- 192.168.1.1
- 256.270.109.101 ← 입력 불가 범위값.
- 232 : 1억
- IPv6 : 128bit 크기를 16진수로 8개 부분 : 16bit : 16진수 : 4개로 사용
- IPv4 : 32bit 크기를 가지고 4개부분(옥텟)으로 8bit(0~255) 씩 나누어 사용
- IP(Internet Protocol) : 인터넷 규약. 형식.
- ipconfig(윈도우), ifconfig(맥os) 명령어로 네트워크 어댑터에 어떤 IP주소가 부여되어 있는지 확인
- 프로그램은 DNS를 이용해서 컴퓨터의 IP 주소를 검색합니다.
- netstat : 네트워크 서비스 상태 보기, port 확

Port 번호
- 운영체제가 관리하는 서버 프로그램의 연결 번호.
- 서버 시작시 특정 port 번호에 바인딩(프로그램에 사용된 구성 요소의 실제 값 또는 프로퍼티를 결정짓는 행위) 됩니다.


IP주소 얻기
InetAddress
- 자바는 IP주소를 java.net 패키지의 InetAddress로 표현합니다.
- 로컬 컴퓨터의 InetAddress를 얻으려면 InetAddress.getLocalHost() 메소드를 호출합니다.
InetAddress ia = InetAddress.getLocalHost();
- getByName() 메소드는 DNS에서 도메인 이름으로 등록된 단 하나의 IP주소를 가져오고, getAllByName() 메소드는 등록된 모든 IP주소를 배열로 가져옵니다.
- InetAddress 객체에서 IP주소를 얻으려면 getHostAddress() 메소드를 호출합니다.
String ip = InetAddress.getHostAddress();
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressExam {
public static void main(String[] args) {
try {
InetAddress local = InetAddress.getLocalHost(); // 로컬 PC IP 주소 확인
System.out.println("내 컴퓨터 IP 주소 : " + local.getHostAddress());
// getAllByName : 도메인 주소를 활용해서 ip 주소 추출
// 여러 IP 주소가 있을 경우가 있어 배열로 저장합니다.
InetAddress[] iaArr = InetAddress.getAllByName("www.naver.com");
for(InetAddress remote : iaArr) {
System.out.println("www.naver.com IP 주소 : " + remote.getHostAddress());
}
}catch(UnknownHostException e) {
e.printStackTrace();
}
}
}
결과 :
내 컴퓨터 IP 주소 : 172.20.10.17
www.naver.com IP 주소 : 223.130.200.104
www.naver.com IP 주소 : 223.130.195.95
TCP
- TCP(Transmission Control Protocol) : 신뢰성 있는 통신
- 신뢰성 : 데이터를 주고 받을때 확인 과정. (패킷 전달간 중간중간 확인)
- 패킷의 손실을 확인하므로 속도가 조금 느립니다.
- 데이터를 정확하게 주고받거나 파일을 주고받을때 사용합니다.
- UDP(User Datagram Protocol) : 비신뢰성 통신
- 신뢰성 없는 : 데이터를 그냥 뿌려주고 상대방이 잘 받았는지 확인 안함.
- 중간확인이 없어 속도가 빠릅니다.
- dhcp 서버 : ip할당
- 전화, 동영상 스트리밍에 사용합니다.
TCP
- TCP는 연결형 프로토콜로, 상대방이 연결된 상태에서 데이터를 주고받는 전송용 프로토콜입니다.
- 클라이언트가 연결 요청을 하고 서버가 연결을 수락하면 통신회선이 고정되고, 데이터는 고정회선을 통해 전달됩니다.
- TCP는 보낸 데이터가 순서대로 전달되며 손실이 발생하지 않습니다.
- ServerSocket은 클라이언트의 연결을 수락하는 서버 쪽 클래스이고, Socket은 클라이언트에서 연결 요청할 때와 클라이언트와 서버 양쪽에서 데이터를 주고 받을때 사용되는 클래스 입니다.

- 세그먼트(segment) : TCP 단위에서 전송되는 데이터의 단위입니다.
- 패킷(packet : pack + bucket) : IP단위에서 호칭되는 데이터의 단위입니다.
- TCP서버 프로그램을 개발하려면 우선 ServerSocket 객체를 생성합니다.
ServerSocket serverSocket = new ServerSocket(50001);
- 기본 생성자로 객체를 생성하고 Port바인딩을 위해 bind() 메소드를 호출해서 ServerSocket 객체를 생성합니다.
ServerSocket serverSocket = new SeverSocket();
serverSocket.bind(new InetSocketAddress(50001));
- 여러개의 IP가 할당된 서버 컴퓨터에서 특정 IP에서만 서비스를 하려면 InetSocketAddress의 첫번째 매개값으로 해당 IP를 줍니다.
ServerSocket = serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress("xxx.xxx.xxx.xxx", 500001));
- Port가 이미 다른 프로그램에서 사용 중이라면 BindException이 발생합니다.
- 따라서 다른 Port로 바인딩 하거나 Port를 사용중인 프로그램을 종료하고 다시 실행해야 합니다.
- ServerSocket이 생성되면 연결 요청을 수락을 위해 accept() 메소드를 실행합니다.
- accept()는 클라이언트가 연결 요청하기 전 까지 블로킹(실행 멈춘상태)하고, 클라이언트의 연결 요청이 들어오면 블로킹이 해제되고 통신용 Socket을 리턴합니다.
Socket socket = serverSocket.accept();
- 리턴된 Socket을 통해 연결된 클라이언트의 IP 주소와 Port 번호를 얻으려면 getRemoteSocketAddress() 메소드를 호출해서 InetSocketAddress를 얻은 다음 getHostName()과 getPost()메소드를 호출 합니다.
InetSocketAddress isa = (InetSocketAddress) socket.getRemote.SocketAddress();
String clientIp = isa.getHostName();
String portNo = isa.getPort();
- ServerSocket의 close() 메소드를 호출해서 Port 번호를 언바인딩 해야 서버가 종료됩니다.
serverSocket.close();
TCP 서버 생성하는 소스코드
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class ServerExam {
private static ServerSocket serverSocket = null;
public static void main(String[] args) {
System.out.println("----------------------------------------------");
System.out.println("서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력 하세요.");
System.out.println("----------------------------------------------");
//서버 소켓을 시작.
startServer();
//키보드 입력
Scanner sc = new Scanner(System.in);
while(true) {
String key = sc.nextLine();
//입력 문자를 소문자로 변환후 q 인지 확인후 맞을때 while문 종료
if(key.toLowerCase().equals("q")) {
break;
}
}
sc.close();
//서버 소켓 닫기
stopServer();
}
public static void startServer() {
//작업 스레드 정의
Thread thread = new Thread() {
@Override
public void run() {
try {
//ServerSocket 생성 및 Port 바인딩
serverSocket = new ServerSocket(50001);
System.out.println("[서버] 시작됨");
while(true) {
System.out.println("\n[서버] 연결 요청을 기다림\n");
// 클라이언트가 접속시 서버와 연결 통로 하나 생성
Socket socket = serverSocket.accept();
// 연결된 클라이언트 정보 확인
InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
System.out.println("[서버] " + isa.getHostName() + "의 연결 요청을 수락함");
//연결 끊기
socket.close();
System.out.println("[서버] " + isa.getHostName() + "의 연결을 끊음");
}
}catch (IOException e) {
System.out.println("[서버] " + e.getMessage());
}
}
};
// 스레드 시작
thread.start();
}
public static void stopServer() {
try {
//ServerSocket을 닫고 Port 언바인딩
serverSocket.close();
System.out.println("[서버] 종료됨");
}catch (IOException e1) {
}
}
}
결과 :
----------------------------------------------
서버를 종료하려면 q 또는 Q를 입력하고 Enter 키를 입력 하세요.
----------------------------------------------
[서버] 시작됨
[서버] 연결 요청을 기다림
yes
q
[서버] 종료됨
[서버] socket closed
TCP 클라이언트
- 클라이언트가 서버에 연결 요청을 하려면 Socket 객체를 생성할 때 생성자 매개값으로 서버 IP주소와 Port 번호를 제공합니다.
- 로컬 컴퓨터에서 실행하는 서버로 연결 요청을 할 경우에는 IP주소 대신 localhost를 사용 가능합니다.
Socket socket = new Socket("IP", 500001);
- 도메인 이름을 사용하려면 DNS에서 IP주소를 검색하는 생성자 매개값으로 InetSocketAddress를 제공합니다.
Socket socket = new Socket(new InetSocketAddress("domainName", 50001);
- 기본 생성자로 Socket을 생성한 후 connect() 메소드로 연결 요청이 가능합니다.
socket = new Socket();
socket.connect(new InetSocketAddress("domainName", 500001));
TCP 클라이언트 생성하는 소스코드
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class ClientExam {
public static void main(String[] args) {
try {
//Socket 생성과 동시에 localhost의 500001 Port로 연결 요청;
Socket socket = new Socket("localhost", 50001);
System.out.println("[클라이언트] 연결 성공");
socket.close();
System.out.println("[클라이언트] 연결 끊음");
}catch(UnknownHostException e) {
}catch(IOException e) {
}
}
}
결과 :
[클라이언트] 연결 성공
[클라이언트] 연결 끊음
입출력 스트림으로 데이터 주고받기
- 클라이언트가 연결 요청(connect())을 하고 서버가 연결 수락(accept())했다면, 양쪽의 Socket객체로부터 각각 InputStream과 OutputStream을 얻을 수 있습니다.


- 상대방에게 데이터를 보낼 때에는 보낼 데이터를 byte[] 배열로 생성하고, 이것을 매개값으로 해서 OutputStream의 write() 메소드를 호출합니다.
- 문자열을 좀 더 간편하게 보내고 싶다면 보조 스트림인 DataOutputStream을 연결해서 사용합니다.
String data = " 보낼 데이터 ";
byte[] bytes = data.getBytes("UTF-8");
OutputStream os = socket.getOutputStream();
os.write(bytes);
os.flush();
// DataOutputStream을 사용하여 문자열을 간편하게 보내기
String data = "보낼 데이터";
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(data);
dos.flush();
- 데이터를 받기 위해서는 받은 데이터를 저장할 byte[] 배열을 하나 생성하고, 이것을 매개값으로 해서 InputStream의 read() 메소드를 호출 해야 합니다.
- read() 메소드는 읽은 데이터를 byte[] 배열에 저장하고 읽은 바이트 수를 리턴합니다.
- 문자열을 좀 더 간편하게 받고 싶다면 보조 스트림인 DataInputStream을 연결해서 사용
byte[] bytes = new byte[1024];
InputStream is = socket.getInputStream();
int num = is.read(bytes);
String data = new String(bytes, 0, num, "UTF-8");
DataInputStream dis = new DataInputStream(socket.getInputStream());
String data = dis.readUTF();
TCP 클라이언트가 보낸 메시지를 다시 돌려 보내는 에코 TCP 서버를 구현한 예제
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class EchoServer {
private static ServerSocket serverSocket = null;
public static void main(String[] args) {
System.out.println("------------------------------------------");
System.out.println("서버를 종료하려면 q를 입력하고 Enter 키를 입력 하세요.");
System.out.println("------------------------------------------");
//TCP 서버 시작
startServer();
//키보드 입력
Scanner sc = new Scanner(System.in);
while(true) {
String key = sc.nextLine();
if(key.toLowerCase().equals("q")) {
break;
}
}
sc.close();
stopServer();
}
public static void startServer() {
//작업 스레드 정의
Thread thread = new Thread() {
@Override
public void run() {
try {
//ServerSocket 생성 및 Port 바인딩
serverSocket = new ServerSocket(50001);
System.out.println("[서버] 시작됨");
while(true) {
System.out.println("\n[서버] 연결 요청을 기다림\n");
//연결수락
Socket socket = serverSocket.accept();
//연결된 클라이언트 정보 얻기
InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
System.out.println("[서버] " + isa.getHostName() + "의 연결 요청을 수락함");
// InputStream is = socket.getInputStream();
// byte[] bytes = new byte[1024];
// int readByteCount = is.read(bytes);
// String message = new String(bytes, 0, readByteCount, "UTF-8");
//
// OutputStream os = socket.getOutputStream();
// bytes = message.getBytes("UTF-8");
// os.write(bytes);
// os.flush();
// System.out.println("[서버] 받은 데이터를 다시 보냄: " + message);
DataInputStream dis = new DataInputStream(socket.getInputStream());
String message = dis.readUTF();
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.flush();
System.out.println("[서버] 받은 데이터를 다시 보냄: " + message);
//연결 끊기
socket.close();
System.out.println("[서버] " + isa.getHostName() + "의 연결을 끊음");
}
}catch (IOException e) {
System.out.println("[서버] " + e.getMessage());
}
}
};
//스레드 시작
thread.start();
}
public static void stopServer() {
try {
//ServerSocket을 닫고 port 언바인딩
serverSocket.close();
System.out.println("[서버] 종료됨");
}catch(IOException e) {}
}
}
결과 :
------------------------------------------
서버를 종료하려면 q를 입력하고 Enter 키를 입력 하세요.
------------------------------------------
[서버] 시작됨
[서버] 연결 요청을 기다림
TCP클라이언트 소스코드 구현
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class EchoClient {
public static void main(String[] args) {
try {
//Socket 생성과 동시에 localhost의 50001 포트로 연결 요청;
Socket socket = new Socket("172.20.10.18", 50001);
System.out.println("[클라이언트] 연결 성공");
// //데이터 보내기
// String sendMessage = "나는 자바가 좋...ㅇ....";
// OutputStream os =socket.getOutputStream();
// byte[] bytes = sendMessage.getBytes("UTF-8");
// os.write(bytes);
// os.flush();
// System.out.println("[클라이언트] 데이터 보냄: " + sendMessage);
//
// //데이터 받기
// InputStream is = socket.getInputStream();
// bytes = new byte[1024];
// int readByteCount = is.read(bytes);
// String receiveMessage = new String(bytes, 0, readByteCount, "UTF-8");
// System.out.println("[클라이언트] 데이터 받음 : " + receiveMessage);
String sendMessage = "행배야 오늘 날씨 직인다~!";
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(sendMessage);
dos.flush();
System.out.println("[클라이언트] 데이터 보냄 : " + sendMessage);
//데이터 받기
DataInputStream dis = new DataInputStream(socket.getInputStream());
String reciveMessage = dis.readUTF();
System.out.println("[클라이언트] 데이터 받음: " + reciveMessage);
//연결 끊기
socket.close();
System.out.println("[클라이언트] 연결 끊음");
}catch(Exception e) {
}
}
}
결과:
[클라이언트] 연결 성공
[클라이언트] 데이터 보냄 : 행배야 오늘 날씨 직인다~!
[클라이언트] 데이터 받음: 행배야 오늘 날씨 직인다~!
[클라이언트] 연결 끊음
UDP
- 발신자가 일방적으로 수신자에게 데이터를 보내는 방식입니다.
- TCP 처럼 연결 요청 및 수락 과정이 없기 때문에 TCP보다 데이터 전송 속도가 상대적으로 빠릅니다.
- 데이터전달의 신뢰성보다 속도가 주용하다면 UDP를 사용하고, 데이터 전달의 신뢰성이 중요 하다면 TCP를 사용합니다.
- DatagramSocket은 발신점과 수신점에 해당하고 DatagramPacket은 주고 받는 데이터에 해당합니다.

UDP 서버
- DatagramSocket 객체를 생성 할 때에는 다음과 같이 바인딩할 Port번호를 생성자 매개값으로 제공합니다.

- receive() 메소드는 데이터를 수신할 때 까지 블로킹되고, 데이터가 수신되면 매개값으로 주어진 DatagramPacket에 저장합니다.

- DatagramPacket 생성자의 첫 번째 매개값은 수신된 데이터를 저장할 배열이고 두 번째 매개값은 수신할 수 있는 최대 바이트 수입니다.

- getSocketAddress() 메소드를 호출하면 정보가 담긴 SocektAddress 객체를 얻을 수 있습니다.

- SocketAddress 객체는 클라이언트로 보낼 DatagramPacket을 생성할 때 네번째 매개값으로 사용 합니다.

- DatagramPacket을 클라이언트로 보낼 때는 DatagramSocket의 send()메소드를 이용합니다.

- UDP 서버를 종료하고 싶을 경우에는 DatagramSocket의 close() 메소드를 호출합니다.

UDP 클라이언트가 구독하고 싶은 뉴스 10개를 전송하는 UDP 서버 구현예제
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.util.Scanner;
public class NewsServer {
private static DatagramSocket datagramSocket = null;
public static void main(String[] args) {
System.out.println("-----------------------------------------");
System.out.println("서버를 종료하려면 q를 입력하고 Enter키를 입력 하세요.");
System.out.println("-----------------------------------------");
//UDP 서버 시작
startServer();
Scanner sc = new Scanner(System.in);
while(true) {
String key = sc.nextLine();
if(key.toLowerCase().equals("q")) {
break;
}
}
sc.close();
//UDP 서버 종료
stopServer();
}
public static void startServer() {
// 작업 스레드 정의
Thread thread = new Thread() {
@Override
public void run() {
try {
datagramSocket = new DatagramSocket(50001);
System.out.println("[서버] 시작됨");
while(true) {
// 클라이언트에서 보내는 데이터를 받을 DatagramPacket을 생성
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
//클라이언트로부터 데이터를 받으면 활성화가 됩니다.
//receive : 대기상태 -> 데이터받음 -> 활성화
datagramSocket.receive(receivePacket);
//클라이언트가 보낸 데이터를 스트링 형태로 변환
String newsKind = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
//클라이언트의 IP와 port 얻기
SocketAddress socketAddress = receivePacket.getSocketAddress();
//10개의 뉴스를 클라이언트로 전송
for(int i = 0; i<=10; i++) {
String data = newsKind + ": 뉴스" + i;
byte[] bytes = data.getBytes("UTF-8");
DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length, socketAddress);
datagramSocket.send(sendPacket);
}
}
} catch (Exception e) {
System.out.println("[서버] " + e.getMessage());
}
}
};
//스레드 시작
thread.start();
}
public static void stopServer() {
//DatagramSocket을 닫고 Port 언바인딩
datagramSocket.close();
System.out.println("[서버] 종료됨");
}
}
결과:
-----------------------------------------
서버를 종료하려면 q를 입력하고 Enter키를 입력 하세요.
-----------------------------------------
[서버] 시작됨
UDP 클라이언트
- 서버에 요청내용을 보내고 그결과를 받는 역할입니다.
- UDP 클라이언트를 위한 DatagramSocket 객체는 기본 생성자로 생성하고, Port번호는 자동으로 부여합니다.

- 생성된 DatagramPacket을 매개값으로 해서 DatagramSocket의 send() 메소드를 호출하면 UDP 서버로 DatagramPacket()이 전송됩니다.

- DatagramSocket을 닫으려면 close() 메소드를 호출합니다.

NewsServer로 구독하고 싶은 뉴스 주제를 보내고 관련 뉴스 10개를 받는 UDP 클라이언트 구현
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class NewsClient {
public static void main(String[] args) {
try {
//datagramsocket 생성
DatagramSocket datagramSocket = new DatagramSocket();
//구독하고 싶은 뉴스 주제 보내기
String data = "정치";
byte[] bytes = data.getBytes("UTF-8");
DatagramPacket sendPacket =
new DatagramPacket(bytes, bytes.length, new InetSocketAddress("172.20.10.18", 50001));
datagramSocket.send(sendPacket);
while(true) {
//뉴스 받기
DatagramPacket receivePacket = new DatagramPacket(new byte[1024], 1024);
datagramSocket.receive(receivePacket);
//문자열로 변환
String news = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
System.out.println(news);
if(news.contains("뉴스10")) {
break;
}
}
datagramSocket.close();
}catch(Exception e) {
}
}
}
결과:
정치: 뉴스1
정치: 뉴스2
정치: 뉴스3
정치: 뉴스4
정치: 뉴스5
//해당 서버에서 5개만 출력되도록 만들어서 5개만 출력됩니다.
728x90
'JAVA > Java 기초' 카테고리의 다른 글
| JSON 데이터형식.java (0) | 2023.02.01 |
|---|---|
| 서버의 동시 요청 처리.java (0) | 2023.02.01 |
| 기본 타입 스트림.java (0) | 2023.01.31 |
| 요소 커스텀 집계.java (0) | 2023.01.30 |
| 입출력 스트림-2.java (0) | 2023.01.30 |