Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- AWS
- EC2
- TypeScript
- window
- db
- sample
- Git
- docker
- Client
- 코딩테스트
- 프로그래머스
- jdbc
- Hibernate
- spring
- Jenkins
- mariadb
- ssh
- 토비의스프링
- spring boot
- Spring Legacy Project
- centos7
- SSL
- 책 정리
- github
- Java
- WebHook
- TLS
- DISTINCT
- vagrant
- Linux
Archives
- Today
- Total
Woopii Vyeolog
[Java] Socket 통신, Tcp Server 샘플 본문
## Github 주소 : https://github.com/leewoopyo/tcp_sample
1. 소켓이란?
소켓은 네트워크 상에서 돌아가는 두 개의 프로그램 간 양방향 통신의 엔드 포인트.
2. 앤드 포인트
여기에서의 앤드 포인트는 아이피 주소와 포트 번호의 조합을 의미함. 모든 TCP 연결은 2개의 앤드 포인트로 유일하게 식별되어질 수 있습니다.
3. 소켓 통신
소켓 통신이란 서버와 클라이언트 양방향 연결이 이루어지는 통신.
4. TCP (스트림 소켓)
- 연결형 (Connection Oriented) 서비스로 연결이 성공해야 통신이 가능하다.
- 데이터의 경계를 구분하지 않는다. (바이트 스트림)
- 데이터의 전송 순서를 보장한다. (데이터의 순서 유지를 위해 각 바이트마다 번호를 부여)
- 신뢰성 있는 데이터를 전송한다. (Sequence Number, Ack Number를 통한 신뢰성 보장)
- 데이터 흐름 제어 (수신자 버퍼 오버플로우 방지) 및 혼잡 제어 (패킷 수가 과도하게 증가하는 현상 방지)
- 연결의 설정 (3-way handshaking) 와 해제(4-way handshaking)
- 전이중 (Full-Duplex), 점대점 (point to point) 서비스
- UDP 보다 전송속도가 느리다.
5. TCP Server
byte의 길이를 표현하는 방식에 따라서 2가지 lengthType을 설정
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* TcpServer
*/
public class TcpServer {
// 서버 포트
private static final int TCP_SVR_PORT = 11111 ;
// 이너 클래스, worker thread
private class Worker extends Thread {
private Socket socket;
public Worker(Socket sock) {
this.socket = sock;
}
// thread 실행 로직
public void run() {
boolean flag = true;
// try ~ catch ~ resource
try (
OutputStream out = this.socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
InputStream in = this.socket.getInputStream();
DataInputStream dis = new DataInputStream(in);
)
{
while(flag) {
// lengthType을 client에서 받음
byte[] byteLengthType = new byte[6];
dis.readFully(byteLengthType, 0, 6);
String lengthType = new String(byteLengthType);
System.out.println("[Tcp_Server] 0. length_type : [" + lengthType + "]");
// 1. lengthType이 'String'일 때
if ("String".equals(lengthType)) {
// 1-1. length 부분 추출 : 빈 4바이트 생성 후 길이부 read
byte[] byteLength = new byte[4];
dis.readFully(byteLength, 0, byteLength.length);
int length = Integer.parseInt(new String(byteLength));
System.out.println("[Tcp_Server] 1. read_length : [" + length + "]");
// 1-2. readMsg 추출 : client에서 보낸 바이트 데이터를 read
byte readMsg[] = new byte[length];
dis.readFully(readMsg, 0, length);
System.out.println("[Tcp_Server] 2. read_msg : [" + new String(readMsg) + "]");
// 1-3. echoMsg 구성 : arraycopy를 사용해서 echoMsg를 구성
byte[] echoMsg = new byte[4 + length];
System.arraycopy(byteLength, 0, echoMsg, 0, 4);
System.arraycopy(readMsg, 0, echoMsg, 4, length);
System.out.println("[Tcp_Server] 3. echo_msg : [" + new String(echoMsg) + "]");
// 1-4. echoMsg write
dos.write(echoMsg, 0, echoMsg.length);
dos.flush();
}
// #2 lengthType이 'Binary'일 때
if ("Binary".equals(lengthType)) {
// 2-1. length 부분 추출 : readInt 메소드로 길이부 추출
int length = dis.readInt();
System.out.println("[Tcp_Server] 1. read_length : [" + length + "]");
// 2-2. readMsg 추출 : client에서 보낸 바이트 데이터를 read
byte readMsg[] = new byte[length];
dis.readFully(readMsg, 0, length);
System.out.println("[Tcp_Server] 2. read_msg : [" + new String(readMsg) + "]");
// 2-3. echoMsg 구성 : arraycopy를 사용해서 echoMsg를 구성
byte[] echoMsg = new byte[length];
System.arraycopy(readMsg, 0, echoMsg, 0, length);
System.out.println("[Tcp_Server] 3. echo_msg : [" + new String(echoMsg) + "]");
// 1-4. echoMsg write
dos.writeInt(echoMsg.length);
dos.write(echoMsg, 0, echoMsg.length);
dos.flush();
}
System.out.println("[Tcp_Server] Tcp Server Response Echo Message Ok........");
}
// EOFException 발생 시
} catch (EOFException eofe) {
//e.printStackTrace();
flag = false;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (this.socket != null) {
System.out.println("[Tcp_Server] disconnected :"+this.socket.getInetAddress().getHostAddress()+"/"+this.socket.getPort());
this.socket.close();
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
// 생성자 메소드 에서 서버 소켓 생성
public TcpServer () throws Exception {
// 소켓 인스턴스 생성
ServerSocket serverSocket = new ServerSocket();
// serReuseAddress 설정을 해줌 (TCP 접속을 닫은 후 일정시간동안 타임아웃 상태일 시 동일 포트를 바인딩 못하는데, 이를 가능하게 하는 옵션)
serverSocket.setReuseAddress(true);
try {
// 소켓에 포트 바인딩
serverSocket.bind(new InetSocketAddress(TCP_SVR_PORT));
System.out.println("starting tcp server : "+TCP_SVR_PORT);
while (true) {
// 서버에서 요청 accept 대기
Socket socket = serverSocket.accept();
System.out.println("connected : "+socket.getLocalPort());
// accept를 받으면 worker Thread 시작
Worker w = new Worker(socket);
w.start();
}
} catch (Exception e) {
e.printStackTrace();
serverSocket.close();
}
}
/**
* main 메소드 실행
* @param args
*/
public static void main(String[] args) {
System.out.println("Hello World!!!");
try {
//서버 인스턴스 실행
new TcpServer();
} catch (Exception e) {
e.printStackTrace();
}
}
}
## 참고
https://coding-factory.tistory.com/614
'java' 카테고리의 다른 글
[Java] Array 중복 제거 (3) | 2022.04.04 |
---|---|
[Java] Socket 통신, TCP Client 샘플 (0) | 2022.04.02 |
[디자인 패턴] Build Pattern, 빌더 패턴 (1) | 2021.02.24 |
Vector vs Arraylist (0) | 2020.02.28 |
String, StringBuffer, StringBuilder (0) | 2020.02.19 |
Comments