원지의 개발
article thumbnail
Published 2023. 9. 14. 14:10
[네트워크] socket, 웹소켓 Study/Network
728x90

socket

  • 컴퓨터 사이에 네트워킹을 위한 통신 채널
  • 클라이언트 프로세스는 소켓을 통해 서버 프로세스와 데이터를 주고받을 수 있음
  • 전화와 같이 신뢰할 수 있는 양방향 통신을 제공
  • 프로세스 간의 통신에 사용되는 양쪽 끝단(endpoint)을 의미
  • 소켓은 TCP/IP 레이어(4계층)에서 작동하고, 웹 소켓은 HTTP 레이어(7계층)에서 작동함
  • 인터넷 프로토콜에 기반, 대부분의 네트워크 소켓은 인터넷 소켓임

과정

  • 시스템을 구축할 때는 서버 프로세스를 위한 server socket 객체를 만듦
  • 서버 서비스가 원활하게 진행되면 클라이언트 프로세스를 만듦
  • 시스템 구축을 완료하면 고유한 IP 주소와 포트 번호를 가진 서버와
    여기에 접속한 클라이언트는 소켓을 통한 양방향 통신이 가능해짐

2022.10.31 - [프로그래밍 언어/Java] - [Java] 정규 표현식, Network

TCP (Transmission Control Protocol) 연결지향 UDP (User Datagram Program) 비연결형
신뢰도 ▲ 신뢰도 ▼
연결 작업 선행 연결 작업 필요 없음
가상회선, 스트림 소켓  
실시간으로 데이터를 주고 받음  
주소 정보를 bind 함수로 묶어서 지속적인 데이터 송수신 소켓에 데이터를 보낼 때마다 주소 정보를 같이 할당
채팅, 인터넷 등에 사용 TV, 스트리밍
계속 연결 상태를 유지해야 하므로 리소스 소모가 큼 수신 여부는 상관하지 않음
Socket, ServerSocket DatagramSocket, DatagramPacket, MulticlastSocket

TCP 소켓

2023.11.01 - [Study/Network] - [네트워크] HTTPS & SSL TLS, 혼합 콘텐츠

  • TLS 핸드쉐이크는 TCP 소켓 프로그래밍에서 보안 소켓 연결을 초기화하는 과정 중 하나 (accept 전에 완료)
  • TLS (Transport Layer Security)는 인터넷에서 데이터를 안전하게 전송하기 위한 프로토콜 중 하나이며, SSL (Secure Sockets Layer)의 후속 버전
  • TLS 핸드쉐이크는 클라이언트와 서버 간의 보안 통신을 설정하기 위한 프로세스

통신 과정

  • 서버소켓은 연결요청이 올 때마다 새로운 소켓을 생성하여 상대편 소켓과 통신할 수 있도록 연결
  • 실제적인 데이터 통신은 서버소켓과 관계없이 소켓 간에 이루어짐
  • 여러 개의 소켓이 하나의 포트를 공유해서 사용할 수 있지만, 서버소켓은 포트를 독점(바인딩 포트)
    한 포트를 둘 이상의 서버소켓과 연결이 가능하면 클라이언트는 어떤 것과 연결되어야 하는지 알 수 없으므로

Socket & ServerSocket 클래

  • Socket: 프로세스간의 통신을 담당
                 InputStream과 OutputStream을 가짐
  • ServerSocket: 포트와 연결되어 기다리다 외부의 연결요청이 들어오면 Socket을 생성해서 소켓과 소켓간의 통신이 이루어지도록 함
                            한 포트에 하나의 ServerSocket만 연결 (프로토콜이 다르면 같은 포트 공유 가능)

예제

더보기

TcpIpServer

package chapter16;

import java.io.*;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;

public class TcpIpServer {
	public static void main(String[] args) {
		ServerSocket serverSocket = null;
		
		try {
			//1. 서버소켓을 생성하여 7777번 포트와 결합(bind)
			serverSocket = new ServerSocket(7777);
			System.out.println(getTime() + " 서버가 준비되었습니다.");
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		while(true) {
			try {
				System.out.println(getTime() + " 연결요청을 기다립니다.");
				//2. 서버소켓은 클라이언트의 연결요청이 올 때까지 실행을 멈추고 계속 기다림
				//2-1. 클라이언트의 연결요청이 오면 클아이언트 소켓과 통신할 새로운 소켓을 생성
				Socket socket = serverSocket.accept();
				System.out.println(getTime() + socket.getInetAddress() + "로부터 연결요청이 들어왔습니다.");
				
				//3. 소켓의 출력스트림을 얻음
				OutputStream out = socket.getOutputStream();
				DataOutputStream dos = new DataOutputStream(out);
				
				//4. 원격 소켓(remote socket)에 데이터를 보냄
				dos.writeUTF("[Notice] Test Message1 from Server.");
				System.out.println(getTime() + " 데이터를 전송했습니다.");
				
				//5. 스트림과 소켓을 닫아줌
				dos.close();
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}//end while
	}

	//현재 시간을 문자열로 반환하는 함수
	static String getTime() {
		SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
		return f.format(new Date());
	}
}
  • accept() 메소드는 클라이언트가 연결 요청을 하기 전까지 블로킹(스레드가 대기 상태)되므로 UI를 생성하는 스레드나, 이벤트를처리하는 스레드에서 accpet() 메소드를 호출하지 않도록 해야함
  • 클라이언트 프로그램이 서버에 연결을 요청하면, 서버소켓은 새로운 소켓을 생성하여 클라이언트 프로그램 소켓(원격소켓)과 연결
  • 새로 생성된 소켓은 [Notice] Test Message1 from Server. 라는 데이터를 원격 소켓에 전송하고 연결을 종료
  • 그리고 서버소켓은 다시 클라이언트 프로그램의 요청을 기다림
  • 클라이언트 프로그램의 요청을 지속적으로 처리하기 위해 무한반복문 사용 (ctrl+C로 강제 종료 해야 함)

TcpIpClient

package chapter16;

import java.io.*;
import java.net.*;

public class TcpIpClient {
	public static void main(String[] args) {
		try {
			String serverIp = "127.0.0.1";
			
			System.out.println("서버에 연결중입니다. 서버 IP: " + serverIp);
			
			//1. 소켓을 생성하여 서버에 연결을 요청
			Socket socket = new Socket(serverIp, 7777);
			
			//2. 연결되면 소켓의 입력스트림을 얻음
			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();
		}
	}
}
  • 먼저 서버 포트를 열고 클라이언트 서버 구동

스레드 병렬 처리

  • 서버를 실행하는 main 스레드가 직접 입출력 작업을 담당하게 되면 입출력이 완료될 때까지 다른 작업을 할 수 없음
  • 그렇기 때문에 accept(), connect(), read(), write()는 별도의 작업 스레드를 생성하여 병렬적으로 처리하는게 좋음
  • 클라이언트의 폭증으로 인해 서버의 과도한 스레드 생성을 방지하려면 스레드풀을 사용하는 것이 바람직함

내용 추가

 


UDP 소켓

  • DatagramSocket과 DatagramPacket(데이터 담음)을 사용
  • 비연결형이므로 ServerSocket(TCP에서는 Socket, ServerSocket 사용)이 필요하지 않음

예제

더보기

UdpClient

package chapter16;

import java.io.IOException;
import java.net.*;

public class UdpClient {
	public void start() throws IOException, UnknownHostException {
		DatagramSocket datagramSocket = new DatagramSocket();
		InetAddress serverAddress = InetAddress.getByName("127.0.0.1");
		
		//데이터가 저장될 공간으로 byte배열 생성
		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(outPacket);
		
		System.out.println("current server time : " + new String(inPacket.getData()));
		datagramSocket.close();
	} //start()
	
	public static void main(String[] args) {
		try {
			new UdpClient().start();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

UdpServer

package chapter16;

import java.io.IOException;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.Date;

public class UdpServer {
	public void start() throws IOException, UnknownHostException {
		DatagramSocket socket = new DatagramSocket(7777);
		DatagramPacket inPacket, outPacket;
		
		byte[] inMsg = new byte[10];
		byte[] outMsg;
		
		while(true) {
			//데이터를 수신하기 위한 패킷을 생성
			inPacket = new DatagramPacket(inMsg, inMsg.length);
			socket.receive(inPacket); //패킷을 통해 데이터를 수신함
			
			//수신한 패킷으로부터 client의 IP주소와 Port를 얻음
			InetAddress address = inPacket.getAddress();
			int port = inPacket.getPort();
			
			//서버의 현재 시간을 시분초 형태로 반환
			SimpleDateFormat sdf = new SimpleDateFormat("[hh:mm:ss]");
			String time = sdf.format(new Date());
			outMsg = time.getBytes(); //time을 byte배열로 반환
			
			//패킷을 생성해서 client에게 전송(send)
			outPacket = new DatagramPacket(outMsg, outMsg.length, address, port);
			socket.send(outPacket);
		}
	}//start()
	
	public static void main(String[] args) {
		try {
			new UdpServer().start(); //UDP서버 실행
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

웹소켓

  • http(웹)에서 실시간 통신 할 수 없는 문제를 해결하기 위해 나온 기술
    웹에서 TCP 소켓을 사용할 수 있지만 메시지를 보내는 것이 개발측면에서 더 적합하기 때문에 발전 됨
  • 소켓은 TCP/IP 레이어(4계층)에서 작동하고, 웹 소켓은 HTTP 레이어(7계층)에서 작동함
  • 평문 메시지 전송 방식으로 SSL/TLS 보안 계층으로 암호화되어야 데이터 탈취 방지할 수 있음
  • HTML5에서 소개된 기술, 양방향 통신을 하고, IP와 포트를 통한 통신
  • TCP 소켓 통신은 바이트 스트림을 통해 데이터 전송, 웹 소켓은 메시지 형식의 데이터를 다룸
웹 소켓은 TCP 소켓과 구분되는 것이 아니라 TCP 소켓의 추상화된 형태
728x90
profile

원지의 개발

@원지다

250x250