728x90
반응형

1. 개요

 - 같은 라우터 내부에서 외부 인터넷이 제한되었으며, 파일을 공유해야할 때 작성하여 사용

 - 같은 공유기 내부의 사설 IP(Private IP)를 사용하여 TCP 소켓 스트림 방식으로 파일을 송수신함

 

2. 사용법

 - 원하는 경로에 File_Share.ps1, send.bat, recv.bat의 3개 파일을 위치시키고, 동일 위치에 전송할 대상을 send.zip으로 압축해 넣어둔다.

 - 파일을 받을 대상 PC에서 recv.bat을 실행 시키고  send.zip이 위치한 PC에서 send.bat을 실행한다.

 

3. 코드 (파워쉘 스크립트 작성)

# File_Share.ps1
param ( 
    [int] $sel = 1,
    [string] $IP = "127.0.0.1",
    [int] $Port = 29800,
    [String] $Send_FileName = "send.zip",
    [String] $Recv_FileName = "recv.zip"
) 

Function Recv_File {
    Param (
        [int] $Port = 29800,
        [String] $FileName = "recv.zip",
        [int] $ChunkSize = 1mb
    ) 

	# Socket Init
    $endpoint = new-object System.Net.IPEndPoint([ipaddress]::any, $port) 
    $listener = new-object System.Net.Sockets.TcpListener $endPoint
    $listener.start() 

    # 연결 대기
    $data = $listener.AcceptTcpClient() 

	# Stream 설정
    $socket_stream = $data.GetStream() 
    $FileReader = New-Object System.IO.BinaryReader $socket_stream
    $FileStream = [System.IO.FileStream]::new($FileName, [System.IO.FileMode]::Append, [System.IO.FileAccess]::Write)
    $Writer = New-Object System.IO.BinaryWriter($FileStream)

    for(){
        $Chunk = $FileReader.ReadBytes($ChunkSize)
        if($Chunk.Length){
            $Writer.Write($Chunk, 0, $Chunk.Length)
        }else{
            break
        }
    }
    
    # Close
    $Writer.Close()  
    $socket_stream.close()
    $listener.stop()
}

Function Send_File { 
    Param ( 
        [string] $IP = "127.0.0.1", 
        [int] $Port = 29800,
        [string] $FileName = "send.zip",
        [int] $ChunkSize = 1mb
    ) 
    
    # Setup connection 
    $EndPoint_IP = [System.Net.Dns]::GetHostAddresses($IP) 
    $Address = [System.Net.IPAddress]::Parse($EndPoint_IP) 
    $Socket = New-Object System.Net.Sockets.TCPClient($Address, $Port) 
    
    # stream 설정
    $Socket_Stream = $Socket.GetStream() 
    $Socket_Writer = New-Object System.IO.BinaryWriter($Socket_Stream)
    $FileInfo = Get-Item -LiteralPath $FileName
    $FileStream = $FileInfo.OpenRead()
    $FileReader = New-Object System.IO.BinaryReader $FileStream
    
    for() {
        $Chunk = $FileReader.ReadBytes($ChunkSize)
        $ChunkSum = 0
                    
        if($Chunk.Length) {
            $Socket_Writer.Write($Chunk, 0, $Chunk.Length)
            $ChunkSum += $Chunk.Length
        }else {
            Write-Host $ChunkSum 'Bytes 전송 완료'
            break;
        }
    }

    # Close
    $Socket_Writer.Close() 
    $FileReader.Close()
    $FileStream.Close()
    $Socket_Writer.Close()
    $Socket_Stream.Close()
}

if($sel -eq 1){
    Write-Host 'Listener'
    Recv_File -Port $Port -FileName $Recv_FileName
}else{
    Write-Host 'Sender'
    Send_File -IP $IP -Port $Port -FileName $Send_FileName
}

 

4. 코드(배치파일 작성)

// listener Start
// recv.bat
#echo off

powershell.exe -File File_Share.ps1 -sel 1

pause
// sender Start
// send.bat
#echo off

powershell.exe -File File_Share.ps1 -sel 2 -IP 127.0.0.1

pause
728x90
반응형
728x90
반응형

1. 목적 

- [프로젝트> 그룹> 커뮤니케이션] 중 화상 회의/영상 채팅 기술을 구현하기 위한 연습코드

- TCP/IP 연결이 성립된 상태에서 1:1로 실시간 단방향 영상 전송을 구현

 

2. 구성

- 노트북 카메라 연결 -> 영상 캡쳐 후 파일 저장 -> 저장된 이미지 파일을 TCP/IP 소켓으로 전송해줌 -> 클라이언트에서는 파일로 받은 후 이미지를 보여줌

- 언어는 C/C++, 네트워크는 윈도우 소켓, 형식은 윈도우 실행파일(exe), 라이브러리는 동적로딩으로 활용(DLL 파일 따로 필요)

- 베이스 코드 : https://hwan001.tistory.com/54?category=747955

 

3. 코드

// windows socket
#include <winsock2.h>

// windows
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// opencv 
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>

using namespace cv;

#pragma comment(lib, "ws2_32.lib")

// Socket
#define IP "127.0.0.1"
#define PORT 6667
#define BUFSIZE 44000

void server();
void client(char *server_ip);
void client_send(SOCKET *sock);
void server_recv(SOCKET *client_sock);

int main() {
    int sel;
    char server_ip[21];
    printf("1: server\n2:client\n3.tmp file clear >");
    scanf_s("%d", &sel);
    switch (sel)
    {
    case 1: // 서버로 수신
        server();
        break;
    case 2: // 클라이언트로 전송
        printf("Server IP : ");
        scanf_s("%s", server_ip, 21);
        if (!strcmp(server_ip, "test")) {
            strcpy(server_ip, IP);
        }
        printf("%s\n", server_ip);
        client(server_ip);
        break;
    case 3: // 임시 파일 삭제
        remove("recv.jpg");
        remove("tmp.jpg");
        break;
    default:
        break;
    }
    return 0;
}

void client(char *server_ip) {
    // WSA  초기화
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    // 소켓 만들기
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
    SOCKADDR_IN addr;
    // 소켓 설정
    ZeroMemory(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(server_ip);
    addr.sin_port = htons(PORT);
    
    // TCP 연결 시도
    connect(sock, (SOCKADDR *)&addr, sizeof(addr));
    // 영상 전송
    client_send(&sock);
    // 마무리
    closesocket(sock);
    WSACleanup();
    remove("tmp.jpg");
}

void server() {
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    // 소켓 만들기
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
    SOCKADDR_IN addr;
    // 소켓 설정
    ZeroMemory(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(PORT);
    
    bind(sock, (SOCKADDR *)&addr, sizeof(addr));
    listen(sock, 2);
    printf("listen ok\n");
    // 클라이언트 연결 요청 수락
    SOCKADDR_IN client_addr;
    ZeroMemory(&client_addr, sizeof(client_addr));
    int nlen = sizeof(client_addr);
    SOCKET client_sock = accept(sock, (SOCKADDR *)&client_addr, &nlen);
    // TCP 연결 수립
    printf("clinet IP : %s\n", inet_ntoa(client_addr.sin_addr));
    // 영상 수신
    server_recv(&client_sock);
    // 마무리
    closesocket(sock);
    WSACleanup();
    remove("recv.jpg");
}

// server function
void server_recv(SOCKET *client_sock) {
    FILE *fp = NULL;
    char buf[BUFSIZE];
    char buf2[BUFSIZE];
    Mat image;
    while (1) {
        // 이미지 파일 수신
        ZeroMemory(buf, NULL);
        fopen_s(&fp, "recv.jpg", "wb");
        // 버퍼 채우기
        recv(*client_sock, buf, sizeof(buf), 0);
        fwrite(buf, BUFSIZE, 1, fp);
        // 버퍼를 두번 받으면 딜레이가 사라진다??
        recv(*client_sock, buf2, sizeof(buf2), 0);
        fwrite(buf2, BUFSIZE, 1, fp);
        fclose(fp);
        // 이미지 보여주기
        image = imread("recv.jpg");
        if (image.empty()) { continue; }
        else imshow("recv", image);
        // esc 누르면 종료
        if (waitKey(33) > 0) break;
    }
}

// client fuction
void client_send(SOCKET *sock) {
    FILE *fp = NULL;
    Mat image;
    VideoCapture cap(0);
    char buf[BUFSIZE];
    while (1) {
        // 카메라 접근 후 파일로 작성
        cap.read(image);
        resize(image, image, Size(300, 400));
        imwrite("tmp.jpg", image);
        // 파일 열어서 읽고 전송
        ZeroMemory(buf, NULL);
        fopen_s(&fp, "tmp.jpg", "rb");
        fread(buf, BUFSIZE, 1, fp);
        send(*sock, buf, sizeof(buf), 0);
        fclose(fp);
    }
}
 

4. 결과

 

 

5. 추가 기능

- 양방향 영상 송수신, IOCP, P2P, 코덱

728x90
반응형

+ Recent posts