一.项目课题 <基于TCP的文件传输协议实现>
客户端代码
需要cJSON.c文件和cJSON.h文件
在这里插入代码片#include "myheadth.h"
#include "myfun.h"#define TIME 10
int sockfd;
void heartbeat(int signum)
{cJSON* root = cJSON_CreateObject();cJSON_AddStringToObject(root,"request","heartbeat"); char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd,JSstr1,strlen(JSstr1),0);cJSON_Delete(root);free(JSstr1);root = NULL;alarm(TIME);
}int main(int argc,char **argv)
{if(argc < 3){fprintf(stderr,"Usage <%s SERIP SERPOST>\n",argv[0]);return -1;}/* 1. 创建套接字*/sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd == -1){perror("socket");return -1;}/* 2.连接服务器*/sin_t server = {AF_INET};server.sin_port = htons(atoi(argv[2]));server.sin_addr.s_addr = inet_addr(argv[1]);int len = sizeof(sin_t);connect(sockfd,(sad_t*)&server,len);//设置心跳定时器signal(SIGALRM,heartbeat);alarm(TIME);//函数声明
int findall_directory(int sockfd);
int upload_directory(int sockfd);
int download_directory(int sockfd);
void menu_2();while(1){menu();printf("请输入你的选择:");int choice;scanf("%d",&choice);getchar();if(choice == 0){quit(sockfd);alarm(TIME);break;}int flag = 0;switch(choice){case 1://用户登录user_login(sockfd);break;case 2://用户注册user_register(sockfd);break;case 3://用户注销user_logout(sockfd);break; case 4:// 进入二级菜单menu_2();default:puts("输入有误请重新输入");flag = 1;break;}if(flag)continue;/* 4. 接收服务端消息*/char bufs[512] = {0};recv(sockfd,bufs,sizeof(bufs)-1,0);cJSON* servers = cJSON_Parse(bufs);if(servers == NULL){puts("malloc node for parse failed");return -1;}alarm(TIME);cJSON* itemRever = cJSON_GetObjectItem(servers,"rever");printf("%s\n",itemRever -> valuestring);if(strcmp(itemRever -> valuestring,"登录成功!") == 0){while(1){menu_2();printf("请输入你的选择:");int choice2;scanf("%d",&choice2);getchar();if(choice2 == 0){alarm(TIME);break;}int flag2 = 0;switch(choice2){case 1://浏览所有目录信息findall_directory(sockfd);//需要修改break;case 2://上传所有信息upload_directory(sockfd);break;case 3://下载所有信息download_directory(sockfd);break;case 4://返回上一级return 0;break;default:puts("输入有误请重新输入");flag = 1;break;}alarm(TIME);if(flag2)continue;}}cJSON_Delete(servers);servers = NULL;}/* 5. 关闭套接字*/close(sockfd);return 0;
}
登录界面以及功能实现
在这里插入代码片#include "myfun.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include "cJSON.h"
void menu()
{printf("\n");printf("\033[1;36m");printf("================消息系统============\n");printf("1. 用户登录\n");printf("2. 用户注册\n");printf("3. 用户注销\n");printf("4. 进入功能\n");printf("0. 退出\n");printf("===================================\n");printf("\033[0m");printf("\n");
}void menu_2()
{printf("\n");printf("\033[1;36m");printf("================消息系统============\n");printf("1. 浏览所有目录信息\n");printf("2. 上传所有目录信息\n");printf("3. 下载所有目录信息\n");printf("0. 返回上一级\n");printf("===================================\n");printf("\033[0m");printf("\n");
}//用户登陆
int user_login(int sockfd)
{char user[20] = {0},passwd[8] = {0};printf("请输入用户名:");fgets(user,20,stdin);user[strlen(user)-1] = 0;printf("请输入密码:");fgets(passwd,8,stdin);passwd[strlen(passwd)-1] = 0;cJSON* root = cJSON_CreateObject();if(root == NULL){puts("malloc root node failed");return -1;}cJSON_AddStringToObject(root,"request","login"); cJSON_AddStringToObject(root,"user",user); cJSON_AddStringToObject(root,"passwd",passwd);char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd,JSstr1,strlen(JSstr1),0);cJSON_Delete(root);free(JSstr1);root = NULL;return 0;
}//用户注册
int user_register(int sockfd)
{char user[20] = {0},passwd[8] = {0};printf("请输入用户名:");fgets(user,20,stdin);user[strlen(user)-1] = 0;// getchar();printf("请输入密码:");fgets(passwd,8,stdin);passwd[strlen(passwd)-1] = 0;sleep(3);cJSON* root = cJSON_CreateObject();if(root == NULL){puts("malloc root node failed");return -1;}cJSON_AddStringToObject(root,"request","register"); cJSON_AddStringToObject(root,"user",user); cJSON_AddStringToObject(root,"passwd",passwd);char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd,JSstr1,strlen(JSstr1),0);cJSON_Delete(root);free(JSstr1);root = NULL;return 0;
}//用户注销
int user_logout(int sockfd)
{char user[20] = {0},passwd[8] = {0};printf("请输入用户名:");fgets(user,20,stdin);user[strlen(user)-1] = 0;printf("请输入密码:");fgets(passwd,8,stdin);passwd[strlen(passwd)-1] = 0;cJSON* root = cJSON_CreateObject();if(root == NULL){puts("malloc root node failed");return -1;}cJSON_AddStringToObject(root,"request","logout"); cJSON_AddStringToObject(root,"user",user); cJSON_AddStringToObject(root,"passwd",passwd);char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd,JSstr1,strlen(JSstr1),0);cJSON_Delete(root);free(JSstr1);root = NULL;return 0;
}// 浏览所有目录以及文件信息
int findall_directory(int sockfd) {cJSON* root = cJSON_CreateObject();if (root == NULL) {puts("malloc root node failed");return -1;}// 修改请求类型为 findall_directorycJSON_AddStringToObject(root, "request", "findall_directory");char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd, JSstr1, strlen(JSstr1), 0);cJSON_Delete(root);free(JSstr1);root = NULL;char bufs[1024 * 1024] = {0};recv(sockfd, bufs, sizeof(bufs) - 1, 0);cJSON* directories = cJSON_Parse(bufs);if (directories == NULL) {puts("malloc node for parse failed");return -1;}cJSON* itemReverse = cJSON_GetObjectItem(directories, "reverse");if (strcmp(itemReverse->valuestring, "null") == 0) {cJSON_Delete(directories);directories = NULL;printf("未有目录信息\n");return 0;}// 解析目录信息cJSON* itemType = cJSON_GetObjectItem(directories, "type");cJSON* itemTitle = cJSON_GetObjectItem(directories, "title");cJSON* itemContent = cJSON_GetObjectItem(directories, "content");cJSON* itemData = cJSON_GetObjectItem(directories, "directory");// 打印目录信息printf("%-18s\t%-70s\t%s\n", itemType->valuestring, itemTitle->valuestring, itemContent->valuestring);if (cJSON_IsArray(itemData)) {int n = cJSON_GetArraySize(itemData);for (int i = 0; i < n; i++) {cJSON* subItem = cJSON_GetArrayItem(itemData, i);cJSON* itemData_name = cJSON_GetObjectItem(subItem, "name");cJSON* itemData_size = cJSON_GetObjectItem(subItem, "size");cJSON* itemData_created_date = cJSON_GetObjectItem(subItem, "created_date");// 打印目录的详细信息printf("%-30s\t%-10d\t%s\n", itemData_name->valuestring, itemData_size->valueint, itemData_created_date->valuestring);}}cJSON_Delete(directories);directories = NULL;return 0;
}// 假设的函数,用于收集目录和文件信息到 cJSON 对象
cJSON* collect_directory_and_file_info() {cJSON* root = cJSON_CreateObject();// 示例:添加一些目录和文件信息cJSON* directories = cJSON_AddArrayToObject(root, "directories");cJSON* files = cJSON_AddArrayToObject(root, "files");// 假设添加一个目录信息cJSON* dir1 = cJSON_CreateObject();cJSON_AddStringToObject(dir1, "name", "/path/to/directory");cJSON_AddNumberToObject(dir1, "size", 1024);cJSON_AddStringToObject(dir1, "created_date", "2025-01-12");cJSON_AddItemToArray(directories, dir1);// 假设添加一个文件信息cJSON* file1 = cJSON_CreateObject();cJSON_AddStringToObject(file1, "name", "/path/to/file.txt");cJSON_AddNumberToObject(file1, "size", 512);cJSON_AddStringToObject(file1, "created_date", "2025-01-11");cJSON_AddItemToArray(files, file1);return root;
}// 上传所有目录以及文件信息
int upload_directory(int sockfd) {cJSON* root = cJSON_CreateObject();if (root == NULL) {puts("malloc root node failed");return -1;}// 修改请求类型为 upload_directorycJSON_AddStringToObject(root, "request", "upload_directory");// 收集目录和文件信息cJSON* directory_and_file_info = collect_directory_and_file_info();cJSON_AddItemToObject(root, "data", directory_and_file_info);char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd, JSstr1, strlen(JSstr1), 0);cJSON_Delete(root);free(JSstr1);root = NULL;// 接收服务器的响应(可选)char bufs[1024 * 1024] = {0};recv(sockfd, bufs, sizeof(bufs) - 1, 0);cJSON* response = cJSON_Parse(bufs);if (response == NULL) {puts("malloc node for parse failed");return -1;}cJSON* itemReverse = cJSON_GetObjectItem(response, "reverse");if (strcmp(itemReverse->valuestring, "null") == 0) {cJSON_Delete(response);response = NULL;printf("上传失败\n");return -1;} else {printf("上传成功\n");}cJSON_Delete(response);response = NULL;return 0;
}// 下载所有目录及文件信息
int download_directory(int sockfd) {cJSON* root = cJSON_CreateObject();if (root == NULL) {puts("malloc root node failed");return -1;}// 修改请求类型为 download_directorycJSON_AddStringToObject(root, "request", "download_directory");char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd, JSstr1, strlen(JSstr1), 0);cJSON_Delete(root);free(JSstr1);root = NULL;// 接收服务器的响应char bufs[1024 * 1024] = {0};recv(sockfd, bufs, sizeof(bufs) - 1, 0);cJSON* response = cJSON_Parse(bufs);if (response == NULL) {puts("malloc node for parse failed");return -1;}cJSON* itemReverse = cJSON_GetObjectItem(response, "reverse");if (strcmp(itemReverse->valuestring, "null") == 0) {cJSON_Delete(response);response = NULL;printf("没有可下载的目录或文件信息\n");return 0;} else {printf("开始下载目录和文件信息\n");}// 解析并处理下载的目录和文件信息cJSON* directories = cJSON_GetObjectItem(response, "directories");cJSON* files = cJSON_GetObjectItem(response, "files");if (cJSON_IsArray(directories)) {int n = cJSON_GetArraySize(directories);for (int i = 0; i < n; i++) {cJSON* subItem = cJSON_GetArrayItem(directories, i);cJSON* dir_name = cJSON_GetObjectItem(subItem, "name");cJSON* dir_size = cJSON_GetObjectItem(subItem, "size");cJSON* dir_created_date = cJSON_GetObjectItem(subItem, "created_date");// 打印目录信息,可添加下载逻辑printf("Directory: %s, Size: %d, Created Date: %s\n", dir_name->valuestring, dir_size->valueint, dir_created_date->valuestring);}}if (cJSON_IsArray(files)) {int m = cJSON_GetArraySize(files);for (int i = 0; i < m; i++) {cJSON* subItem = cJSON_GetArrayItem(files, i);cJSON* file_name = cJSON_GetObjectItem(subItem, "name");cJSON* file_size = cJSON_GetObjectItem(subItem, "size");cJSON* file_created_date = cJSON_GetObjectItem(subItem, "created_date");// 打印文件信息,可添加下载逻辑printf("File: %s, Size: %d, Created Date: %s\n", file_name->valuestring, file_size->valueint, file_created_date->valuestring);}}cJSON_Delete(response);response = NULL;return 0;
}int quit(int sockfd)
{cJSON* root = cJSON_CreateObject();if(root == NULL){puts("malloc root node failed");return -1;}cJSON_AddStringToObject(root,"request","quit"); char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd,JSstr1,strlen(JSstr1),0);cJSON_Delete(root);free(JSstr1);root = NULL;return 0;
}
需要引用cJSON文件 json文件:
服务器端自己构建函数mufun.c
#include "myfun.h"
#include<dirent.h>
#include<sys/stat.h>typedef unsigned long long ull;//数据库连接
static MYSQL* mysql_connect()
{//数据库初始化MYSQL* mysql = mysql_init(NULL);if(mysql == NULL){fprintf(stderr,"mysql_init初始化失败\n");return NULL;}mysql_set_character_set(mysql,"utf8");//数据库连接if(NULL == mysql_real_connect(mysql,"localhost","root","123456","xiaohua",0,NULL,0)){fprintf(stderr,"conn:%s\n",mysql_error(mysql));mysql_close(mysql);return NULL; }return mysql;
}//登录
int login(const char* user,const char* passwd)
{MYSQL* mysql = mysql_connect();char sql[128] = {0};sprintf(sql,"select * from users");if(mysql_real_query(mysql,sql,strlen(sql))){fprintf(stderr,"exec:%s\n",mysql_error(mysql));mysql_close(mysql);return 0; }//获得字符集MYSQL_RES *result = mysql_store_result(mysql);if(result == NULL){fprintf(stderr,"store res:%s\n",mysql_error(mysql));mysql_close(mysql);return 0; }ull rnum = mysql_num_rows(result);//记录数量for(int i = 0; i < rnum; i++){MYSQL_ROW row = mysql_fetch_row(result);if(strcmp(row[0],user) == 0 && strcmp(row[1],passwd) == 0){mysql_free_result(result);char sql2[128] = {0};sprintf(sql2,"update users set state = 1 where username = '%s'",user);mysql_real_query(mysql,sql2,strlen(sql2));mysql_close(mysql);return 1;}}mysql_free_result(result);mysql_close(mysql);return 0;
}//注册
int regist(const char* user,const char* passwd)
{MYSQL* mysql = mysql_connect();char sql1[128] = {0};sprintf(sql1,"create table if not exists users(username varchar(20) primary key,passwd varchar(8) not null,state int default 0)default charset=utf8");if(mysql_real_query(mysql,sql1,strlen(sql1))){fprintf(stderr,"exec:%s\n",mysql_error(mysql));mysql_close(mysql);return 0; }char sql2[128] = {0};sprintf(sql2,"insert into users(username,passwd) values('%s','%s')",user,passwd);if(mysql_real_query(mysql,sql2,strlen(sql2))){fprintf(stderr,"exec:%s\n",mysql_error(mysql));mysql_close(mysql);return 0; }mysql_close(mysql);return 1;
}//注销
int logout(const char* user,const char* passwd)
{MYSQL* mysql = mysql_connect();char sql[128] = {0};sprintf(sql,"select * from users");if(mysql_real_query(mysql,sql,strlen(sql))){fprintf(stderr,"exec:%s\n",mysql_error(mysql));mysql_close(mysql);return 0; }//获得字符集MYSQL_RES *result = mysql_store_result(mysql);if(result == NULL){mysql_close(mysql);return 0; }ull rnum = mysql_num_rows(result);//记录数量for(int i = 0; i < rnum; i++){MYSQL_ROW row = mysql_fetch_row(result);if(strcmp(row[0],user) == 0 && strcmp(row[1],passwd) == 0){char sql2[128] = {0};sprintf(sql2,"delete from users where username = '%s'",user);if(mysql_real_query(mysql,sql2,strlen(sql2))){fprintf(stderr,"exec:%s\n",mysql_error(mysql));mysql_close(mysql);return 0; }mysql_free_result(result);mysql_close(mysql);return 1;}}mysql_free_result(result);mysql_close(mysql);return 0;
}// 浏览所有目录文件信息
int findall_directory(int sockfd) {MYSQL* mysql = mysql_connect();if (mysql == NULL) {fprintf(stderr, "Failed to connect to MySQL database.\n");return -1;}char sql1[128] = {0};cJSON* root = cJSON_CreateObject();// 假设表名为 directories_files,包含目录和文件信息sprintf(sql1, "select * from xiaohua");if (mysql_real_query(mysql, sql1, strlen(sql1))) {fprintf(stderr, "Failed to execute SQL query: %s\n", mysql_error(mysql));mysql_close(mysql);cJSON_AddStringToObject(root, "reverse", "null");char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd, JSstr1, strlen(JSstr1), 0);return 0;}MYSQL_RES *result = mysql_store_result(mysql);if (result == NULL) {fprintf(stderr, "Failed to store query result: %s\n", mysql_error(mysql));mysql_close(mysql);cJSON_AddStringToObject(root, "reverse", "null");char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd, JSstr1, strlen(JSstr1), 0);return -1;}uint32_t fnum = mysql_num_fields(result);my_ulonglong rnum = mysql_num_rows(result);// 获得列名MYSQL_FIELD *fields = mysql_fetch_fields(result);cJSON_AddStringToObject(root, "reverse", "not null");// 假设表的列名为 dir_name, file_name, size, created_datecJSON_AddStringToObject(root, "dir_name", fields[0].name);cJSON_AddStringToObject(root, "file_name", fields[1].name);cJSON_AddStringToObject(root, "size", fields[2].name);cJSON_AddStringToObject(root, "created_date", fields[3].name);cJSON* array = cJSON_CreateArray();for (int i = 0; i < rnum; i++) {cJSON* obj = cJSON_CreateObject();MYSQL_ROW row = mysql_fetch_row(result);for (int j = 0; j < fnum; j++) {cJSON_AddStringToObject(obj, fields[j].name, row[j]);}cJSON_AddItemToArray(array, obj);}cJSON_AddItemToObject(root, "data", array);mysql_free_result(result);mysql_close(mysql);char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd, JSstr1, strlen(JSstr1), 0);cJSON_Delete(root);return 0;
}// 上传所有目录文件
int upload_directory(int sockfd) {cJSON* root = cJSON_CreateObject();cJSON* array = cJSON_CreateArray();// 打开当前目录DIR* dir = opendir(".");if (dir == NULL) {perror("opendir");cJSON_AddStringToObject(root, "reverse", "null");char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd, JSstr1, strlen(JSstr1), 0);cJSON_Delete(root);return -1;}struct dirent* entry;while ((entry = readdir(dir))!= NULL) {if (entry->d_name[0] == '.') continue; // 跳过隐藏文件和目录struct stat st;if (stat(entry->d_name, &st) == -1) {perror("stat");continue;}cJSON* obj = cJSON_CreateObject();cJSON_AddStringToObject(obj, "name", entry->d_name);cJSON_AddNumberToObject(obj, "size", (int)st.st_size);cJSON_AddStringToObject(obj, "type", S_ISDIR(st.st_mode)? "directory" : "file");// 获取文件的创建时间char time_str[20];strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&st.st_ctime));cJSON_AddStringToObject(obj, "created_date", time_str);cJSON_AddItemToArray(array, obj);}closedir(dir);cJSON_AddItemToObject(root, "data", array);cJSON_AddStringToObject(root, "request", "upload_directory");char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd, JSstr1, strlen(JSstr1), 0);cJSON_Delete(root);free(JSstr1);return 0;
}// 下载所有目录文件信息
int download_directory(int sockfd) {cJSON* root = cJSON_CreateObject();cJSON_AddStringToObject(root, "request", "download_directory");// 将请求信息发送到服务器char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd, JSstr1, strlen(JSstr1), 0);cJSON_Delete(root);free(JSstr1);// 接收服务器的响应char buffer[4096];int bytes_received = recv(sockfd, buffer, sizeof(buffer) - 1, 0);if (bytes_received <= 0) {perror("recv");return -1;}buffer[bytes_received] = '\0';// 解析服务器的响应cJSON* response = cJSON_Parse(buffer);if (response == NULL) {fprintf(stderr, "Failed to parse JSON response\n");return -1;}// 检查服务器是否返回错误信息cJSON* reverse = cJSON_GetObjectItem(response, "reverse");if (reverse!= NULL && strcmp(reverse->valuestring, "null") == 0) {fprintf(stderr, "Server returned an error\n");cJSON_Delete(response);return -1;}// 假设服务器返回的数据在 "data" 键下cJSON* data = cJSON_GetObjectItem(response, "data");if (data == NULL ||!cJSON_IsArray(data)) {fprintf(stderr, "Invalid data format from server\n");cJSON_Delete(response);return -1;}// 遍历服务器返回的目录文件信息int array_size = cJSON_GetArraySize(data);for (int i = 0; i < array_size; i++) {cJSON* item = cJSON_GetArrayItem(data, i);if (item == NULL) continue;cJSON* name = cJSON_GetObjectItem(item, "name");cJSON* size = cJSON_GetObjectItem(item, "size");cJSON* type = cJSON_GetObjectItem(item, "type");cJSON* created_date = cJSON_GetObjectItem(item, "created_date");if (name == NULL || size == NULL || type == NULL || created_date == NULL) {fprintf(stderr, "Invalid item format from server\n");continue;}// 这里可以添加逻辑将文件或目录信息保存到本地// 例如,打印文件或目录信息printf("Name: %s, Size: %d, Type: %s, Created Date: %s\n", name->valuestring, size->valueint, type->valuestring, created_date->valuestring);}cJSON_Delete(response);return 0;
}int check(int sockfd,const char* user)
{MYSQL* mysql = mysql_connect();char sql1[128] = {0};cJSON* root = cJSON_CreateObject();sprintf(sql1,"select * from unread where username = '%s'",user);if(mysql_real_query(mysql,sql1,strlen(sql1))){mysql_close(mysql);cJSON_AddStringToObject(root,"reverse","null");char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd,JSstr1,strlen(JSstr1),0);return 0; }MYSQL_RES *result = mysql_store_result(mysql);if(result == NULL){mysql_close(mysql);cJSON_AddStringToObject(root,"reverse","null");char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd,JSstr1,strlen(JSstr1),0);return -1; }uint32_t fnum = mysql_num_fields(result);my_ulonglong rnum = mysql_num_rows(result);//获得列名MYSQL_FIELD *fields = mysql_fetch_fields(result);cJSON_AddStringToObject(root,"reverse","not null");cJSON_AddStringToObject(root,"type",fields[1].name);cJSON_AddStringToObject(root,"title",fields[2].name);cJSON_AddStringToObject(root,"content",fields[3].name);cJSON* array = cJSON_CreateArray();for(int i = 0; i < rnum; i++){MYSQL_ROW row = mysql_fetch_row(result);cJSON* obj = cJSON_CreateObject();for(int j = 1; j < fnum; j++){cJSON_AddStringToObject(obj,fields[j].name,row[j]);}cJSON_AddItemToArray(array,obj);}cJSON_AddItemToObject(root,"data",array);mysql_free_result(result);char sql2[128] = {0};sprintf(sql2,"delete from unread where username = '%s'",user);mysql_real_query(mysql,sql2,strlen(sql2));mysql_close(mysql);char* JSstr1 = cJSON_PrintUnformatted(root);send(sockfd,JSstr1,strlen(JSstr1),0);return 0;
}//退出
int quit(const char* user)
{MYSQL* mysql = mysql_connect();char sql[128] = {0};sprintf(sql,"update users set state = 0 where username = '%s'",user);if(mysql_real_query(mysql,sql,strlen(sql))){fprintf(stderr,"exec:%s\n",mysql_error(mysql));mysql_close(mysql);return -1; }mysql_close(mysql);return 0;
}
服务器端fock.c
在这里插入代码片#include "mysock.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include "cJSON.h"
#include <dirent.h>
#include <sys/stat.h>
#include <arpa/inet.h>// 假设以下函数在其他地方实现,在此声明它们
int findall_directory(int sockc);
int download_directory(int sockc);
int upload_directory(int sokc);
int login(const char *user, const char *passwd);
int regist(const char *user, const char *passwd);
int logout(const char *user, const char *passwd);
int quit(const char *user);/*监听函数,返回监听套接字*/
int mysock_init(const char *Ip, const char *Port)
{/* 1. 创建套接字*/int sockl = socket(AF_INET, SOCK_STREAM, 0);if (sockl == -1)return -1;/* 2. 绑定自己地址信息*/struct sockaddr_in server = {0};server.sin_family = AF_INET;server.sin_port = htons(atoi(Port));inet_pton(AF_INET, Ip, &server.sin_addr); //将字符串变成网络字节序socklen_t len = sizeof(server);if (-1 == bind(sockl, (struct sockaddr *)&server, len)){close(sockl);return -1;}/* 3. 监听客户端连接*/if (-1 == listen(sockl, 5)){close(sockl);return -1;}//返回监听套接字return sockl;
}char user_name[20] = {0};/*连接函数,接收客户端连接*/
int mysock_accept(int sockl)
{struct sockaddr_in peer = {0}; //对方socklen_t len = sizeof(peer);int sockc = accept(sockl, (struct sockaddr *)&peer, &len);if (sockc == -1)return -1;char IP[INET_ADDRSTRLEN + 1];inet_ntop(AF_INET, &peer.sin_addr, IP, INET_ADDRSTRLEN);printf("[%s:%d]已连接\n", IP, ntohs(peer.sin_port));//生成连接套接字return sockc;
}/* 接收客户端信息的函数*/
void *from_client(void *argp)
{int sockc = *(int *)argp;struct sockaddr_in peer = {0};socklen_t len = sizeof(peer);getpeername(sockc, (struct sockaddr *)&peer, &len);// 获取客户端地址信息while (1){char str[512] = {0};int n = recv(sockc, str, sizeof(str), 0);if (n == 0){printf("客户端[%s:%d]已断开连接\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));quit(user_name);break;}/* 处理客户端请求*/to_client(str, sockc);}return NULL;
}void to_client(const char *jsStr, int sockc)
{/* 给客户端发消息*/cJSON *root = cJSON_Parse(jsStr);if (root == NULL)return;cJSON *itemRequest = cJSON_GetObjectItem(root, "request");cJSON *itemUser = cJSON_GetObjectItem(root, "user");cJSON *itemPasswd = cJSON_GetObjectItem(root, "passwd");//登录if (strcmp(itemRequest->valuestring, "login") == 0){puts("用户登录");char *res[] = {"登录失败!", "登录成功!"};int i = login(itemUser->valuestring, itemPasswd->valuestring);cJSON *rever = cJSON_CreateObject();if (rever == NULL)return;if (i == 1){memset(user_name, 0, 20);strcpy(user_name, itemUser->valuestring);}cJSON_AddStringToObject(rever, "rever", res[i]);char *JSstr1 = cJSON_PrintUnformatted(rever);send(sockc, JSstr1, strlen(JSstr1), 0);cJSON_Delete(rever);}//注册else if (strcmp(itemRequest->valuestring, "register") == 0){puts("用户注册");char *res[] = {"注册失败!", "注册成功,请登录..."};int i = regist(itemUser->valuestring, itemPasswd->valuestring);cJSON *rever = cJSON_CreateObject();if (rever == NULL)return;cJSON_AddStringToObject(rever, "rever", res[i]);char *JSstr1 = cJSON_PrintUnformatted(rever);send(sockc, JSstr1, strlen(JSstr1), 0);cJSON_Delete(rever);}//注销else if (strcmp(itemRequest->valuestring, "logout") == 0){puts("用户注销");char *res[] = {"注销失败!", "注销成功!"};int i = logout(itemUser->valuestring, itemPasswd->valuestring);cJSON *rever = cJSON_CreateObject();if (rever == NULL)return;cJSON_AddStringToObject(rever, "rever", res[i]);char *JSstr1 = cJSON_PrintUnformatted(rever);send(sockc, JSstr1, strlen(JSstr1), 0);cJSON_Delete(rever);}// 浏览所有目录文件信息else if (strcmp(itemRequest->valuestring, "findall_directory") == 0){puts("浏览所有目录文件信息");findall_directory(sockc);}// 上传目录文件信息else if (strcmp(itemRequest->valuestring, "upload_directory") == 0){puts("上传目录文件信息");int upload_directory(int sockc) {cJSON *root = cJSON_CreateObject();cJSON *array = cJSON_CreateArray();DIR *dir = opendir(".");if (dir == NULL) {perror("opendir");cJSON_AddStringToObject(root, "reverse", "null");char *JSstr = cJSON_PrintUnformatted(root);send(sockc, JSstr, strlen(JSstr), 0);cJSON_Delete(root);free(JSstr);return -1;}struct dirent *entry;while ((entry = readdir(dir))!= NULL) {if (entry->d_name[0] == '.') continue;struct stat st;if (stat(entry->d_name, &st) == -1) {perror("stat");continue;}cJSON *obj = cJSON_CreateObject();cJSON_AddStringToObject(obj, "name", entry->d_name);cJSON_AddNumberToObject(obj, "size", (int)st.st_size);cJSON_AddStringToObject(obj, "type", S_ISDIR(st.st_mode)? "directory" : "file");cJSON_AddItemToArray(array, obj);}closedir(dir);cJSON_AddItemToObject(root, "data", array);cJSON_AddStringToObject(root, "request", "upload_directory");char *JSstr = cJSON_PrintUnformatted(root);send(sockc, JSstr, strlen(JSstr), 0);cJSON_Delete(root);free(JSstr);return 0;}upload_directory(sockc);}// 下载所有目录信息else if (strcmp(itemRequest->valuestring, "download_directory") == 0){puts("下载所有目录信息");// 假设 download_directory 函数的参数为 sockcdownload_directory(sockc);}//检测是否退出else if (strcmp(itemRequest->valuestring, "quit") == 0){quit(user_name);}//心跳检测机制else if (strcmp(itemRequest->valuestring, "heartbeat") == 0){struct sockaddr_in peer = {0}; //对方socklen_t len = sizeof(peer);getpeername(sockc, (struct sockaddr *)&peer, &len);char IP[INET_ADDRSTRLEN + 1];inet_ntop(AF_INET, &peer.sin_addr, IP, INET_ADDRSTRLEN);printf("[%s:%d]还在连接中\n", IP, ntohs(peer.sin_port));}cJSON_Delete(root);
}
服务器端 server.c
#include "myfun.h"
#include "mysock.h"
#include "pthreadpool.h"int main(int argc,char **argv)
{if(argc < 3){fprintf(stderr,"Usage <%s SERIP SERPOST>\n",argv[0]);return -1;}//调用函数threadpool_t pool;threadpool_init(&pool,8,10);/* 1. 调用监听函数*/int sockl = mysock_init(argv[1],argv[2]);if(sockl == -1){perror("mysock_init");return -1;}while(1){/* 2.调用连接函数,接收客户端连接*/int sockc = mysock_accept(sockl);if(sockc == -1)continue;threadpool_addtask(&pool,from_client,(void*)(uint64_t)sockc);}return 0;
}
服务器pthreadPool.c
#include "pthreadpool.h"
#include <stdlib.h>void* thread_fun(void *argp)
{threadpool_t* pool = (threadpool_t*)argp;task_t *p = NULL;while(1){//互斥锁pthread_mutex_lock(&pool->mutex);//判断队列情况//任务队列为空等待while(pool -> queue_num == 0)pthread_cond_wait(&pool->queue_empty,&pool->mutex);//任务队列不为空,被线程池中线程竞争p = pool -> head;pool -> queue_num--;//表示任务队列只有一个节点if(pool -> queue_num == 0)pool -> head = pool -> tail = NULL;elsepool -> head = p -> next;//判断任务队列是否为满通知其他线程if(pool->queue_num == pool -> queue_max_size -1)pthread_cond_signal(&pool->queue_full);pthread_mutex_unlock(&pool->mutex);//调用函数(*(p -> taskfun))(p -> argp);//调用完毕回收资源free(p);p = NULL;}
}
相关文章:
一.项目课题 <基于TCP的文件传输协议实现>
客户端代码 需要cJSON.c文件和cJSON.h文件 在这里插入代码片#include "myheadth.h" #include "myfun.h"#define TIME 10 int sockfd; void heartbeat(int signum) {cJSON* root cJSON_CreateObject();cJSON_AddStringToObject(root,"request"…...
【数据结构学习笔记】19:跳表(SkipList)
介绍 跳表是一个能在 O ( n l o g n ) O(nlogn) O(nlogn)时间完成查找、插入、删除的数据结构,相比于树形结构优点就是很好写(所以也用于实现Redis ZSet)。其核心思想就是维护一个元素有序的,能随机提升索引层数的链表。最下面一…...
Cocos Creator 3.8 修改纹理像素值
修改的代码: import { _decorator, Component, RenderTexture, Sprite, Texture2D, ImageAsset, SpriteFrame, Vec2, gfx, director, log, math, v2 } from cc;const { ccclass, property } _decorator;ccclass(GradientTransparency) export class GradientTrans…...
【Linux】网络层
目录 IP协议 协议头格式 网段划分 2中网段划分的方式 为什么要进行网段划分 特殊的IP地址 IP地址的数量限制 私有IP地址和公有IP地址 路由 IP协议 在通信时,主机B要把数据要给主机C,一定要经过一条路径选择,为什么经过路由器G后&…...
单片机Day1
目录 一.什么是单片机? 二.单片机的组成 三.封装形式 四.优势 五.分类 通用型: 专用型: 按处理的二进制位可以分为: 六.应用: 七.发展趋势 1.增加CPU的数据总线宽度。 2.存储器的发展。 3.片内1/0的改进 …...
django基于 Python 的考研学习系统的设计与实现
以下是对Django基于Python的考研学习系统的设计与实现: 一、系统概述 Django基于Python的考研学习系统是一个为考研学子提供一站式学习辅助的平台。它整合了丰富的学习资源、学习计划制定、学习进度跟踪以及交流互动等功能,旨在满足考生在备考过程中的…...
openCvSharp 计算机视觉图片找茬
一、安装包 <PackageReference Include"OpenCvSharp4" Version"4.10.0.20241108" /> <PackageReference Include"OpenCvSharp4.runtime.win" Version"4.10.0.20241108" /> 二、准备两张图片 三、编写代码 using OpenCv…...
深入学习 Python 爬虫:从基础到实战
深入学习 Python 爬虫:从基础到实战 前言 Python 爬虫是一个强大的工具,可以帮助你从互联网上抓取各种数据。无论你是数据分析师、机器学习工程师,还是对网络数据感兴趣的开发者,爬虫都是一个非常实用的技能。在本文中ÿ…...
【Web安全】SQL 注入攻击技巧详解:UNION 注入(UNION SQL Injection)
【Web安全】SQL 注入攻击技巧详解:UNION 注入(UNION SQL Injection) 引言 UNION注入是一种利用SQL的UNION操作符进行注入攻击的技术。攻击者通过合并两个或多个SELECT语句的结果集,可以获取数据库中未授权的数据。这种注入技术要…...
【DAPM杂谈之一】DAPM作用与内核文档解读
本文主要分析DAPM的设计与实现 内核的版本是:linux-5.15.164,下载链接: Linux内核下载 主要讲解有关于DAPM相关的知识,会给出一些例程并分析内核如何去实现的 /****************************************************************…...
计算机网络之---防火墙与入侵检测系统(IDS)
防火墙与入侵检测系统(IDS) 防火墙(Firewall) 和 入侵检测系统(IDS, Intrusion Detection System) 都是网络安全的关键组件,但它们的作用、功能和工作方式有所不同。 防火墙 防火墙是网络安全的一种设备或软件&#…...
HTML中meta的用法
学习网络空间安全专业,每个人有每个人的学法和选择。不论他选择什么,哪都是他自己的选择,这就是大多数视频教学的博主教学的步骤都不同原因之一。有人选择丢掉大部分理论直接学习网安,而我,选择了捡起大部分理论学习网…...
前端学习-事件流,事件捕获,事件冒泡以及阻止冒泡以及相应案例(二十八)
目录 前言 事件流与两个阶段说明 说明 事件捕获 目标 说明 事件冒泡 目标 事件冒泡概念 简单理解 阻止冒泡 目标 语法 注意 综合示例代码 总结 前言 梳洗罢,独倚望江楼。过尽千帆皆不是,斜晖脉脉水悠悠。肠断白蘋洲 事件流与两个阶段说明…...
国产OS移植工业物联网OPC-UA协议
国家对于工业互联网、基础软件等关键领域的重视程度不断提升,为工业领域的硬件与软件国产化提供了坚实的政策保障。国产操作系统对工业物联网的一些重要领域的适配支持一直在推进。本次通过国产UOS系统移植测试OPC-UA协议。 1、OPC UA通信协议 OPC UA 协议…...
第25章 汇编语言--- 信号量与互斥锁
信号量(Semaphore)和互斥锁(Mutex,全称Mutual Exclusion Object)是两种用于管理对共享资源的访问的同步机制。它们在多线程或多进程编程中非常重要,可以确保同一时间只有一个线程或进程能够访问特定的资源&…...
写个自己的vue-cli
写个自己的vue-cli 1.插件代码2. 发布流程3. 模板代码讲解3.1 vue2模板的运行流程:3.2 vue3模板的运行流程: 1.插件代码 写一个自己的vue-cli插件 插件地址:插件地址 流程: 实现简单版 vue-cli 步骤文档1. 项目初始化 - 创建项目文件夹 qsl-vue-cli - …...
使用new Vue创建Vue 实例并使用$mount挂载到元素上(包括el选项和$mount区别)
new Vue({...}) 是创建一个新的 Vue 实例的方式。你可以通过传递一个选项对象来配置这个实例。常见的选项包括: •data:定义组件的数据属性。 •el:指定 Vue 实例应该挂载到哪个 DOM 元素上(通常是一个选择器字符串,如…...
【理论】测试框架体系TDD、BDD、ATDD、MBT、DDT介绍
一、测试框架是什么 测试框架是一组用于创建和设计测试用例的指南或规则。框架由旨在帮助 QA 专业人员更有效地测试的实践和工具的组合组成。 这些指南可能包括编码标准、测试数据处理方法、对象存储库、存储测试结果的过程或有关如何访问外部资源的信息。 A testing framewo…...
机器学习全流程解析:数据导入到服务上线全阶段介绍
目录 1. 数据导入 2. 数据预处理 3. 超参数搜索与优化 4. 模型训练 5. 模型评估 6. 模型压缩与优化 7. 模型注册与版本管理 8. 服务上线与部署 总结 1. 数据导入 数据源:数据库、文件系统、API等。数据格式:CSV、JSON、SQL 数据库表、Parquet …...
shell脚本练习
1、shell 脚本写出检测 /tmp/size.log 文件如果存在显示它的内容,不存在则创建一个文件将创建时间写入。 if [ -f /tmp/size.log ];thencat /tmp/size.logelsestat exist.sh | awk -F: "NR5" > /tmp/size.logfi 2、写一个 shel1 脚本,实现批量添加…...
金山WPS Android面试题及参考答案
说说你所知道的所有集合?并阐述其内部实现。 在 Android 开发(Java 语言基础上)中有多种集合。 首先是 List 集合,主要包括 ArrayList 和 LinkedList。 ArrayList 是基于数组实现的动态数组。它的内部有一个数组来存储元素,当添加元素时,如果数组容量不够,会进行扩容操作…...
分类模型为什么使用交叉熵作为损失函数
推导过程 让推理更有体感,进行下面假设: 假设要对猫、狗进行图片识别分类假设模型输出 y y y,是一个几率,表示是猫的概率 训练资料如下: x n x^n xn类别 y ^ n \widehat{y}^n y n x 1 x^1 x1猫1 x 2 x^2 x2猫1 x …...
高等数学学习笔记 ☞ 单调性、凸凹性、极值、最值、曲率
1. 单调性 1. 单调性定义:设函数在区间上有定义,对于区间上任意两点,若: ①:当时,恒有,则称函数在区间上单调递增。 ②:当时,恒有,则称函数在区间上单调递减…...
【操作系统】详解操作系统及其结构
考察频率难度40%--60%⭐⭐ 这又是一类面试考察题,是关于操作系统的一些概念问题,很少会单独拎出来作为一个问题进行提问,但却是必须要掌握的。因为如果这个你不会,其他的问题就已经没有回答的必要了。 什么是操作系统࿱…...
primitive 的 Appearance编写着色器材质
import { nextTick, onMounted, ref } from vue import * as Cesium from cesium import gsap from gsaponMounted(() > { ... })// 1、创建矩形几何体,Cesium.RectangleGeometry:几何体,Rectangle:矩形 let rectGeometry new…...
自动化测试框架搭建-接口数据结构设计
目的 确认数据库如何保存接口数据,既有扩展性,数据又全又好用 根据用途设计数据库字段 区分环境:可以明确当前接口自动化用例,是在哪个环境需要执行的 模块:微服务架构,不同测试同学负责不同的模块&…...
Python自学 - 使用自定义异常
<< 返回目录 1 Python自学 - 使用自定义异常 在Python中, 不仅可以使用内置异常,用户还可以创建自己的异常。自定义异常需要继承自Exception类或其子类,如下是一个自定义异常示例: 示例1:一个简单的自定义异常…...
微信小程序-Docker+Nginx环境配置业务域名验证文件
在实际开发或运维工作中,我们时常需要在 Nginx 部署的服务器上提供一个特定的静态文件,用于域名验证或第三方平台验证。若此时使用 Docker 容器部署了 Nginx,就需要将该验证文件正确地映射(挂载)到容器中,并…...
“AI智能服务平台系统,让生活更便捷、更智能
大家好,我是资深产品经理老王,今天咱们来聊聊一个让生活变得越来越方便的高科技产品——AI智能服务平台系统。这个系统可是现代服务业的一颗璀璨明珠,它究竟有哪些魅力呢?下面我就跟大家伙儿闲聊一下。 一、什么是AI智能服务平台系…...
【PPTist】插入形状、插入图片、插入图表
一、插入形状 插入形状有两种情况,一种是插入固定的形状, 一种是插入自定义的形状。 插入固定的形状时,跟上一篇文章 绘制文本框 是一样一样的,都是调用的 mainStore.setCreatingElement() 方法,只不多传的类型不一…...
云集电商:数据库的分布式升级实践|OceanBase案例
电商行业对数据库有哪些需求 云集电商作为一家传统电商企业,业务涵盖了美妆个护、服饰、水果生鲜、健康保健等多个领域,在创立四年后在纳斯达克上市(股票代码:YJ)。与京东、淘宝、拼多多等电商平台不同,云…...
OOM排查思路
K8S 容器的云原生生态,改变了服务的交付方式,自愈能力和自动扩缩等功能简直不要太好用。 有好的地方咱要夸,不好的地方咱也要说,真正的业务是部署于容器内部,而容器之外,又有一逻辑层 Pod 。 对于容器和…...
Q_OBJECT宏报错的问题
在Qt中继承QObject,并且加上Q_OBJECT宏,有时候会报错,比如我的错误: error: debug/httpmgr.o:httpmgr.cpp:(.rdata$.refptr._ZTV7HttpMgr[.refptr._ZTV7HttpMgr]0x0): undefined reference to vtable for HttpMgr 意思是没有虚…...
iOS - 关联对象
详细总结 Objective-C 的关联对象功能: 1. 基本使用 // 1. 设置关联对象 objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);// 2. 获取关联对象 id objc_getAssociatedObject(id object, const void *key);// 3. …...
Linux之进程
Linux之进程 一.进程进程之形ps命令进程状态特殊进程孤儿进程守护进程 进程创建之创建子进程进程特性优先级进程切换(分时操作系统) 二.环境变量三.进程地址空间四.进程终止&进程等待五.进程替换六.自定义shell 本篇博客希望简略的介绍进程ÿ…...
数据库事务
一 事务的概念 为什么要有事务,我们先前没学事务,也能写sql语句,事务的意义是什么? 由来: 是为了服务应用层开发,降低开发难度。假如没有事务,那我们身为开发人员,要处理转账需求,此时一定是有…...
Python statistics 模块
在数据分析和科学计算中,统计学是一个非常重要的工具。 Python 提供了一个内置的 statistics 模块,专门用于处理基本的统计计算。本文将详细介绍 statistics 模块的功能和使用方法,帮助初学者快速掌握如何使用这个模块进行基本的统计分析。 …...
AI知识-TF-IDF技术(Term Frequency-Inverse Document Frequency)
摘要 TF-IDF(Term Frequency-Inverse Document Frequency)是一种常见的统计方法,用于评估一个词对于一个文档集或一个语料库中的其中一份文档的重要性。本文将全面阐述TF-IDF的通俗理解、技术原理、应用场景,并做以总结。 通俗理…...
spring cloud的核心模块有哪些
Spring Cloud 的核心模块就像一套精心设计的工具箱,每个模块都扮演着特定的角色,共同构建起微服务架构的坚实基础。 1. Spring Cloud Netflix(部分组件已迁移或弃用,但仍是理解 Spring Cloud 的重要参考): …...
java_将数据存入elasticsearch进行高效搜索
使用技术简介: (1) 使用Nginx实现反向代理,使前端可以调用多个微服务 (2) 使用nacos将多个服务管理关联起来 (3) 将数据存入elasticsearch进行高效搜索 (4) 使用消息队列rabbitmq进行消息的传递 (5) 使用 openfeign 进行多个服务之间的api调用 参…...
RAG中的文本切分策略详解
RAG中的文本切分策略详解 1. 选择RAG中的文本切分策略 1.1 不同的文本切分策略 1. CharacterTextSplitter - 这是最简单的方法。它默认基于字符(默认为"")来切割,并且通过字符的数量来衡量块的长度 2. RecursiveCharacterTextSplitter - 基于字符列表拆分文本。 …...
1-1 电场基本概念
目录: 目录 目录: 1.0 电荷守恒定律 2.0 互斥与相吸 3.0 电场的概念 4.0 库伦定律 5.0 矢量的概念 1.0 电荷守恒定律 电荷守恒定律是物理学中的一个基本原理,它指出在一个封闭系统内,电荷的总量是保持不变的。这意味着电荷既…...
SpringBoot初始化执行自定义接口
SpringBoot初始化执行自定义接口 直接加载接口的方法上即可 PostConstructpublic void init() {//加载初始化数据}PostConstruct是一个在Java EE 5规范中引入的注解,用于标记在依赖注入完成后需要执行的方法。这个注解定义在javax.annotation包中,而不…...
【Ubuntu与Linux操作系统:一、Ubuntu安装与基本使用】
第1章 Ubuntu安装与基本使用 1.1 Linux与Ubuntu Linux是一种开源、类Unix操作系统内核,拥有高稳定性和强大的网络功能。由于其开源性和灵活性,Linux被广泛应用于服务器、嵌入式设备以及桌面环境中。 Ubuntu是基于Debian的一个流行Linux发行版…...
C++大端小端判断方法
文章目录 大端小端定义判断方法方法一:利用联合体(Union)特性判断方法二:通过指针类型转换判断方法三:利用位运算与移位操作判断方法四:使用系统提供的字节序相关宏(特定平台支持) 联…...
【IO编程】标准IO和文件IO的对比
标准 I/O 和 文件 I/O 是两种常见的输入输出操作方式。它们的核心功能都是处理数据流,但使用场景和实现方式有所不同,适用于不同的需求。 标准 I/O 标准 I/O 是指与标准输入、标准输出和标准错误流(分别为 stdin、stdout 和 stderr…...
C#范围表达式,模式匹配,逆变和协变--11
目录 一.范围表达式 1.概述 2.语法 3.代码示例 4.实现原理 5.应用场景 二.模式匹配 1.概述 2.核心概念 3.常用模式类型 4.Switch表达式 5.使用示例 6.优势 三.逆变和协变 1.概述 2.泛型类型参数的变性 3.协变示例 4.逆变示例 5.注意事项 6.应用场景 总结 一…...
矩阵求逆的几种方式
矩阵求逆的几种方式(以二阶为例) 矩阵求逆的方法有多种,以下是常用的几种方式总结: 1. 行列式公式法 这是最常见的方法,适用于 2 2 2 \times 2 22矩阵。 对于矩阵: Φ [ a b c d ] , \Phi \begin{bma…...
全新市场阶段, Plume 生态不断壮大的 RWAfi 版图
加密市场在 2024 年迎来了新的里程碑。BTC 不仅成功推出 ETF,以 BTC 为代表的主流加密货币还在一系列传统金融机构的推动下逐步与主流金融市场接轨。与此同时,随着特朗普成功当选下一任美国总统,他承诺推出一系列友好的加密政策,并…...
HTTPS SSL/TLS 工作流程
目录 一、HTTP/HTTPS 简介1、HTTP协议相关内容2、HTTPS协议3、HTTP版本差异: 二、HTTPS 协议工作流程解析1. 客户端请求 SSL 握手2. 服务端接收 SSL 握手连接3. TLS 握手中的密钥协商4. HTTP 数据的加密与解密5. 安全性保障 三、HTTPS 协议的相关知识拓展1. TLS 与 …...