본문 바로가기
정보보안

소켓 통신

by asd135 2025. 5. 25.
728x90

소켓 통신이란?

네트워크 상에서 다른 컴퓨터 간 데이터를 주고받기 위한 통신 방식. IP주소와 포트 번호를 사용함

 

소켓 통신의 흐름

서버 측

1. 소켓 생성: 통신을 위한 소켓을 만듬

2. 바인딩: 소켓에 IP와 포트 연결

3. 리스닝: 클라이언트의 접속 대기

4. 접속 수락: 클라이언트가 접속하면 연결 수락

5. 데이터 송수신: 클라이언트와 데이터 주고 받기

6. 연결 종료

 

클라이언트 측

1. 소켓 생성

2. 서버에 연결 요청

3. 데이터 송수신

4. 연결 종료

 

소켓의 종류

TCP 소켓: 연결지향형, 데이터 신회성 높음

UDP 소켓: 비연결지향형, 속도가 빠르지만 신뢰성이 낮음

 

전송방식에 따른 속도차이

TCP는 데이터를 주고받기 전에 3-way handshake로 연결부터 설정해야함, UDP는 handshake없이 바로 전송

 

서버

import socket 

# 1. 소켓 생성 (IPv4, TCP 소켓)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# - socket.AF_INET: IPv4 주소 체계 사용
# - socket.SOCK_STREAM: TCP 프로토콜 사용 

# 2. 바인딩 (IP와 포트 연결)
sock.bind(("", 9999))
# - 빈 문자열("")은 모든 IP 주소에서 접속을 허용한다는 의미 (0.0.0.0)
# - 포트 번호 9999 사용

# 3. 접속 대기 상태 진입
sock.listen()
print("서버 시작")
# - 최대 동시 접속 수는 기본값 (일반적으로 OS에서 설정한 수)
# - listen() 호출 후부터 클라이언트의 접속을 받을 준비 완료

# 4. 클라이언트 접속 수락
conn, addr = sock.accept()
# - 클라이언트가 접속하면 연결을 수락
# - conn: 클라이언트와 데이터를 주고받을 수 있는 소켓 객체
# - addr: 클라이언트의 (IP, 포트) 주소 정보

# 5. 클라이언트로부터 데이터 수신
read_data = conn.recv(1024)
# - 최대 1024바이트까지 데이터를 수신
# - 클라이언트가 보낸 데이터를 바이트로 받아옴

print("recv >>> {}".format(read_data))
# - 수신한 데이터를 출력

# 6. 접속 종료
conn.close()  # 클라이언트와의 연결 종료
sock.close()  # 서버 소켓 닫기

 

바이트, 스트링 차이

바이트: 

1. 컴퓨터가 처리하는 순수한 이진 데이터

2. 0~255 범위의 숫자 배열

3. 사용 예시: 파일 저장, 네트워크 전송, 암호화 등

스트링:

1. 사람이 읽을 수 있는 문자

2. 유니코드 문자

3. 사용 예시: 화면 출력, 텍스트 데이터 처리 

 

import socket

# 1. 소켓 생성
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2. 접속시도
sock.connect(("127.0.0.1", 9999))

# 3. 데이터 송신
send_data = input("입력: ")
sock.sendall(bytes(send_data, "utf-8"))
# - 입력받은 문자열을 바이트로 변환하여 서버로 전송
# - utf-8 인코딩을 사용해 문자열을 bytes 타입으로 바꿈
# - sendall(): 모든 바이트가 전송될 때까지 내부적으로 반복 호출

# 4. 접속 종료
print("클라이언트 종료")
sock.close()

 

에코 서버

에코 서버란?

클라이언트가 보낸 데이터를 그대로 되돌려주는 서버

클라이언트 -> 서버: "Hello"

서버 -> 클라이언트: "Hello"

클라이언트가 보낸 메시지를 서버가 그대로 반사해주는 역할을 함

 

에코 서버

import socket 

# 1. 소켓 생성 (IPv4, TCP 소켓)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# - socket.AF_INET: IPv4 주소 체계 사용
# - socket.SOCK_STREAM: TCP 프로토콜 사용 

# 2. 바인딩 (IP와 포트 연결)
sock.bind(("", 9999))
# - 빈 문자열("")은 모든 IP 주소에서 접속을 허용한다는 의미 (0.0.0.0)
# - 포트 번호 9999 사용

# 3. 접속 대기 상태 진입
sock.listen()
print("서버 시작")
# - 최대 동시 접속 수는 기본값 (일반적으로 OS에서 설정한 수)
# - listen() 호출 후부터 클라이언트의 접속을 받을 준비 완료

# 4. 클라이언트 접속 수락
conn, addr = sock.accept()
# - 클라이언트가 접속하면 연결을 수락
# - conn: 클라이언트와 데이터를 주고받을 수 있는 소켓 객체
# - addr: 클라이언트의 (IP, 포트) 주소 정보

# 5-1. 클라이언트로부터 데이터 수신
read_data = conn.recv(1024)
print("recv >>> {}".format(read_data))
# - 최대 1024바이트까지 데이터를 수신
# - 클라이언트가 보낸 데이터를 바이트로 받아옴
# - 수신한 데이터를 출력

# 5-2. 데이터 송신
conn.sendall(read_data)
print("send >>> {}".format(read_data))
# - recv()로 클라이언트가 보낸 메시지를 받고
# - sendall()로 그대로 다시 돌려보냄 

# 6. 접속 종료
conn.close()  # 클라이언트와의 연결 종료
sock.close()  # 서버 소켓 닫기

 

에코 클라이언트

import socket

# 1. 소켓 생성
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2. 접속시도
sock.connect(("127.0.0.1", 9999))

# 3-1. 데이터 송신
send_data = input("입력: ")
sock.sendall(bytes(send_data, "utf-8"))
# - 입력받은 문자열을 바이트로 변환하여 서버로 전송
# - utf-8 인코딩을 사용해 문자열을 bytes 타입으로 바꿈
# - sendall(): 모든 바이트가 전송될 때까지 내부적으로 반복 호출

# 3-2. 데이터 수신
recv_data = sock.recv(1024)
print(f"recv : {recv_data}")

# 4. 접속 종료
print("클라이언트 종료")
sock.close()

 

반복문으로 메시지를 여러번 주고 받음

import socket 

# 1. 소켓 생성 (IPv4, TCP 소켓)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# - socket.AF_INET: IPv4 주소 체계 사용
# - socket.SOCK_STREAM: TCP 프로토콜 사용 

# 2. 바인딩 (IP와 포트 연결)
sock.bind(("", 9999))
# - 빈 문자열("")은 모든 IP 주소에서 접속을 허용한다는 의미 (0.0.0.0)
# - 포트 번호 9999 사용

# 3. 접속 대기 상태 진입
sock.listen()
print("서버 시작")
# - 최대 동시 접속 수는 기본값 (일반적으로 OS에서 설정한 수)
# - listen() 호출 후부터 클라이언트의 접속을 받을 준비 완료

# 4. 클라이언트 접속 수락
conn, addr = sock.accept()
# - 클라이언트가 접속하면 연결을 수락
# - conn: 클라이언트와 데이터를 주고받을 수 있는 소켓 객체
# - addr: 클라이언트의 (IP, 포트) 주소 정보

while True:
# 5-1. 클라이언트로부터 데이터 수신
    read_data = conn.recv(1024)
    print("recv >>> {}".format(read_data))
    # - 최대 1024바이트까지 데이터를 수신
    # - 클라이언트가 보낸 데이터를 바이트로 받아옴
    # - 수신한 데이터를 출력

    if read_data.decode() == "end":
        break

    # 5-2. 데이터 송신
    conn.sendall(read_data)
    print("send >>> {}".format(read_data))
    # - recv()로 클라이언트가 보낸 메시지를 받고
    # - sendall()로 그대로 다시 돌려보냄 

    # 6. 접속 종료
print("접속종료")
conn.close()  # 클라이언트와의 연결 종료
sock.close()  # 서버 소켓 닫기
import socket

# 1. 소켓 생성
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2. 접속시도
sock.connect(("127.0.0.1", 9999))

while True:
    # 3-1. 데이터 송신
    send_data = input("입력: ")
    sock.sendall(bytes(send_data, "utf-8"))

    if send_data == "end":
        break
    # - 입력받은 문자열을 바이트로 변환하여 서버로 전송
    # - utf-8 인코딩을 사용해 문자열을 bytes 타입으로 바꿈
    # - sendall(): 모든 바이트가 전송될 때까지 내부적으로 반복 호출

    # 3-2. 데이터 수신
    recv_data = sock.recv(1024)
    print(f"recv : {recv_data}")

# 4. 접속 종료
print("클라이언트 종료")
sock.close()

 

 

'정보보안' 카테고리의 다른 글

암호화, 대칭 암호화  (0) 2025.05.26
쓰레드를 이용한 소켓 통신  (0) 2025.05.25
스니핑(Sniffing)  (0) 2025.04.20
네트워크, 전송 계층 TCP/IP 프로토콜의 연관성  (0) 2025.04.15
HTTP 통신 프로토콜  (1) 2025.04.11