Linux C/S文件传输和云端文件下载服务模拟

/*
 * 这是模拟云端和本地pc的音乐文件的上位机同步程序。
 * xiaoyang @2011.3
 * For PIC32单片机大赛
 *
 * 本程序完全开源,无版权限制。可任意修改使用。
 */
 
+--------------+
| 实现说明	|
+--------------+ 
本模拟程序采用linux Socket和Qt界面开发而成,以实现云端和本地,本地和CloudPlayer之间的数据传输。由于云端环境搭建困难,采用模拟的方式实现相应的效果。
相关技术:linux socket、多线程、文件管理,qt界面编程

+-----------+
| client端 |
+-----------+
使用方法:
双击打开Client即可

功能说明:
--------
client-0.8文件夹中放置的是本地pc服务程序。它的基本功能包括:
(1).获取“云端”音乐文件列表.
(2).下载”云端“选定的音乐文件.
(3).本地pc音乐文件管理.
(4).向CloudPlayer发送音乐文件.

开发环境说明:
OS:		Ubuntu 10.04
界面:	Qt GUI
IDE:	Qt4.6 Creator
其他;	不支持跨平台运行

+-------------------------------------+
| server端(模拟云端)	|
+-------------------------------------+
使用方法:
在终端进入路径,如下运行:
$: chmod 777 server
$: ./server

功能说明:
--------
client-0.8文件夹中放置的是本地pc服务程序。它的基本功能包括:
(1).监听本地请求事件.
(2).将“云端”音乐文件列表传送到本地.
(3).将“云端”选定的音乐文件下载到本地.

开发环境说明:
OS:		Ubuntu 10.04
界面:	linux命令行界面
IDE:	无
其他;	不支持跨平台运行

现把服务端代码粘上来:

/*
 * file trans server
 *
 * xiaoyang 2011.3.20
 */
#include <netinet/in.h>    // for sockaddr_in
#include <sys/types.h>    // for socket
#include <sys/socket.h>    // for socket
#include <stdio.h>        // for printf
#include <stdlib.h>        // for exit
#include <string.h>        // for bzero
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctime>

#include <string>
#include <vector>
#include <iostream>

using namespace std;
/*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
*/
#define SERVER_PORT 			9800 
#define LENGTH_OF_LISTEN_QUEUE  20
#define BUFFER_SIZE 			1024
#define FILE_NAME_MAX_SIZE 		512
#define MAX_INFO				1024

#define CMD_LIST    "list"
#define CMD_DOWN    "download"
#define CMD_STOP    "stop"

#define RETURN_OK	"ok"

#define MUSIC_PATH	"./Music"

#pragma pack (1)
typedef struct FILE_INFO{
    char name[512];
    unsigned long size;
    time_t mtime;    //last modified time
}FileInfo;
#pragma pack()
/*
 * by xiaoyang @2011.3.20
 * function:file scan under given directionary
 * path:    the given dir
 * strvec:  Vector to load scan result(warnning:itsval will be changed!)
 * return:  0 if success,or -1 if failed
 */

/*
 * read lenghth of a file
 * return 0 if can't find file, or 1
 */
int
get_file_info ( vector <string> strvec,vector<FileInfo> &file_info)
{
  struct stat buf;

  for (vector < string >::iterator iter = strvec.begin ();
       iter != strvec.end (); ++iter)
  {
      if (stat ((*iter).c_str(), &buf) < 0)
        {
          continue;
        }

       FileInfo new_info;
       strcpy(new_info.name ,(*iter).c_str());
       new_info.size = (unsigned long) buf.st_size;
       new_info.mtime = buf.st_mtime;
       file_info.push_back(new_info);
  }

  return 1;
}


/*
 * read lenghth of a file
 * return 0 if can't find file, or its lenghth
 */
unsigned long
get_file_size (const char *filename)
{
  struct stat buf;
  if (stat (filename, &buf) < 0)
    {
      return 0;
    }
  return (unsigned long) buf.st_size;
}


/*
 * check if a path is a dir
 * return 0 if is dir or -1 for others
 */
int if_dir(char *path)
{
    struct stat st;
    stat(path,&st);
    if (S_ISDIR(st.st_mode))
    {
        printf("is a dir\n");
        return 0;
    }else
    {
        printf("is not a dir\n");
        return -1;
    }
    return -1;
}

/*
 * function:file scan under given directionary
 * path:    the given dir
 * strvec:  Vector to load scan result(warnning:itsval will be changed!)
 * return:  0 if success,or -1 if failed
 */

int
scan_allfile (const char *path, vector <string> &strvec)
{
  DIR *dp;			//dir stream
  struct dirent *entry;		//dir infomation
  //struct stat statbuf;

  //open dir,test if it exist
  if ((dp = opendir (path)) == 0)
    {
      fprintf (stderr, "open dir failed\n");
      return -1;
    }

  //read dir
  while ((entry = readdir (dp)) != 0)
    {
      //ignore .. dir
      if (!strcmp (entry->d_name, ".") || !strcmp (entry->d_name, ".."))
	{
	  continue;
	}

      //get file info and add it into strvec
      string tmp_path (path);
      if (*(tmp_path.end () - 1) != '/')
	tmp_path += '/';
      tmp_path += entry->d_name;


      //if dir
      if (entry->d_type == 4)
	{
	  scan_allfile (tmp_path.c_str (), strvec);
	}
      else
        {
          strvec.push_back (tmp_path);
	  //do nothing
	}
    }
  closedir (dp);
  return 0;
}

/*
 *
 * test function
 */
int
test_main ()
{
  char *path = (char*)MUSIC_PATH;
  vector < string > strvec;
  vector<FileInfo> fi;
  scan_allfile (path, strvec);
  get_file_info (  strvec,fi);
  for (vector < FileInfo >::iterator iter = fi.begin ();
     iter != fi.end (); ++iter)
  {
      cout << (*iter).name << "\t\t";
      cout << (*iter).size << "\t\t";
      cout << ctime( &(*iter).mtime) << endl;
  }

  return 0;
}


int main(int argc, char **argv)
{
	char cmd[512]={'\0'};
	int server_socket = -1;
	char buffer[BUFFER_SIZE] = {0};
    //设置一个socket地址结构server_addr,代表服务器internet地址, 端口
    struct sockaddr_in server_addr;
    
    bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    server_addr.sin_port = htons(SERVER_PORT);

    //创建用于internet的流协议(TCP)socket,用server_socket代表服务器socket
    server_socket = socket(PF_INET,SOCK_STREAM,0);
    if( server_socket < 0)
    {
        printf("Create Socket Failed!");
        exit(1);
    }
    
    //把socket和socket地址结构联系起来
    if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
    {
        printf("Server Bind Port : %d Failed!", SERVER_PORT); 
        exit(1);
    }
    
    //server_socket用于监听
    if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) )
    {
        printf("Server Listen Failed!"); 
        exit(1);
    }
    
    while (1) //服务器端要一直运行
    {
        //定义客户端的socket地址结构client_addr
        struct sockaddr_in client_addr;
        socklen_t length = sizeof(client_addr);

        //接受一个到server_socket代表的socket的一个连接
        //如果没有连接请求,就等待到有连接请求--这是accept函数的特性
        //accept函数返回一个新的socket,这个socket(new_server_socket)用于同连接到的客户的通信
        //new_server_socket代表了服务器和客户端之间的一个通信通道
        //accept函数把连接到的客户端信息填写到客户端的socket地址结构client_addr中
        printf("server[%d]:wait for client..\n",server_socket);
        int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length);
        if ( new_server_socket < 0)
        {
            printf("Server Accept Failed!\n");
            break;
        }
        
		printf("server already setup..\n");
        bzero(buffer, BUFFER_SIZE);
        length = recv(new_server_socket,buffer,BUFFER_SIZE,0);//这里先接收客户端发来的命令
        if (length < 0)
        {
            printf("Cmd invalid\n");
            break;
        }
        buffer[length+1]='\0';
        //
        printf("get command:%s\n",buffer);
        
        if(strcmp(buffer,CMD_DOWN) == 0){
        	bzero(buffer, BUFFER_SIZE);
			
			//return ok
			strcpy(buffer,(char*)RETURN_OK);
			if(send(new_server_socket,buffer,64,0)<0)
            {
                printf("Send size Failed\n");
                break;
            }
            bzero(buffer, BUFFER_SIZE);
			printf("send ok,ready for download\n");
			
			//get filename
        	length = recv(new_server_socket,buffer,BUFFER_SIZE,0);//这里先接收客户端发来的要获取的文件名
		    if (length < 0)
		    {
		        printf("Server Recieve Data Failed!\n");
		        break;
		    }
			buffer[length+1]='\0';
			printf("get filename:%s\n",buffer);

		    char file_name[FILE_NAME_MAX_SIZE+1];
		    bzero(file_name, FILE_NAME_MAX_SIZE+1);
		    strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
		    FILE * fp = fopen(file_name,"r");
		    if(NULL == fp )
		    {
		        printf("File:\t%s Not Found\n", file_name);
		    }
		    else
		    {
		        bzero(buffer, BUFFER_SIZE);
		        int file_block_length = 0;
		        while( (file_block_length = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
		        {
		            //printf("file_block_length = %d\n",file_block_length);
		            //发送buffer中的字符串到new_server_socket,实际是给客户端
		            if(send(new_server_socket,buffer,file_block_length,0)<0)
		            {
		                printf("Send File:\t%s Failed\n", file_name);
		                break;
		            }
		            bzero(buffer, BUFFER_SIZE);
		        } 
				//这段代码是循环读取文件的一段数据,在循环调用send,发送到客户端,
				//这里强调一点的TCP每次接受最多是1024字节,多了就会分片,因此每次发送时尽量不要超过1024字节。
		        fclose(fp);
		        printf("File:\t%s Transfer Finished\n",file_name);
		    }
        	goto end_session;
        }else if(strcmp(buffer,CMD_LIST) == 0){
        	bzero(buffer, BUFFER_SIZE);
		    
		    //wait for ok
		    length = recv(new_server_socket,buffer,BUFFER_SIZE,0);//recv ok
		    if (length < 0)
		    {
		        printf("Cmd invalid\n");
		        break;
		    }
		    buffer[length+1]='\0';
		    printf("get message1:%s\n",buffer);
        	if(strcmp(buffer,RETURN_OK) != 0){
        		printf("unknow echo\n");
        		goto end_session;
        	}
        	//send file count
			char *path = (char*)MUSIC_PATH;
			vector < string > strvec;
			vector<FileInfo> fi;
			scan_allfile (path, strvec);
			get_file_info (  strvec,fi);
			
			sprintf(buffer,"%d",fi.size());
			if(send(new_server_socket,buffer,64,0)<0)
            {
                printf("Send size Failed\n");
                break;
            }
            bzero(buffer, BUFFER_SIZE);
			printf("send count of file info ok\n");
			
			//send data
			char* temp_buffer = (char*)malloc(sizeof(FileInfo)*MAX_INFO);
			bzero(temp_buffer, sizeof(FileInfo)*MAX_INFO);
			unsigned int i = 0;
			for (vector < FileInfo >::iterator iter = fi.begin();
			 	iter != fi.end ();
			 	++iter)
			{
				char* pos = temp_buffer + i * sizeof(FileInfo);
				memcpy(pos,&(*iter),sizeof(FileInfo));
			  	i++;
			}
			//调试代码
			i = 0;
			for (vector < FileInfo >::iterator iter = fi.begin ();
			 	iter != fi.end ();
			 	++iter)
			{
				FileInfo *temp_info =(FileInfo *)(temp_buffer + i * sizeof(FileInfo));
				printf("\t\tfile:%s\n",temp_info->name);
			  	i++;
			}
			
			//wait for ok
			bzero(buffer, BUFFER_SIZE);
		    length = recv(new_server_socket,buffer,BUFFER_SIZE,0);//recv ok
		    if (length < 0)
		    {
		        printf("Cmd invalid\n");
		        break;
		    }
		    buffer[length+1]='\0';
		    printf("get message2:%s\n",buffer);
        	if(strcmp(buffer,RETURN_OK) != 0){
        		printf("unknow echo\n");
        		goto end_session;
        	}
        	
        	//send data
			if(send(new_server_socket,temp_buffer,fi.size()*sizeof(FileInfo),0)<0)
	        {
	            printf("Send file info Failed\n");
	        }
			free(temp_buffer);
        	bzero(buffer, BUFFER_SIZE);
        	printf("file info send ok!\n");
        	
        	fi.clear();
        	strvec.clear();
        	goto end_session;
        }else if(strcmp(buffer,CMD_STOP) == 0){
        	bzero(buffer, BUFFER_SIZE);
        	goto end_session;
        }else{
        
        }
end_session:

        //关闭与客户端的连接
        close(new_server_socket);
    }
end:
    //关闭监听用的socket
    close(server_socket);
    return 0;
}

上图:

next:

next:

原文地址:https://www.cnblogs.com/yixiaoyang/p/1990915.html