자바의 정석, 드디어 막단원!!
(완전 인터넷 프로토콜 관련 내용이 많아서 작년 강노 참고해서 적어보는 것두 좋을듯!)
= 두 대 이상의 컴퓨터를 케이블로 연결하여 네트워크를 구성하는 것
컴퓨터간의 관계를 역할
로 구분하는 두 개념
서버
클라이언트
[아래는 클라이언트와 서버를 연결하는 두 가지 방식]
서버기반 모델
: 전용서버를 두는 것P2P 모델
: 전용서버 없이 각 클라이언트가 서버 역할까지 동시에 수행= 서버와 이어진 모든 기기와 단말기에서 이용하는 웹에 접근하는 소프트웨어
= 서비스를 제공하는 컴퓨터
= 컴퓨터를 구별하는데 사용되는 고유한 주소값
&
연산하면 네트워크 주소를 얻음**서브넷 마스크: 클래스리스 기반 IP 주소에서 네트워크 주소와 호스트 주소를 구분하기 위한 구분자
= IP주소를 다루기 위한 클래스
(IP 주소는 IP로 사용되는 32bit 또는 128bit의 부호 없음의 숫자로 UDP나 TCP 등의 프로토콜이 구축되는 하위 레벨 프로토콜)
getAddress()
= IP주소를 byte 배열로 반환getAllByName(String host)
getByAddress(byte[] addr)
getByName(String host)
getCanonicalHostName()
isMulticastAddress()
= 인터넷에 존재하는 서버들의 자원에 접근할 수 있는 주소
ex.
http://www.javachobo.com:80/sample/hello.html?referer=javachobo#index1
1. 프로토콜: http
2. 호스트명: www.javachobo.com
3. 포트번호: 80
4. 경로명: /sample/
5. 파일명: hello.html
6. 쿼리: refer=javachobo
7. 참조: index1
= 어플리케이션과 URL 간의 통신 연결을 위한 추상클래스 (최상위 클래스)
= 소켓을 이용한 통신 프로그래밍
** 소켓 = 프로세스 간의 통신을 위해 사용되는 endpoint
OSI 7계층 중 전송 계층에 해당
연결 후 통신이 이뤄짐(전화기)
1:1 통신
데이터의 경계를 구분하기 X
신뢰성 있는 데이터를 전송(순서 보장, 수신 여부 확인)
그래서 UDP보다 전송속도가 느림
ex.
Socket
클래스: 프로세스 간의 통신 담당, 두 스트림을 통해 프로세스 간의 입출력이 이뤄짐
ServerSocket
클래스: 포트와 연결되어 외부의 연결요청을 기다리다 들어오면 Socet을 생성해 둘 사이의 통신이 이뤄지도록 함
ServerSocket
)을 사용해 서버 컴퓨터의 특정 포트에서 클라이언트의 연결 요청 처리 준비를 함간단한 하나의 예시 코드를 보자.
import java.net.*;
import java.io.*;
import java.util.Date;
import java.text.SimpleDateFormat;
public class TcpIpServer {
public static void main(String[] args) {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(7777);
System.out.println(getTime()+"서버가 준비되었습니다.");
} catch(IOException e) {
e.printStackTrace();
}
while(true) {
try {
System.out.println(getTime()+"연결요청을 기다립니다.");
Socket socket = serverSocket.accept();
System.out.println(getTime()+socket.getInetAddress()+"로부터 연결요청이 들어왔습니다.");
//소켓의 출력 스트림을 얻음
OutputStream out = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
//원격 소켓에 데이터를 보냄
dos.writeUTF("[Notice] Test Message1 from Server.");
System.out.println(getTime()+"데이터를 전송했습니다.");
dos.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//아래의 클라이언트는 위의 서버 프로그램을 먼저 실행시킨 뒤 실행해야됨
public class TcpIpClient {
public static void main(String[] args) {
try {
String serverIp = "127.0.0.1";
System.out.println("서버에 연결중입니다. 서버IP:"+serverIp);
Socket socket = new Socket(serverIp, 7777);
InputStream in = socket.getInputStream();
DataInputStream dis = new DataInputStream(in);
System.out.println("서버로부터 받은 메세지:"+dis.readUTF());
System.out.println("연결을 종료합니다.");
dis.close();
socket.close();
System.out.println("연결이 종료되었습니다.");
} catch(ConnectException ce) { //서버와의 연결 실패
ce.printStackTrace();
} catch(IOException ie) {
ie.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
}
이외에도 소켓으로 데이터를 송신하는 작업과 수신한느 작업을 별도의 스레드 Sender, Receiver가 처리하도록 하여 송신과 수신이 동시에 이루어지도록 만들 수 있다.
//서버 클래스!!!
public class TcpIpMultichatServer {
HashMap clients;
//여러개의 client를 HashMap으로 관리!!
TcpIpMultichatServer() {
clients = new HashMap();
Collections.synchronizedMap(clients); //동기화
//클라이언트가 접속을 해제하면 HashMap에서 제거한다
}
public void start() {
ServerSocket serverSocket = null;
Socket socket = null;
try {
serverSocket = new ServerSocket(7777);
System.out.println("서버가 시작되었습니다.");
while(true) {
socket = serverSocket.accept();
System.out.println("["+socket.getInetAddress()+":"+socket.getPort()"+"]"+"에서 접속하였습니다.");
ServerReceiver thread = new ServerReciever(socket);
thread.start();
}
} catch(Exception e) {
e.printStackTrace();
}
}
void sendToAll(String msg) {
Iterator it = clients.keySet().iterator();
// 클라이언트가 추가될 때마다 생성되며 클라이언트의 입력을 서버에 접속된 모든 클라이언트에게 전송
while(it.hasNext()) {
try {
DataOutputStream out = (DataOutputStream) clients.get(it.next());
out.writeUTF(msg);
} catch(IOException e) {}
}
}
public static void main(String args[]) {
new TcpIpMultichatServer().start();
}
}
//클라이언트 클래스
pulic class TcpIpMultichatClient {
public static void main(String[] args) {
if(args.length != 1) {
System.out.println("USAGE: java TcpIpMultichatClient 대화명");
System.exit(0);
}
try {
String serverIp = "127.0.0.1";
Socket socket = new Socket(serverIp, 7777);
System.out.prinlnt("서버에 연결되었습니다.");
Thread sender = new Thread(new ClientSender(socket, args[0]));
Thread receiver = new Thread(new ClientReceiver(socket));
sender.start();
receiver.start();
} catch(ConnectException ce) {
ce.printStackTrace();
} catch(Exception e) {}
}
}
static class ClientSender extends Thread {
Socket socket;
DataOutputStream out;
String name;
ClientSender(Socket socket, String name) {
this.socket = socket;
try {
out = new DataOutputStream(socket.getOutputStream());
this.name = name;
} catch(Exception e) {}
}
public void run() {
Scanner scanner = new Scanner(System.in);
try {
if(out != null) {
out.writeUTF(name);
}
while(out != null) {
out.writeUTF("["+name+"]"+scanner.nextLine());
}
} catch(IOException e) {}
}
}
static class ClientReceiver extends Thread {
Socket socket;
DataInputStream in;
ClientReceiver(Socket socket) {
this.socket = socket;
try {
in = new DataInputStream(socket.getInputStream());
} catch (IOException e) {}
}
public void run() {
while(int != null) {
try {
System.out.println(in.readUTF());
} catch (IOException e) {}
}
}
}
연결 없이 통신이 이뤄짐(소포)
1:多, 多:1, 多:多
데이터의 경계 구분 (datagram)
신뢰성 없는 데이터 전송(데이터 수신여부확인 x, 전송순서 바뀔수도)
그래서 TCP 보다 전송 속도가 빠름
ex. DatagramSocket, DatagramPacket(헤더/수신할 호스트의 정보가 저장됨+데이터)
(연결지향적 프로토콜이 아니므로 ServerSocket
이 필요하지 않음)
UDP에서 사용하는 소켓은 DatagramSocket
, 데이터를 DatagramPacket
에 담아서 전송
DatagramPacket
은 헤더와 데이터로 구성돼 있다
헤더: DatagramPacket
을 수신할 호스트의 정보(주소, 포트)가 저장됨
//클라이언트!!
public class UdpClient {
public void start() throws IOException, UnknownHostException {
DatagramSocket datagramSocket = new DatagramSocket();
InetAddress serverAddress = InetAddress.getByName("127.0.0.1");
Byte[] msg = new byte[100];
DatagramPacket outPacket = new DatagramPacket(msg, 1, serverAddress, 7777);
DatagramPacket inPacket = new DatagramPacket(msg, msg.length_;
datagramSocket.send(outPacket);
datagramSocket.receive(inPacket);
System.out.println("current server time: "+new String(inPacket.getData()));
datagramSocket.close();
}
public static void main(String args[]) {
try {
new UdpClient().start();
} catch(Exception e) {
e.printStackTrace();
}
}
}
//서버!!
public class UdpServer {
public void start() throws IOException {
DatagramSocket = new DatagramSocket(7777);
DatagramPacket inPacket, outPacket;
byte[] inMsg = new byte[10];
byte[] outMsg;
while(true) {
inPacket = new DatagramPacket(inMsg, inMsg.length);
socket.receive(inPacket);
InetAddress address = inPacket.getAddress();
int port = inPacket.getPort();
SimpleDateFormat sdf = new SimpleDateFormat("[hh:mm:ss]");
String time = sdf.format(new Date());
outMsg = time.getBytes();
outPacket = new DatagramPacket(outMsg, outMsg.length, address, port);
socket.send(outPacket);
}
}
public static void main(String args[]) {
try {
new UdpServer().start();
} catch(Exception e) {
e.printStackTrace();
}
}
}
자바의 정석, 2nd Edition.
https://tree-19.tistory.com/79