/* * 这是模拟云端和本地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:

浙公网安备 33010602011771号