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