C++ SOCKET 网络编程之TCP方式图片等文件传输

利用网络传输文件是常用的功能,本文使用tcp 方式实现文件的传输。

其文件树结构为:

.
├── base
│   ├── data_info.h
│   └── file_operation.h
├── client
│   ├── 1.jpg
│   ├── client_tcp.h
│   └── file_client.c
└── server
    ├── file_server.c
    └── sever_tcp.h

1、base目录下为文件传输的数据结构以及文件操作接口,其源码如下

data_info.h 包含传输的数据结构:

#ifndef __FILE_DATA_INFO_HEADER__
#define __FILE_DATA_INFO_HEADER__
#include<string.h>

#define BUFFER_SIZE 1024

enum info_type
{
	file_info,
	file_data,
	consult_result,
};

struct data_base
{
	short i_type;
	data_base()
	{
		i_type = info_type::file_info;
	}
};

struct st_file_info : public data_base
{
	char name[32];
	int size;
	st_file_info()
	{
		memset((void*)&name, 0, sizeof(name));
		size = 0;
		i_type = info_type::file_info;
	}
};

struct st_file_data : public data_base
{
	int size;
	char data[BUFFER_SIZE];
	st_file_data()
	{
		size = 0;
		memset(&data, 0, sizeof(data));
		i_type = info_type::file_data;
	}
};

struct  st_consult_result : public data_base
{
	int result;
	st_consult_result()
	{
		result = -1;
		i_type = info_type::consult_result;
	}
};

#endif //__FILE_DATA_INFO_HEADER__

file_operation.h 为对文件的读写操作:

#ifndef __FILE_OPERATION_HEADER__
#define __FILE_OPERATION_HEADER__
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include"data_info.h"

int write_to_file(int fd,const char* data,int size)
{
    write(fd,data,size);
}

int read_from_file(int fd,const int offset,char* readbuf,int size)
{
    if(nullptr == readbuf || fd <= -1)
    {
        return -1;
    }
    lseek(fd,offset,SEEK_SET);
    int ret = read(fd,readbuf,size);
    return ret;
}

int open_file(const char* file_path,const char* file_name,int flag)
{
    char file[64];
    memset((void*)&file,0,sizeof(file));
    sprintf(file,"%s/%s",file_path,file_name);
    int fd = open(file,flag,0666);
    if( -1 == fd)
    {
        return -1;
    }
    return fd;
}

int close_file(const int fd)
{
    close(fd);
}

int get_file_info(const char* file_path,const char* file_name,data_base* file_data)
{
    if( nullptr == file_data ||
       nullptr == file_path  ||
       file_data->i_type !=  info_type::file_info )
    {
        return -1;
    }
    struct stat file_info;
    char file[64];
    memset((void*)&file,0,sizeof(file));
    sprintf(file,"%s/%s",file_path,file_name);
    if(-1 == stat(file,&file_info))
    {
        return -2;
    }
    
    st_file_info* info = (st_file_info*) file_data;
    info->size = file_info.st_size;
    file_data->i_type =  info_type::file_info;
    memcpy((void*)info->name ,file_name,sizeof(info->name));
    return 0;
}

#endif //__FILE_OPERATION_HEADER__

2、client 端 问文件按发送方,分了两个文件,一个是client_tcp.h,一个是file_client.c。其中client_tcp.h为tcp 网络连接操作,file_client.c为文件发送操作。

client_tcp.h

#ifndef __CLIENT_TCP_HEADER__
#define __CLIENT_TCP_HEADER__
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

int create_tcp_client_ipv4(const char* ip)
{
    if(nullptr == ip)
    {
        return -2;
    }
    int socket_fd = -1;
    socket_fd = socket(AF_INET,SOCK_STREAM,0);
    if(socket_fd<= -1)
    {
        return -1;
    }

    struct sockaddr_in serv_addr;
    memset((void*)&serv_addr,0,sizeof(struct sockaddr_in));
    serv_addr.sin_port = htons(8888);
	serv_addr.sin_family = AF_INET;
    inet_pton(AF_INET, ip, &serv_addr.sin_addr);

     int ret = connect(socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
     if(0 != ret)
     {
         return -3;
     }

    return socket_fd;
}

int connect_cient_close(int socket_fd)
{
    close(socket_fd);
}

int connect_client_recv_data(int socket_fd,void* recvbuf,int size)
{
    if(nullptr == recvbuf || size < 0)
	{
		printf("error!!! clinet recv buf is null or empty,can't to recv data!!!");
		return -1;
	}
	int recvlen = recv(socket_fd, recvbuf, size, 0);
	return recvlen;
}

int connect_client_send_data(int socket_fd,void* sendbuf, int size)
{
    if(size < 0 || nullptr == sendbuf )
	{
		printf("error!!! client  data is empty ,no need to send!!");
		return -1;
	}
	int sendsize = write(socket_fd,sendbuf,size);

	return sendsize;
}


#endif //__CLIENT_TCP_HEADER__

file_client.c

#include <stdio.h>
#include "client_tcp.h"
#include "../base/data_info.h"
#include "../base/file_operation.h"

int send_consult_file_infomation(const int socket_fd,const st_file_info* file_info)
{
    if(nullptr == file_info || socket_fd <= -1)
    {
        return -1;
    }
    
    int ret = connect_client_send_data(socket_fd,(void*)file_info,sizeof(st_file_info));
    if(ret <= -1)
    {
        return -2;
    }

    return ret;
}

int send_consult_file_end(const int socket_fd,const st_consult_result* file_result)
{
     if(nullptr == file_result || socket_fd <= -1)
    {
        return -1;
    }
    
    int ret = connect_client_send_data(socket_fd,(void*)file_result,sizeof(st_consult_result));
    if(ret <= -1)
    {
        return -2;
    }

    return ret;
} 

int main(int argc,char** argv)
{
    int socket_fd;
    socket_fd = create_tcp_client_ipv4("127.0.0.1");
    if(-1 >= socket_fd)
    {
        printf("create client tcp to server error! code is %d !!!",socket_fd);
        return 0;
    }

    st_file_info file_info;
    int ret = get_file_info(".","1.jpg",&file_info);
    if(ret < 0)
    {
        printf("get file information error! code is %d !!!",ret);
        return 0;
    }


    int fd = open_file(".","1.jpg",O_RDONLY);
    if(fd <= -1)
    {
        printf(" open file error! code is %d !!!",fd);
        return 0;
    }

    send_consult_file_infomation(socket_fd,&file_info);

    int recv_ret = -1;
    char buffer[BUFFER_SIZE];
    memset((void*)buffer,0,sizeof(buffer));

    int read_size = 0;
    int total_offset = 0;
    char send_buffer[BUFFER_SIZE];
    memset((void*)send_buffer,0,sizeof(send_buffer));
    bool send_flag = true;
    while(send_flag)
    {
        recv_ret = connect_client_recv_data(socket_fd,buffer,sizeof(buffer));
        if(recv_ret > 0 )
        {
               data_base* recv = (data_base*) buffer; 
               if(recv->i_type == info_type::consult_result)
               {
                   st_consult_result* result = (st_consult_result*)recv;
                    if(result->result == 1)
                    {
                        while(true)
                        {
                            memset((void*)send_buffer,0,sizeof(send_buffer));
                            read_size = read_from_file(fd,total_offset,send_buffer,sizeof(send_buffer));
                            if(read_size > 0 )
                            {
                                st_file_data data;
                                memset((void*)&data,0,sizeof(data));
                                memcpy(data.data,send_buffer,sizeof(data.data));
                                data.size = read_size;
                                data.i_type = info_type::file_data;
                                connect_client_send_data(socket_fd,(void*)&data,sizeof(st_file_data));
                                total_offset+= read_size;
                                read_size = -1;
                            }else if (read_size == 0){
                                st_consult_result result;
                                memset((void*)&result,0,sizeof(result));
                                result.result = 1;
                                result.i_type = info_type::consult_result;
                                send_consult_file_end(socket_fd,&result);
                                send_flag = false;
                                break;
                            }else{
                                close_file(fd);
                                break;
                            }
                        }
                        
                    }
               }else{
                   printf("wait for consult inforamtion");
               }
        }
    }
    close_file(fd);
    connect_cient_close(socket_fd);
    return 0;
}

3、server 端为文件接收方,同样分为2个文件,一个 sever_tcp.h,一个file_server.c。

sever_tcp.h

#ifndef __SERVER_TCP_HEADER__
#define __SERVER_TCP_HEADER__
#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<stdio.h>

int create_socket_ipv4()
{
	int socketfd = -1;
	
	socketfd = socket(AF_INET,SOCK_STREAM,0);
	if (socketfd <= -1)
	{
		return -1;
	}

	struct sockaddr_in  serv_addr;
	memset((void*)&serv_addr,0,sizeof(struct sockaddr_in));
	serv_addr.sin_port = htons(8888);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_family = AF_INET;

	if (-1 == bind(socketfd, (sockaddr*)&serv_addr, sizeof(struct sockaddr_in)))
	{
		close(socketfd);
		return -1;
	}

	if (-1 == listen(socketfd, 5))
	{
		close(socketfd);
		return -1;
	}

	return socketfd;

}

int connect_accept(int socket_fd)
{
	struct sockaddr_in cli_addr;
	int cli_fd = -1;
	memset((void*)&cli_addr, 0, sizeof(struct sockaddr_in));
	socklen_t len = sizeof(struct sockaddr);
	cli_fd = accept(socket_fd, (sockaddr*)&cli_addr, &len);
	if (-1 >= cli_fd)
	{
		return -1;
	}

	char client_IP[32];
	memset((void*)&client_IP, 0, sizeof(client_IP));
	printf("client ip:%s port:%d\n",
		inet_ntop(AF_INET, &cli_addr.sin_addr.s_addr, client_IP, sizeof(client_IP)),
		ntohs(cli_addr.sin_port));

	return cli_fd;
}

int connect_close(int socket_fd)
{
	close(socket_fd);
	return 0;
}

int connect_send_data(int socket_fd,char* sendbuf,int size)
{
	if(size<0 || nullptr == sendbuf )
	{
		printf("error!!! data is empty ,no need to send!!");
		return -1;
	}
	int sendsize = write(socket_fd,sendbuf,size);
	return sendsize;
}

int connect_recv_data(int socket_fd,char* recvbuf,int size)
{
	if(nullptr== recvbuf || size <= 0)
	{
		printf("error! recv buf is null or empty,can't to recv data!!!");
		return -1;
	}
	int recvlen = recv(socket_fd,recvbuf,size,0);
	return recvlen;
}


#endif //__SERVER_TCP_HEADER__

file_server.c

#include<stdio.h>
#include"../base/data_info.h"
#include"../base/file_operation.h"
#include"sever_tcp.h"


int consult_file_infomation(int cli_fd,int res)
{
	struct st_consult_result result;

    result.result = res;
    connect_send_data(cli_fd,(char*)&result,sizeof(result));
}

int main(int argc,char** argv)
{
    int socket_fd = -1;
    socket_fd = create_socket_ipv4();
    if(socket_fd <= -1 )
    {
        printf("create server error!, code is %d!!",socket_fd);
        return 0;
    }

    int total_recv = 0;
    int file_total_size = 0;
    int fd = -1;

    do
    {
        int cli_socket_fd = connect_accept(socket_fd);
        if(cli_socket_fd<= -1)
        {
            continue;
        }

        while(true)
        {
            data_base data = {};
            int recv_size =  connect_recv_data(cli_socket_fd,(char*)&data,sizeof(data));
            if(recv_size > 0 )
            {
                if(data.i_type == info_type::file_info)
                {
                     st_file_info info = {};
                     connect_recv_data(cli_socket_fd,(char*)&info+sizeof(data_base),sizeof(info)-sizeof(data_base));
                     file_total_size = info.size;
                     fd = open_file(".",info.name,O_WRONLY|O_CREAT|O_APPEND|O_TRUNC);
                     if(fd <=-1)
                     {
                         printf("create file error! code is %d !!",fd);
                         break;
                     }
                     consult_file_infomation(cli_socket_fd,1);
                }else if(data.i_type == info_type::file_data){
                    st_file_data data = {};
                    connect_recv_data(cli_socket_fd,(char*)&data+sizeof(data_base),sizeof(data)-sizeof(data_base));
                    write_to_file(fd,data.data,data.size);
                    total_recv+= data.size;
                    recv_size = -1;
                }else if(data.i_type == info_type::consult_result){
                    st_consult_result result = {};
                    connect_recv_data(cli_socket_fd,(char*)&result+sizeof(data_base),sizeof(result)-sizeof(data_base));
                    if(result.result == 1)
                    {
                        printf(" file total size is %d,and recv total size is %d\n",file_total_size,total_recv);
                    }                   
                    close_file(fd);
                    break;
                }
            }
        }

    }while(false);
    connect_close(socket_fd);
    return 0;
}

编译运行结果:

.
├── base
│   ├── data_info.h
│   └── file_operation.h
├── client
│   ├── 1.jpg
│   ├── a.out
│   ├── client_tcp.h
│   └── file_client.c
└── server
    ├── 1.jpg
    ├── a.out
    ├── file_server.c
    └── sever_tcp.h

client 端1.jpg 图片完整的传输到了server端。

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值