서버
# 필요한 패키지 import
# SERVER
import socket # 소켓 프로그래밍에 필요한 API를 제공하는 모듈
import struct # 바이트(bytes) 형식의 데이터 처리 모듈
import pickle # 객체의 직렬화 및 역직렬화 지원 모듈
import cv2 # OpenCV(실시간 이미지 프로세싱) 모듈
# 서버 ip 주소 및 port 번호
ip = '127.0.0.1'
port = 5000
# 1. 소켓 객체 생성
server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2. 바인딩
server_socket.bind((ip, port))
# 3. 접속 대기
server_socket.listen(10)
# 4. 접속 수락(클라이언트 연결안되면 여기서 멈춰있음)
client_socket, address = server_socket.accept()
# 수신한 데이터를 넣을 버퍼(바이트 객체)
data_buffer = b""
# calcsize : 데이터의 크기(byte)
# - L : 부호없는 긴 정수(unsigned long) 8 bytes
# data_size = struct.calcsize("L")
data_size = struct.calcsize("Q")
# struct.calcsize("L")은 부호 없는 긴 정수(unsigned long)의 크기를 바이트 단위로 계산하는 함수
# 64비트 아키텍처를 사용하고 있다면 8바이트가 나온다.
print(f'{data_size} 나는 data_size 8')
print(f'{data_buffer} 나는 data_buffer')
while True:
# 설정한 데이터의 크기보다 버퍼에 저장된 데이터의 크기가 작은 경우
# 현재까지 수신된 데이터의 크기가 기대되는 데이터의 크기보다 작을 때까지 계속해서 데이터를 수신하는 무한 루프입니다
while len(data_buffer) < data_size:
# 5. 데이터 수신
data_buffer += client_socket.recv(4096)
# 이 부분은 클라이언트 소켓에서 최대 4096바이트의 데이터를 수신하여 data_buffer에 추가하는 역할을 합니다
# recv() 메서드는 소켓으로부터 데이터를 읽어오는 역할
# 버퍼의 저장된 데이터 분할
packed_data_size = data_buffer[:data_size]
# print(f'data_buffer: {data_buffer}')
print(f'packed_data_size: {packed_data_size}') # \x00\x00T\x0e\x80\x04\x95\x03
print(f'packed_data_size int로: {int.from_bytes(packed_data_size, byteorder="big")}')
data_buffer = data_buffer[data_size:]
# print(f'data_buffer 끝 배열: {data_buffer}')
# struct.unpack : 변환된 바이트 객체를 원래의 데이터로 반환
# - > : 빅 엔디안(big endian)
# - 엔디안(endian) : 컴퓨터의 메모리와 같은 1차원의 공간에 여러 개의 연속된 대상을 배열하는 방법
# - 빅 엔디안(big endian) : 최상위 바이트부터 차례대로 저장
# - L : 부호없는 긴 정수(unsigned long) 4 bytes
frame_size = struct.unpack(">Q", packed_data_size)[0]
print(f'frame_size: {frame_size}') # 23215 출력됨
# 프레임 데이터의 크기보다 버퍼에 저장된 데이터의 크기가 작은 경우
while len(data_buffer) < frame_size:
# 데이터 수신
data_buffer += client_socket.recv(4096)
# 프레임 데이터 분할
frame_data = data_buffer[:frame_size]
data_buffer = data_buffer[frame_size:]
print("수신 프레임 크기 : {} bytes".format(frame_size))
# loads : 직렬화된 데이터를 역직렬화
# - 역직렬화(de-serialization) : 직렬화된 파일이나 바이트 객체를 원래의 데이터로 복원하는 것
frame = pickle.loads(frame_data)
# imdecode : 이미지(프레임) 디코딩
# 1) 인코딩된 이미지 배열
# 2) 이미지 파일을 읽을 때의 옵션
# - IMREAD_COLOR : 이미지를 COLOR로 읽음
frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
# 프레임 출력
cv2.imshow('Frame', frame)
# 'q' 키를 입력하면 종료
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
# 6. 접속종료
client_socket.close()
server_socket.close()
print('연결 종료')
# 모든 창 닫기
cv2.destroyAllWindows()
클라이언트
from flask import Flask, render_template, Response
import cv2
import struct
import pickle
import socket
import timeit
app = Flask(__name__)
# OpenCV를 사용하여 동영상 프레임을 수신하여 브라우저에 스트리밍하는 함수
def gen_frames():
ip = '127.0.0.1'
port = 6000
# 1. 소켓 생성
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
# 2. 바인딩
server_socket.bind((ip, port))
# 3. 접속 대기
print('대기중이요!')
server_socket.listen(10)
# 4. 클라이언트 연결 대기 및 데이터 수신
client_socket, address = server_socket.accept()
while True:
start_t = timeit.default_timer()
# 데이터 수신
data_buffer = b""
data_size = struct.calcsize(">Q")
while len(data_buffer) < data_size:
data_buffer += client_socket.recv(4096)
packed_data_size = data_buffer[:data_size]
frame_size = struct.unpack(">Q", packed_data_size)[0]
data_buffer = data_buffer[data_size:]
while len(data_buffer) < frame_size:
data_buffer += client_socket.recv(4096)
frame_data = data_buffer[:frame_size]
data_buffer = data_buffer[frame_size:]
frame = pickle.loads(frame_data)
frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
# 프레임을 JPEG 이미지로 변환
ret, buffer = cv2.imencode('.jpg', frame)
terminate_t = timeit.default_timer()
FPS = int(1./(terminate_t - start_t ))
print(f'현재 FPS: {FPS}')
frame = buffer.tobytes()
# 이미지를 브라우저에 전송
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
# Flask 애플리케이션 루트 경로를 설정하고 이미지를 스트리밍하는 함수를 렌더링하는 라우트를 추가합니다.
@app.route('/')
def index():
return render_template('./index.html')
@app.route('/video_feed')
def video_feed():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(debug=True)
'Python' 카테고리의 다른 글
ai 학습시킬 때 공짜로 다운받는 경로 (0) | 2024.12.03 |
---|---|
excel to pdf python(엑셀을 pdf로 변환하기)_linux environment not window (0) | 2024.08.28 |
생소켓으로 비디오 스트리밍 받아오는 과제2 (0) | 2024.05.29 |
opencv 과제1 (0) | 2024.05.28 |
python에서 Input (0) | 2024.03.11 |