公网socket文件(图像)传输

9 篇文章 0 订阅

---------https://docs.python.org/2/library/socket.html-----------官网是个不错的选择!!!

1.服务器端

参考网站:https://www.cnblogs.com/dreamer-fish/p/5501924.html

server.py运行于公网服务器(腾讯云-安全组加入8080端口文章-6)

#coding=utf-8
'''
程序思路:9位字符串用于接收文件(这里是图片)的大小self.filesize;根据文件大小接收后续客户端发来的文件流(二进制流)。
'''
from socket import *
import threading
import SocketServer,time,struct,os
class MyRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        print('connected from:', self.client_address)
        while True:
            self.buf = self.request.recv(9)
            if self.buf: 
                self.filesize = int(self.buf)
                print('file size is:{}'.format(self.filesize))
                self.filenewname = "new.jpg"
                recvd_size = 0 #定义接收了的文件大小
                file = open(self.filenewname,'w')
                print('stat receiving...')
                while not recvd_size == self.filesize:
                    if self.filesize - recvd_size > 1024:
                        rdata = self.request.recv(1024)
                        recvd_size += len(rdata)
                    else:
                        rdata = self.request.recv(self.filesize - recvd_size)
                        recvd_size = self.filesize
                    file.write(rdata)
                file.close()
                print('receive done')
if __name__ == '__main__':
    HOST = ''
    POST = 8080
    ADDR = (HOST, POST)
    tcpServ = SocketServer.ThreadingTCPServer(ADDR, MyRequestHandler)
    print('waiting for connection...' )
    tcpServ.serve_forever()

运行程序后,本地(联网)测试8080端口:telnet 【公网IP】 8080

2.客户端

参考网站1:https://blog.csdn.net/yutianzuijin/article/details/27205121

参考网站2:https://www.bogotobogo.com/cplusplus/sockets_server_client.php

运行于连接网络的电脑上。

  • 获取文件大小(#include <sys/stat.h>)
  • sprintf将文件大小转换为9位长度的字符串(文件大小前补0)
  • socket发送9位(字符串形式)文件大小
  • socket发送文件。
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <sys/stat.h>
#include<unistd.h>
#define PORT 8080
#define LENGTH 512

using namespace std;
//文件大小
int file_size2(char* filename)
{
    struct stat statbuf;
    stat(filename,&statbuf);
    int size=statbuf.st_size;
    return size;
}
int main(int argc, char *argv[]){
    int sockfd;
    int nsockfd;
    char revbuf[LENGTH];
    struct sockaddr_in remote_addr;
    /* Get the Socket file descriptor */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        fprintf(stderr, "ERROR: Failed to obtain Socket Descriptor! (errno = %d)\n",errno);
        exit(1);
    }
    /* Fill the socket address struct */
    remote_addr.sin_family = AF_INET;
    remote_addr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &remote_addr.sin_addr);  //127.0.0.1表示本机IP,修改为云服务器公网IP即可
    bzero(&(remote_addr.sin_zero), 8);

    /* Try to connect the remote */
    if (connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1)
    {
        fprintf(stderr, "ERROR: Failed to connect to the host! (errno = %d)\n",errno);
        exit(1);
    }
    else
        printf("[Client] Connected to server at port %d...ok!\n", PORT);

    /* Send File to Server */
    char sdbuf[LENGTH];
    char fname[256];
    char head_buffer[256]="";
    int n;
    bzero(fname,256);
    bzero(head_buffer,256);
    cout<<"input file name:";
    fgets(fname,255,stdin);           //传输文件名
    char *fs_name = (char*)malloc((strlen(fname)-1)*sizeof(char));

    memcpy(fs_name,fname,(strlen(fname)-1));
    cout<<"file name:"<<fs_name<<endl;
    FILE *fs = fopen(fs_name, "rw");
    int f_size = file_size2(fs_name);       //文件大小
    cout<<"f_size:"<<f_size<<endl;
    char char_f_size[128];
    sprintf(char_f_size,"%09d",f_size);
    //strcat(head_buffer,fs_name);
    strcat(head_buffer,char_f_size);
    n = write(sockfd,head_buffer, strlen(head_buffer));
    cout<<"finish writing head, head width(send length):"<<strlen(head_buffer)<<endl;
    if(n<0) printf("Error: sending filename");
    printf("[Client] Sending %s to the Server... ", fs_name);
    if(fs == NULL)
    {
        printf("ERROR: File %s not found.\n", fs_name);
        exit(1);
    }
    bzero(sdbuf, LENGTH);
    int fs_block_sz;
    while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
    {
        if(send(sockfd, sdbuf, fs_block_sz, 0) < 0)
        {
            fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", fs_name, errno);
            break;
        }
        bzero(sdbuf, LENGTH);
    }
    printf("Ok File %s from Client was Sent!\n", fs_name);
    close (sockfd);
    printf("[Client] Connection lost.\n");
    return (0);
}

c++程序需要编译,Linux64bit环境下CMakeLists文件提供如下:(也可以直接gcc编译)

project(ser_cli)
cmake_minimum_required(VERSION 2.8)
cmake_policy(SET CMP0015 NEW)

include_directories(include)
link_directories(lib)
set(CMAKE_CXX_FLAGS "-std=c++11")

add_executable(c_client c_client.cpp)

#添加后可进行调试
set( CMAKE_BUILD_TYPE Debug )

target_link_libraries(c_client)

粘包问题:我采用的是加入文件头部(文件长度)的方式。但同时需要注意,每次client发送数据后,最好清空一下数组:

memset(head,0,sizeof(head));//头部数组(head)清空
memset(data,0,sizeof(data));//文件数组(data)清空

如果不清空我的程序导致读取的包太短的问题,清空就没问题了。

将文件封装为json格式,图片以base64封装为json格式:https://blog.csdn.net/weixin_42755375/article/details/81783125

json头文件:https://github.com/nlohmann/json#conversion-from-stl-containers(stl容器数据结构list vector等都可以打包)

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值