포스코DX X 비트교육센터 6기 - 소켓통신


TCP 소켓 프로그래밍

  • 스트림 통신 프로토콜
  • client와 server사이에서, 보낸 만큼 모두 받을 수는 없다. stream 통신이기 때문이고, 경계가 없다라는 말을 한다. 100byte 보내도 2번에 걸쳐 50byte 씩읽을 수 있다.
  • 그러기에, 응용 프로토콜(보조 스트림)을 이용하여 경계를 만들어주어야한다. (ex. send된 것에 개행이 있을 때 까지 recieve하게 하여 server가 받게한다.)

image

  • 소켓 주소를 binding한다.
  • client가 소켓을 만들어서 connect를 호출한다. (패킷이 하나 날아간다. 데이터가 없는. 연결 요청 패킷.)
  • accept() 단계에서 연결이 됨을 확인함. 이 과정이 blocking이 된다고 말한다.
  • write / read가 진행된다.
  • 끝나면 close한다.

코딩해보기

package test;

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.net.SocketException;

public class TCPServer {

	public static void main(String[] args) {
		ServerSocket serverSocket = null;
		
		try {
			//1. Server Socket 생성
			serverSocket = new ServerSocket();
			
			//2. 바인딩(Binding)
			// Socket에 InetSocketAddress(IPAddresss + port)를 바인딩 한다.
			// IPAddress: 0.0.0.0: 특정 호스트 IP에 바인딩 하지 않는다.
			// IPAddress : 내가 접속할 IP주소 0.0.0.0 - 특정 호스트 IP에 바인딩하지 않는다, 아무데서나 접근 가능
			serverSocket.bind(new InetSocketAddress("0.0.0.0", 5000), 10);
			
			//3. accept
			Socket socket = serverSocket.accept(); // blocking
			
			try {
				InetSocketAddress remoteInetSocketAddress = (InetSocketAddress)socket.getRemoteSocketAddress();
				String remoteHostAddress = remoteInetSocketAddress.getAddress().getHostAddress();
				int remotePort = remoteInetSocketAddress.getPort();
				System.out.println("[server] connected by client[" + remoteHostAddress + ":" + remotePort + "]");
				
				//4.  IO Stream 받아오기
				OutputStream os = socket.getOutputStream();
				InputStream is = socket.getInputStream();
				
				while(true) {
					//5. 데이터읽기
					byte[] buffer = new byte[256]; 
					int readByteCount = is.read(buffer);  // blocking
					
					if(readByteCount == -1) {
						// 클라이언트가 정상적으로 종료(close() 호출)
						System.out.println("[server] closed by client");
						break;
					}
					
					String data = new String(buffer, 0, readByteCount, "utf-8");
					System.out.println("[server] received:" + data);
					
					//6. 데이터 쓰기
					os.write(data.getBytes("utf-8"));
				}				
			} catch(SocketException e) {
				System.out.println("[server] suddenly closed by client");
			} catch (IOException e) {
				System.out.println("[server] error:" + e);
			} finally {
				try {
					if(socket != null && !socket.isClosed()) {
						socket.close();
					}
				} catch(IOException e) {
					e.printStackTrace();
				}
			}
			
		} catch (IOException e) {
			System.out.println("[server] error:" + e);
		} finally {
			try {
				if(serverSocket != null && !serverSocket.isClosed()) {
					serverSocket.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		

	}

}

  • 텔넷 다운로드

image

  • 텔넷 사용 이유?
    • telnet은 통신 인터페이스를 제공하는 프로토콜입니다. 연결을 시도하는 클라이언트 컴퓨터가 가상의 연결 통로를 통해 원격으로 서버 컴퓨터(호스트)에 접속할 수 있게 해 줍니다.
    • 현재 telnet은 클라이언트가 서버의 특정 포트로 잘 연결되는지 확인하기 위한 도구로 가장 많이 활용되지 않을까 싶습니다. 통신 가능 여부를 확인하고 연결이 불가하면 방화벽 오픈 작업을 하는 식입니다.
  • 연결 완료

image

  • GET / HTTP/1.1

image

  • 텔넷에서 자동으로 개행을 넣어줌.

C:\Users\pc\Desktop\poscodx2023\eclipse\java-study\network\target\classes>java test.TCPServer

C:\Users\pc\Desktop\poscodx2023\eclipse\java-study\network\target\classes>java echo.EchoServer

Thread

package thread;

public class threadEx01 {
	public static void main(String[] args) {
		//for(int i = 0 ; i <10; i++) {
		//	System.out.print(i);
		//}
		
		//Thread를 쓰면, 자리 선점하는데 시간이 걸려서 밀린다. 
		//출력 결과 : abc0123456789defghijklmnopqrstuvwxyz
		new DigitalThread().start();
		
		for(char c= 'a'; c<= 'z'; c++) {
			System.out.print(c);
			
			try {
				//sleep을 통해 이 두 가지 for문을 섞어줌.
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

package thread;

public class DigitalThread extends Thread {

	@Override
	public void run() {
		for(int i = 0 ; i <10; i++) {
			System.out.print(i);
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}

	

}

http 는

문서를 공유하기 위함이다.

연결을 계속 유지할 필요가 없다.

왜냐하면 문서를 읽는 시간이 있기 때문에, 요청이 계속 하지 않고

연결을 계속 남겨두면 낭비다.

효율적으로하기 위해 http는 문서를 받고 연결을 끊어둔다.