JAVA ServerSocket를 활용한 통신
Network
Server
종류
- TCP (Transmission Control Protocol 전송제어규약)
- DB(oracle)
-
Web(tomcat)
-
종단 시스템 : host 라고 하며 네트워크상에서 더이상 연장되지 않은 기기 (PC, smart Phone, scanner, printer)
-
Router(라우터) : host 간의 상호 데이터를 교환할 수 있도록 해주는 장치
-
www : world wide web
URL : Uniform Resource Locator 보통 IP주소로 연결하지만 우리가 보는 웹페이지 주소는 URL로 되어있다.
TCP
- 신사적인 Protocol.
- 전화 -> 상대방 -> 연결 -> 통신
- 동기화 send(보낸다) -> recv(받는다) 처리 순서가 일치해야 한다.
- 데이터의 경계가 없다. Data의 용량의 한계가 없다.
- 1 대 1 통신만 가능.
- 채팅, String통신, Object를 보낼 수 있는 것이 있음
UDP
- 비 연결형 Protocol
- 편지, 지상파방송
- 데이터의 경계가 있다. Data 용량의 한계가 있다.
- 1대 1 (unicast)
- 1대 다수(broadcast)
- 다수 대 다수 (multicast)
7 Layer
1계층 - physical Layer 물리계층
2계층 - DataLink Layer 주소(IP)를 헤더에 첨부
3계층 - Network Layer 네트워크 IP -> address
4계층 - Transport Layer 네크워크 Port
5계층 - Session Layer 저장공간 세션을 동기화
6계층 - Presentation Layer 보안, 압축, 확장
7계층 - Application Layer 프로그램
용어
- Pecket(묶음)
- 제어 정보, 데이터들이 결합된 형태로 전송이 되는 실제의 데이터 IP, Port, String, Dto(Object)
-
IP : Internet Protocol -> address v4 v6 컴퓨터마다의 주소
IPv4 : 0 ~ 255 xxx.xxx.xxx.xxx IPv6 : 0 ~ xxx.xxx.xxx.xxx.xxx.xxx
- Port Number
- 한 IP에서 어떤 프로그램으로 송 수신 해야하는지 구분 짓는 번호
IP 주소는 internet상에 존재하는 host(PC) 를 식별할 수 있으나
최종 주체인 process(프로그램)을 식별하지 못하기 때문에
프로세스를 구별하기 위해서 지정된 수치(0 ~ 1024 : system)제외하고 수치를 지정한다.
- Socket
- 유닉스(File)
send recv 또는 write, read
통신의 주체, 통신을 하기위한 Object
IP, Port, TCP/UDP
- DNS (Domain Name System) Server
- IP -> String (아이티 주소를 문자열로 바꾸어줌) xxx.xxx.xxx.xxx -> www.naver.com
통신 순서
Server Client
1. Socket 버전 확인 1. Socket 버전확인
2. Binding : IP, Port 설정
3. Listen
4. Accept <---- 통신 방향 --- 2. Connect
5. recv(받는다), read <------ 3. send(보내다), write
6. send --------> 4. recv(받는다)
Server String
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Socket cs = null; // 클라이언트 담당 소켓 생성
try {
ServerSocket svs = new ServerSocket(1234); // 서버 소켓 생성
System.out.println("접속 대기중");
cs = svs.accept();
System.out.println("IP:"+ cs.getInetAddress()+"port: "+cs.getPort());
// recv
BufferedReader reader = new BufferedReader(new InputStreamReader(cs.getInputStream())); // 담당 소켓의 스트림으로부터 데이터 읽어들임
String pecket = reader.readLine(); // 한줄씩 문자열 읽어옴
System.out.println("client로 부터 받은 데이터: "+pecket );
// send (서버의 보내기는 받은 내용을 다른 host로 보내는 기능을 한다.)
PrintWriter pw = new PrintWriter (cs.getOutputStream()); // cs(클라이언트소켓)의 스트림에서 출력
pw.println(pecket);
pw.flush(); // 반드시 flush를 해줘야 정상 작동 한다.
cs.close();
svs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Client String
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
InetSocketAddress sockAddr = new InetSocketAddress("127.0.0.1", 1234); // 127.0.0.1 의 부분에 접속할 서버 IP 입력 , 포트넘버 입력
Socket clientsc = new Socket(); // 클라이언트 소켓 생성
try {
clientsc.connect(sockAddr); // connect을 통해 서버 접속
InetAddress ia; // 확인용
if((ia = clientsc.getInetAddress())!=null) {
System.out.println("connect success" + ia);
}
else {
System.out.println("connect fail");
}
System.out.print("전송할 텍스트 입력: ");
String pecket = sc.next();
//send
PrintWriter pw = new PrintWriter(clientsc.getOutputStream()); //소켓을 통해 위에서 입력 받은 텍스트 출력
pw.println(pecket); //실제 송신
pw.flush();
//recv
BufferedReader reader = new BufferedReader(new InputStreamReader(clientsc.getInputStream())); //소켓을 통해 들어온 문자열 입력
String str = reader.readLine(); // 한줄씩 인식
System.out.println("Server로 부터 받은 데이터: "+str);
clientsc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Server Object
String 이외의 Object로 데이터를 받을 수 있다.
이렇게 되면 문자열 이외의 다양한 정보를 넘기고 받을 수 있게 된다.
- Dto
import java.io.Serializable;
// Serialize(직렬화) 전송 -> 순서를 정해야 한다.
// Network, web 에서 송수신을 할때 반드시 적어 주어야 한다.
// dto는 서버에도 있어야 하며 클라이언트도 있어야한다. (둘다 직렬화가 되어있어야 한다.)
public class MemberDto implements Serializable{
/**
*
*/
private static final long serialVersionUID = 7159726773562029167L;
private int number;
private String name;
public MemberDto() {
}
public MemberDto(int number, String name) {
super();
this.number = number;
this.name = name;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "MemberDto [number=" + number + ", name=" + name + "]";
}
}
- Server
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import dto.MemberDto;
public class Main {
public static void main(String[] args) throws Exception{
ServerSocket serSocket = new ServerSocket(9000);
System.out.println("대기중...");
Socket socket = serSocket.accept();
System.out.println("client IP: "+socket.getInetAddress() //들어온 소켓의 IP 및 포트 넘버출력
+" Port: "+socket.getPort());
//recv
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); // ObjectInputSrteam 인스턴스 생성 소켓으로 받은 내용 읽어들임
//MemberDto dto = (MemberDto)ois.readObject(); // 멤버dto의 클래스 형 변환
Object obj = ois.readObject(); // 위의 방법 대로 형변환을 해주어서 받을 수도 있고 Object로 바로 받을 수 있다.
//System.out.println("client로 부터 Dto: "+dto.toString());
//send
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
//oos.writeObject(dto); // 변현환 된 dto는 다시 Object로 담길수 있기 때문에 바로 전송 가능
oos.writeObject(obj); // 만약 object로 받으면 그대로 넣어서 송신 가능하다.
oos.flush();
serSocket.close();
}
}
- Client
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import dto.MemberDto;
public class Main {
public static void main(String[] args)throws Exception {
InetSocketAddress sockAddr = new InetSocketAddress("127.0.0.1", 9000); // 수신받을 서버의 IP와 포트넘버 기입
Socket socket = new Socket();
socket.connect(sockAddr); // 접속 까지는 방식이 String과 같다.
InetAddress inetAddr; // 접속 확인용
if((inetAddr = socket.getInetAddress()) != null){
System.out.println("Server connect success: "+ inetAddr);
}else {
System.out.println("Server connect fail");
}
MemberDto sendDto = new MemberDto(111,"홍길동"); // 송신할 인스턴스를 생성한다.
// send 부터
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(sendDto);
oos.flush();
//recv
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
MemberDto recvDto = (MemberDto)ois.readObject();
System.out.println("Server로부터 받은 Dto: "+recvDto.toString());
socket.close();
}
}
Thread
- 동작하고 있는 프로그램을 프로세스(Process)라고 한다. 보통 한 개의 프로세스는 한 가지의 일을 하지만, 이 쓰레드를 이용하면 한 프로세스 내에서 두 가지 또는 그 이상의 일을 동시에 할 수 있게 된다.
예제
- Main Class ```java package main;
public class Main {
public static void main(String[] args) {
Thread thread1 = new ThreadEx("퐁");
Thread thread2 = new ThreadEx("당");
Thread thread3 = new ThreadEx("!!!");
thread1.start();
thread2.start();
thread3.start();
} } ``` - Thread ```java public class ThreadEx extends Thread{
String msg;
public ThreadEx(String msg) {
this.msg = msg;
}
@Override
public void run() {
super.run();
// for for for 3개가 한꺼번에 작동 한다. 먼저 출력되는건 순서가 다를 수 있음. 하지만 공평하게 횟수는 같다.
for (int i = 0; i < 10; i++) {
System.out.println(msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} } ``` 쓰레드에 문자열을 입력하여 for문을 돌렸다. 동시에 3개의 for문이 돌아가면서 프로세스를 실행한다.
각 프로세스의 순서는 일정하지 않을 수 있다.
여기서 sleep의 경우 쓰레드의 run 템포를 조절 할 수 있다. 1000 == 1초