网络流媒体播放器(网络由局域网实现)
核心功能是要求实现多进程访问(即存在多个终端用户可以访问,并下载视频资源),网络访问,要求存在守护进程
下载:二进制拷贝vedio目录下的文件。
提示输入printf语句要使用中文
文件要封装,
我使用的系统是redhat6.5,gcc --version结果是:gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)
=======Welcome kun_Player=======
1.注册
2.用户登录
3.忘记密码
用户menu
1:下载视频
2:上传文件
3:用户修改密码/输入
4:注销账号
下载视频menu
1.列出可下载视频文件
2.选择下载视频/创建一个"id+movie"目录,将下载的视频放在该目录下
这是我的文件[root@Redhat6 player]# ll -a
总用量 28
drwxr-xr-x 3 root root 4096 7月 28 12:34 .
drwxr-xr-x 12 root root 4096 7月 25 10:59 ..
-rw-r--r-- 1 root root 0 7月 25 11:03 client.c
-rw-r--r-- 1 root root 0 7月 25 11:02 Makefile
-rw-r--r-- 1 root root 1907 7月 25 21:04 player.h
-rw-r--r-- 1 root root 0 7月 25 11:03 service.c
-rw-r--r-- 1 root root 2762 7月 25 21:03 user.c
-rw-r--r-- 1 root root 0 7月 25 11:01 user.db
drwxr-xr-x 2 root root 4096 7月 28 12:34 video‘
pwd (video) = /c_code/player7/video
=============================================================
这是我当前的player.h文件
#ifndef __KUN_PLAYER_H__
#define __KUN_PLAYER_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <share.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
#include <syslog.h>
#include <errno.h>
#include <time.h>
#include <arpa/inet.h>
#define SERVER_PORT 8888
#define MAX_CLIENTS 10
#define BUFFER_SIZE 1024
#define VIDEO_DIR "/c_code/player7/video/"
#define USER_DB "/c_code/player7/user.db"
extern char current_user_id[20];
typedef struct user {
char id[20];
char pwd[20];
} User;
typedef struct node {
void *data;
struct node *next;
struct node *prev;
} Node;
typedef struct file_info {
char file_name[120];
unsigned long file_size;
}File_info;
// 菜单功能
void main_menu();
void regis_menu();
void login_menu();
void forget_pwd_menu();
void user_menu(const char *user_id);
void download_menu(int sockfd);
void upload_menu(int sockfd);
void change_password_menu(const char *user_id);
void delete_account_menu(const char *user_id);
// 用户管理
Node *create_userlist_head();
void add_user(Node **head, User *user);
void delete_user(Node **head, const char *id);
Node *find_user_byid(Node *head, const char *id);
void save_user_file(Node *head, const char *filename);
void load_user_file(Node **head, const char *filename);
void free_user_list(Node *head);
// 网络功能
int init_server();
void handle_client(int client_fd);
void download_file(int sockfd, const char *filename);
void upload_file(int client_fd, const char *filename);
void list_videos(int sockfd);
int connect_server();
// 守护进程
void daemonize();
#endif
该函数ERRP在share.h中
//容错宏
20 //第一个参数:表示条件
21 //第二个参数:表示错误信息
22 //第三个参数:表示处理结果 退出
23 #define ERRP(con, info, ret) do{ \
24 if (con) \
25 { \
26 printf(#info" false!(errline : %d fun c : %s file : %s)\n", __LINE__, __func__, __FILE__); \
27 ret; \
28 } \
29 }while(0)
=========================================================================
这是我目前的user.c
#include "player.h"
Node* create_userlist_head() {
Node* head = (Node*)malloc(sizeof(Node));
ERRP(head == NULL, "内存申请失败", goto ERR1);
head->data = NULL;
head->prev = head;
head->next = head;
return head;
ERR1:
printf("内存申请失败!\n");
return NULL;
}
void add_user(Node** head, User* user) {
ERRP(*head == NULL || user == NULL, "head或用户数据异常", goto ERR2);
Node* new_node = (Node*)malloc(sizeof(Node));
ERRP(new_node == NULL, "内存申请失败", goto ERR1);
new_node->data = user;
new_node->next = (*head)->next;
new_node->prev = *head;
(*head)->next->prev = new_node;
(*head)->next = new_node;
return;
ERR1:
printf("内存申请失败!\n");
return;
ERR2:
printf("head或其他用户数据异常\n");
return;
}
void delete_user(Node** head, const char* id) {
ERRP(*head == NULL || id == NULL, "head或id异常", goto ERR2);
Node* todelete = find_user_byid(*head, id);
if (todelete == NULL) {
printf("id错误,没查询到该用户\n");
return;
}
todelete->prev->next = todelete->next;
todelete->next->prev = todelete->prev;
free(todelete->data); // 释放User数据
free(todelete);
return;
ERR2:
printf("head或其他用户数据异常\n");
return;
}
Node* find_user_byid(Node* head, const char* id) {
ERRP(head == NULL || id == NULL, "head或id异常", goto ERR2);
Node* current = head->next;
while (current != head) {
User* user = (User*)current->data;
if (strcmp(user->id, id) == 0) {
return current;
}
current = current->next;
}
return NULL;
ERR2:
printf("head或其他用户数据异常\n");
return NULL;
}
void save_user_file(Node* head, const char* filename) {
ERRP(head == NULL || filename == NULL, "head或文件名异常", goto ERR2);
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
ERRP(fd == -1, open , goto ERR3);
Node* current = head->next;
while (current != head) {
User* user = (User*)current->data;
ssize_t written = write(fd, user, sizeof(User));
ERRP(written != sizeof(User), "写入失败", goto ERR4);
current = current->next;
}
close(fd);
return;
ERR2:
printf("head或其他用户数据异常\n");
return;
ERR3:
printf("文件打开失败\n");
return;
ERR4:
printf("写入文件失败\n");
close(fd);
return;
}
void load_user_file(Node** head, const char* filename) {
ERRP(head == NULL || filename == NULL, "head或文件名异常", goto ERR2);
int fd = open(filename, O_RDONLY);
if (fd == -1) {
printf("用户数据库不存在。\n");
return;
}
User temp;
while (read(fd, &temp, sizeof(User)) == sizeof(User)) {
User* new_user = (User*)malloc(sizeof(User));
if (new_user == NULL) {
printf("内存申请失败!\n");
close(fd);
return;
}
*new_user = temp;
add_user(head, new_user);
}
close(fd);
return;
ERR2:
printf("head或其他用户数据异常\n");
return;
}
void free_user_list(Node* head) {
ERRP(head == NULL , "head", goto ERR2);
Node* current = head->next;
while (current != head) {
Node* next = current->next;
free(current->data);
free(current);
current = next;
}
free(head);
return;
ERR2:
printf("head异常\n");
return;
}
==========================================================
这是我目前的service.c
#include "player.h"
static Node *user_list = NULL;
static int server_fd = -1;
/*
SIGCHLD信号处理函数
用于回收子进程资源,防止僵尸进程
*/
void sigchld_handler(int sig) {
while (waitpid(-1, NULL, WNOHANG) > 0);
}
/*
* 守护进程化函数
* 将当前进程转变为守护进程
*/
void daemonize() {
pid_t pid = fork();
ERRP(pid < 0, "创建守护进程失败", exit(EXIT_FAILURE));
// 父进程退出
if (pid > 0) {
exit(EXIT_SUCCESS);
}
// 创建新会话
if (setsid() < 0) {
exit(EXIT_FAILURE);
}
// 忽略信号
signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);
pid = fork();
ERRP(pid < 0, "第二次fork失败", exit(EXIT_FAILURE));
if (pid > 0) {
exit(EXIT_SUCCESS);
}
umask(0);
chdir("/");
int x=0;
//当进程从普通进程转变为守护进程时,它会继承父进程所有打开的文件描述符
//这些文件描述符可能包括终端设备、管道、临时文件等,守护进程不再需要这些资源
//如果不关闭,会导致系统资源(文件描述符)被无意义占用
for (x= sysconf(_SC_OPEN_MAX); x >= 0; x--) {
close(x);
}
}
/*
* 初始化服务器
* 创建socket,绑定端口并开始监听
* 返回: 成功返回0,失败返回-1
*/
int init_server() {
struct sockaddr_in server_addr;
// 创建TCP socket
server_fd = socket(AF_INET, SOCK_STREAM, 0);
ERRP(server_fd < 0, "创建socket失败", return -1);
// 设置socket选项,允许地址重用
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// 配置服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT);
// 绑定socket到地址
ERRP(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0,
"绑定端口失败", close(server_fd); return -1);
// 开始监听,最大连接数为MAX_CLIENTS
ERRP(listen(server_fd, MAX_CLIENTS) < 0,
"监听失败", close(server_fd); return -1);
printf("服务器启动成功,监听端口: %d\n", SERVER_PORT);
return 0;
}
/*
* 列出视频目录中的文件
* sockfd: 客户端socket文件描述符
*/
void list_videos(int sockfd) {
DIR *dir;
struct dirent *entry;
char buffer[BUFFER_SIZE] = {0};
// 打开视频目录
dir = opendir(VIDEO_DIR);
if (dir == NULL) {
strcpy(buffer, "无法打开视频目录");
send(sockfd, buffer, strlen(buffer), 0);
return;
}
// 构建文件列表字符串
strcpy(buffer, "可下载视频列表:\n");
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
strcat(buffer, entry->d_name);
strcat(buffer, "\n");
}
closedir(dir);
send(sockfd, buffer, strlen(buffer), 0);
}
/*
* 发送文件给客户端
* sockfd: 客户端socket文件描述符
* filename: 要发送的文件名
*/
void send_file(int sockfd, const char *filename) {
}
void up_load(int client_fd, const char *filename) {
}
/*
* 处理客户端请求
* client_fd: 客户端socket文件描述符
*/
// 在 handle_client 函数中添加新的命令处理
void handle_client(int client_fd) {
char buffer[BUFFER_SIZE];
ssize_t bytes_received;
while ((bytes_received = recv(client_fd, buffer, BUFFER_SIZE, 0)) > 0) {
buffer[bytes_received] = '\0';
if (strncmp(buffer, "LIST", 4) == 0) {
list_videos(client_fd);
}
else if (strncmp(buffer, "DOWNLOAD ", 9) == 0) {
send_file(client_fd, buffer + 9);
}
else if (strncmp(buffer, "UPLOAD ", 7) == 0) {
up_load(client_fd,buffer + 7);
}
}
close(client_fd);
}
/*
* 服务器主循环
* 接受客户端连接并创建子进程处理
*/
void run_server() {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_fd;
// 设置SIGCHLD信号处理
signal(SIGCHLD, sigchld_handler);
while (1) {
// 接受客户端连接
client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
if (client_fd < 0) {
perror("接受连接失败");
continue;
}
printf("新客户端连接: %s:%d\n",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 创建子进程处理客户端
pid_t pid = fork();
if (pid == 0) { // 子进程
close(server_fd);
handle_client(client_fd);
exit(EXIT_SUCCESS);
} else if (pid > 0) { // 父进程
close(client_fd);
} else {
perror("fork失败");
close(client_fd);
}
}
}
/*
* 主函数
*/
int main() {
daemonize();
// 初始化用户数据库
user_list = create_userlist_head();
load_user_file(&user_list, USER_DB);
// 初始化服务器
if (init_server() < 0) {
return EXIT_FAILURE;
}
// 运行服务器主循环
run_server();
// 清理资源
free_user_list(user_list);
close(server_fd);
return EXIT_SUCCESS;
}
===========================================================
这是我目前的client.c
#include "player.h"
char current_user_id[20] = {0};
/*
* 连接到服务器
* 返回: 成功返回socket文件描述符,失败返回-1
*/
int connect_server() {
int sockfd;
struct sockaddr_in server_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
ERRP(sockfd < 0, "创建socket失败", return -1);
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("连接服务器失败");
close(sockfd);
return -1;
}
return sockfd;
}
void receive_file(int sockfd, const char *save_path) {
}
// 上传文件功能
void upload_menu(int sockfd) {
}
void download_menu(int sockfd) {
struct file_info {
char file_name[120];
unsigned long file_size;
} file_info;
char buffer[BUFFER_SIZE];
char filename[256];
printf("\n=======下载视频=======\n");
printf("1. 列出可下载视频\n");
printf("2. 输入文件名下载\n");
printf("请选择: ");
int choice;
scanf("%d", &choice);
getchar();
if (choice == 1) {
send(sockfd, "LIST", 4, 0);
ssize_t bytes = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
if (bytes > 0) {
buffer[bytes] = '\0';
printf("%s\n", buffer);
}
return;
}
printf("请输入要下载的文件名: ");
fgets(filename, sizeof(filename), stdin);
filename[strcspn(filename, "\n")] = '\0';
// 1. 发送下载请求
snprintf(buffer, sizeof(buffer), "DOWNLOAD %s", filename);
send(sockfd, buffer, strlen(buffer), 0);
// 2. 接收文件信息
ssize_t bytes = recv(sockfd, &file_info, sizeof(file_info), MSG_WAITALL);
if (bytes <= 0) {
printf("文件不存在或接收失败\n");
return;
}
// 3. 创建用户目录
char user_dir[256];
snprintf(user_dir, sizeof(user_dir), "%smovie", current_user_id);
mkdir(user_dir, 0755);
// 4. 准备接收文件
char save_path[PATH_MAX];
snprintf(save_path, sizeof(save_path), "%s/%s", user_dir, file_info.file_name);
printf("开始下载: %s (%.2f MB)\n", file_info.file_name,
file_info.file_size / (1024.0 * 1024));
int fd = open(save_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
perror("创建文件失败");
return;
}
// 5. 接收文件内容
// 6. 验证完整性
}
/*
* 用户菜单
* user_id: 当前登录的用户ID
*/
void user_menu(const char *user_id) {
int sockfd = connect_server();
if (sockfd < 0) {
printf("无法连接到服务器\n");
return;
}
int choice;
while (1) {
printf("\n=======用户菜单=======\n");
printf("用户: %s\n", user_id);
printf("1. 下载视频\n");
printf("2. 上传文件\n");
printf("3. 修改密码\n");
printf("4. 注销账号\n");
printf("5. 退出登录\n");
printf("请选择: ");
scanf("%d", &choice);
getchar(); // 清除换行符
switch (choice) {
case 1:
download_menu(sockfd);
break;
case 2:
upload_menu(sockfd);
break;
case 3:
change_password_menu(user_id);
break;
case 4:
delete_account_menu(user_id);
close(sockfd);
return; // 注销后返回主菜单
case 5:
close(sockfd);
return;
default:
printf("无效选择\n");
}
}
}
/*
* 用户注册菜单
*/
void regis_menu() {
User new_user;
Node *user_list = create_userlist_head();
load_user_file(&user_list, USER_DB);
printf("\n=======用户注册=======\n");
printf("请输入用户名: ");
fgets(new_user.id, sizeof(new_user.id), stdin);
new_user.id[strcspn(new_user.id, "\n")] = '\0';
printf("请输入密码: ");
fgets(new_user.pwd, sizeof(new_user.pwd), stdin);
new_user.pwd[strcspn(new_user.pwd, "\n")] = '\0';
if (find_user_byid(user_list, new_user.id) != NULL) {
printf("用户名已存在\n");
free_user_list(user_list);
return;
}
User *user = (User *)malloc(sizeof(User));
strcpy(user->id, new_user.id);
strcpy(user->pwd, new_user.pwd);
add_user(&user_list, user);
save_user_file(user_list, USER_DB);
printf("注册成功\n");
free_user_list(user_list);
}
/*
* 用户登录菜单
*/
void login_menu() {
char id[20], pwd[20];
Node *user_list = create_userlist_head();
load_user_file(&user_list, USER_DB);
printf("\n=======用户登录=======\n");
printf("请输入用户名: ");
fgets(id, sizeof(id), stdin);
id[strcspn(id, "\n")] = '\0';
printf("请输入密码: ");
fgets(pwd, sizeof(pwd), stdin);
pwd[strcspn(pwd, "\n")] = '\0';
Node *node = find_user_byid(user_list, id);
if (node == NULL) {
printf("用户名不存在\n");
} else {
User *user = (User *)node->data;
if (strcmp(user->pwd, pwd) == 0) {
printf("登录成功\n");
strcpy(current_user_id, user->id);
user_menu(user->id);
} else {
printf("密码错误\n");
}
}
free_user_list(user_list);
}
// 添加修改密码功能
void change_password_menu(const char *user_id) {
char old_pwd[20], new_pwd[20], confirm_pwd[20];
Node *user_list = create_userlist_head();
load_user_file(&user_list, USER_DB);
printf("\n=======修改密码=======\n");
printf("用户: %s\n", user_id);
Node *node = find_user_byid(user_list, user_id);
if (node == NULL) {
printf("用户不存在\n");
free_user_list(user_list);
return;
}
printf("请输入旧密码: ");
fgets(old_pwd, sizeof(old_pwd), stdin);
old_pwd[strcspn(old_pwd, "\n")] = '\0';
User *user = (User *)node->data;
if (strcmp(user->pwd, old_pwd) != 0) {
printf("旧密码错误\n");
free_user_list(user_list);
return;
}
printf("请输入新密码: ");
fgets(new_pwd, sizeof(new_pwd), stdin);
new_pwd[strcspn(new_pwd, "\n")] = '\0';
printf("请确认新密码: ");
fgets(confirm_pwd, sizeof(confirm_pwd), stdin);
confirm_pwd[strcspn(confirm_pwd, "\n")] = '\0';
if (strcmp(new_pwd, confirm_pwd) != 0) {
printf("两次输入密码不一致\n");
free_user_list(user_list);
return;
}
strcpy(user->pwd, new_pwd);
save_user_file(user_list, USER_DB);
printf("密码修改成功\n");
free_user_list(user_list);
}
// 添加注销账号功能
void delete_account_menu(const char *user_id) {
char confirm[20];
Node *user_list = create_userlist_head();
load_user_file(&user_list, USER_DB);
printf("\n=======注销账号=======\n");
printf("警告: 此操作将永久删除您的账号!\n");
printf("用户: %s\n", user_id);
printf("确认注销账号?(输入YES确认): ");
fgets(confirm, sizeof(confirm), stdin);
confirm[strcspn(confirm, "\n")] = '\0';
if (strcmp(confirm, "YES") == 0) {
delete_user(&user_list, user_id);
save_user_file(user_list, USER_DB);
printf("账号已注销\n");
free_user_list(user_list);
return; // 返回到主菜单
} else {
printf("取消注销操作\n");
}
free_user_list(user_list);
}
/*
* 忘记密码菜单
*/
void forget_pwd_menu() {
printf("\n=======忘记密码=======\n");
printf("请联系管理员重置密码\n");
}
/*
* 主菜单
*/
void main_menu() {
int choice;
while (1) {
printf("\n=======Welcome kun_Player=======\n");
printf("1. 注册\n");
printf("2. 用户登录\n");
printf("3. 忘记密码\n");
printf("4. 退出\n");
printf("请选择: ");
scanf("%d", &choice);
getchar(); // 清除换行符
switch (choice) {
case 1:
regis_menu();
break;
case 2:
login_menu();
break;
case 3:
forget_pwd_menu();
break;
case 4:
return;
default:
printf("无效选择\n");
}
}
}
int main() {
main_menu();
return 0;
}
===================flie_service.c===============================
/*
文件传输
服务器接收客户端传输文件2.0
*/
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#define BACKLOG 3
#define PORT 7777
#define IP "127.0.0.1"
int file_access(int fd);
int file_imformation_accept(int fd,char buff[],unsigned long int *file_size);
//默认接收文件路径
static char filepath[50] = "/c_code/player_test/video/";
struct file_imformation{
char file_name[120];
unsigned long int file_length;
};
int main(int argc,char* argv[]){
int fd;
struct sockaddr_in daddr;
char buff[1024];
int err;
//建立套接字
fd = socket(AF_INET,SOCK_STREAM,0);
if(fd < 0){
printf("套接字建立失败!\n");
}
//初始化服务器地址
memset(&daddr,0,sizeof(struct sockaddr));
daddr.sin_family = AF_INET;
daddr.sin_port = htons(PORT);
daddr.sin_addr.s_addr = inet_addr(IP);
//套接字绑定ip
err = bind(fd,(struct sockaddr*)&daddr,sizeof(struct sockaddr));
if(err < 0){
printf("绑定失败\n");
}
//监听端口
err = listen(fd,BACKLOG);
if(err < 0){
printf("监听错误!\n");
}
//接受连接
socklen_t len = sizeof(struct sockaddr);
int acfd = accept(fd,(struct sockaddr*)&daddr,&len);
file_access(acfd);
close(acfd);
close(fd);
return 0;
}
//接收文件内容
int file_access(int fd){
unsigned long int size = -1;
unsigned long int recv_size = 0;
unsigned long int file_size;
char buffer[1024];
char file_url[200] = {0};
//创建并打开文件
memset(file_url,0,sizeof(file_url));
memset(buffer,0,sizeof(buffer));
//获取客户端发送信息
file_imformation_accept(fd,file_url,&file_size);
//创建接收文件
int filefd = open(file_url,O_RDWR|O_CREAT,0777);
if(filefd == -1){
perror("文件打开失败");
return -1;
}
//从套接字中读取数据并写入文件
while(size){
size = read(fd,buffer,sizeof(buffer));
if(size == -1){
printf("文件传输错误\n");
remove(file_url);
close(filefd);
return -1;
}else if(size > 0){
recv_size += size;
write(filefd,buffer,size);
memset(buffer,0,sizeof(buffer));
}else{
if(recv_size != file_size){
printf("错误:文件传输失败,文件大小不一致!\n");
remove(file_url);
}else{
printf("接收文件成功!\n");
}
close(filefd);
return 0;
}
}
}
//在接受文件内容前,接受文件信息
int file_imformation_accept(int fd,char buff[],unsigned long int *file_size){
int i = 0;
struct file_imformation file_im;
while(i < strlen(filepath)){
buff[i] = filepath[i];
i++;
}
int len = read(fd,&file_im,sizeof(struct file_imformation));
if(len <= 0){
printf("错误:接收文件信息为空");
}
printf("接收文件名称为%s\n",file_im.file_name);
printf("接收文件大小为%ld\n",file_im.file_length);
//获取文件大小
*file_size = file_im.file_length;
//获取文件名
if(NULL == strcpy(&buff[i],file_im.file_name)){
printf("错误:获取文件名失败\n");
}
printf("文件url是%s\n",buff);
return 0;
}
==================================file_client.c===================================
/*
文件传输
客户端向服务器传送文件2.0
*/
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
#define PORT 7777
#define IP "127.0.0.1"
struct file_imformation{
char file_name[120];
unsigned long int file_length;
};
int file_transfer(int fd,char* path,unsigned long int file_size);
int file_imformation_transfer(int server_fd);
void show(int count);
int main(int argc,char* argv[]){
int fd;
struct sockaddr_in daddr;
int err;
//建立套接字
fd = socket(AF_INET,SOCK_STREAM,0);
if(fd < 0){
printf("socket create fail!\n");
}
//初始化服务器地址
memset(&daddr,0,sizeof(struct sockaddr));
daddr.sin_family = AF_INET;
daddr.sin_port = htons(PORT);
daddr.sin_addr.s_addr = inet_addr(IP);
//建立连接
err = connect(fd,(struct sockaddr*)&daddr,sizeof(struct sockaddr));
if(err < 0){
printf("connect fail!\n");
}
file_imformation_transfer(fd);
close(fd);
return 0;
}
//传输文件内容
int file_transfer(int fd,char* path,unsigned long int file_size){
int size = 0;
unsigned long sum = 0;
int n = 0;
char buffer[1024];
memset(buffer,0,sizeof(buffer));
int filefd = open(path,O_RDWR);
if(filefd == -1){
perror("file open fail");
}
while(1){
size = read(filefd,buffer,sizeof(buffer));
if(size == -1){
printf("文件传输错误\n");
close(filefd);
return -1;
}else if(size > 0){
size = write(fd,buffer,size);
sum += size;
unsigned long int p = (sum * 100)/file_size;
printf("\r文件已传输%ld\%%",p);
}else{
//当读取为0时,表示文件读取完毕
printf("传输成功 %ld byte!\n",sum);
close(filefd);
return 0;
}
}
}
//在传输文件内容之前,先传送文件信息,比如文件名
int file_imformation_transfer(int server_fd){
struct file_imformation file_im;
struct stat sta;
char path[200];
memset(path,0,sizeof(path));
memset(&file_im,0,sizeof(struct file_imformation));
memset(&sta,0,sizeof(struct stat));
printf("请输入文件路径和文件名:\n");
scanf("%s",path);
/*
获取文件名
根据文件路径path确定文件名
加入输入path为"/home/my/text.txt"那么i定位到最后一个反斜杠,然后将文件名复制到file_im.file_name中
*/
int i = strlen(path) - 1;
while(path[i] != '/' && i >= 0){
i--;
}
i++;
for(int j = 0;i < strlen(path)+1;j++){
file_im.file_name[j] = path[i];
i++;
}
printf("文件名为:%s\n",file_im.file_name);
/*
文件大小的获取
*/
if(stat(path,&sta) == -1){
perror("获取文件信息错误");
return -1;
}
file_im.file_length = sta.st_size;
printf("文件大小为%ld\n",file_im.file_length);
//向服务器发送文件名
write(server_fd,&file_im,sizeof(struct file_imformation));
//开始文件传输
file_transfer(server_fd,path,sta.st_size);
return 0;
}
void show(int count){
while(count >0 ){
write(1,"#",1);
count--;
}
}
===========================================================================
[root@Redhat6 player_test]# ./ser
接收文件名称为upload.mp4
接收文件大小为2892683
文件url是/c_code/player_test/video/upload.mp4
接收文件成功!
[root@Redhat6 player_test]# cd video/
[root@Redhat6 video]# ls
upload.mp4
[root@Redhat6 video]# ll upload.mp4
-rwxr-xr-x 1 root root 2892683 7月 29 10:02 upload.mp4
[root@Redhat6 video]# ll /tools/upload.mp4
-rwxr-xr-x 1 root root 2892683 7月 28 19:31 /tools/upload.mp4
[root@Redhat6 player_test]# ./cli
请输入文件路径和文件名:
/tools/upload.mp4
文件名为:upload.mp4
文件大小为2892683
文件已传输100%传输成功 2892683 byte!
此函数能实现文件的完整传输,请参考file_service.c和file_client.c仿照其处理逻辑完善
该播放器的文件上传,下载模块
最新发布