
作业社区
探索学习新天地,共享知识资源!
胡汉三66 的学生作业:
tcp_client.c #include #include #include #include // bzore() #include // close() #include #include #include #include // TCP客户端连接 // ./a.out ip port int main(int argc, const char *argv[]) { int sfd,ret; ssize_t sbytes = 0, rbytes = 0; char buffer[1024] = {0}; struct sockaddr_in svr_addr; if(argc != 3){ fprintf(stderr,"Usage : %s < ip > < port >.\n",argv[0]); exit(EXIT_FAILURE); } // 1.创建套接字 sfd = socket(AF_INET,SOCK_STREAM,0); if(sfd == -1){ perror("[ERROR] Failed to socket."); exit(EXIT_FAILURE); } printf("sfd = %d\n",sfd); // 2.建立连接 bzero(&svr_addr,sizeof(struct sockaddr_in)); // 指针指向空间初始化(清零) svr_addr.sin_family = AF_INET; // 协议族 svr_addr.sin_port = htons(atoi(argv[2])); // 端口 svr_addr.sin_addr.s_addr = inet_addr(argv[1]); // IP ret = connect(sfd,(const struct sockaddr *)&svr_addr,sizeof(struct sockaddr_in)); // 客户端 连接 服务器 if(ret == -1){ perror("[ERROR] Failed to connect."); exit(EXIT_FAILURE); } for(;;){ // 循环输入发送 // 输入数据 putchar('>'); memset(buffer,0,sizeof(buffer)); fgets(buffer,sizeof(buffer),stdin); // 3.发送数据 (客户端-->服务器) sbytes = send(sfd,buffer,strlen(buffer) + 1,0); // "+1" ---> "\0" if(ret == -1){ perror("[ERROR] Failed to send."); exit(EXIT_FAILURE); } if(strncmp(buffer,"quit",4) == 0) break; // 4.接收数据 (服务器--->客户端) bzero(buffer,sizeof(buffer)); // 指针指向空间初始化(清零) rbytes = recv(sfd,buffer,sizeof(buffer),0); // "+1" ---> "\0" if(ret == -1){ perror("[ERROR] Failed to recv."); exit(EXIT_FAILURE); }else if(rbytes > 0){ printf("buffer : %s\n",buffer); }else if(rbytes == 0){ printf("The server has been shut down.\n"); } } close(sfd); // 关闭 文件描述符 return 0; } tcp_server.c #include #include #include #include // bzore() #include // close() #include #include #include #include #define BACKLOG 10 // 监听队列最大值 // TCP服务器连接 // ./a.out ip port int main(int argc, const char *argv[]) { int sfd,ret,cfd; struct sockaddr_in svr_addr,cli_addr; ssize_t rbytes = 0,sbytes = 0; char buffer[1024] = {0}; socklen_t len = sizeof(struct sockaddr_in); if(argc != 3){ fprintf(stderr,"Usage : %s < ip > < port >.\n",argv[0]); exit(EXIT_FAILURE); } // 1.创建套接字 sfd = socket(AF_INET,SOCK_STREAM,0); if(sfd == -1){ perror("[ERROR] Failed to socket."); exit(EXIT_FAILURE); } printf("sfd = %d\n",sfd); bzero(&svr_addr,sizeof(struct sockaddr_in)); // 指针指向空间初始化(清零) svr_addr.sin_family = AF_INET; // 协议族 svr_addr.sin_port = htons(atoi(argv[2])); // 端口 svr_addr.sin_addr.s_addr = inet_addr(argv[1]); // IP // 2.绑定ip地址与端口号 ret = bind(sfd,(const struct sockaddr *)&svr_addr,sizeof(struct sockaddr_in)); if(ret == -1){ perror("[ERROR] Failed to bind."); exit(EXIT_FAILURE); } // 3.建立监听队列 ret = listen(sfd,BACKLOG); if(ret == -1){ perror("[ERROR] Failed to listen."); exit(EXIT_FAILURE); } // 4.建立连接,并产生新的客户端用于数据收发 cfd = accept(sfd,(struct sockaddr *)&cli_addr,&len); if(cfd == -1){ perror("[ERROR] Failed to accept."); exit(EXIT_FAILURE); } printf("ip : %s port : %d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port)); for(;;){ memset(buffer,0,sizeof(buffer)); // 清空 rbytes = recv(cfd,buffer,sizeof(buffer),0); if(rbytes == -1){ perror("[ERROR] Failed to recv."); exit(EXIT_FAILURE); }else if(rbytes > 0){ // 如果收到数据 // 如果输入是"quit",则退出 if(strncmp(buffer,"quit",4) == 0) break; // 将接收到的 客户端数据 回传给 客户端 sbytes = send(cfd,buffer,sizeof(buffer),0); if(sbytes == -1){ perror("[ERROR] Failed to recv."); exit(EXIT_FAILURE); } }else if(rbytes == 0){ printf("The client has been shutdown.\n"); break; } } close(sfd); // 关闭 文件描述符 close(cfd); return 0; } 【图片】





浪潮君 的学生作业:
#include #include #include #include // 定义一个全局变量,两个线程都会对它执行加一操作 static int global = 0; // 声明并初始化互斥锁 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 子线程函数:对 global 执行 loops 次加一操作 void *do_thread(void *arg) { int loops = *(int *)arg; // 从参数中取出循环次数 for (int i = 0; i < loops; i++) { pthread_mutex_lock(&mutex); // 加锁:进入临界区 global++; // 修改共享变量 pthread_mutex_unlock(&mutex); // 解锁:退出临界区 } return NULL; // 线程无返回值 } int main() { pthread_t tid[2]; // 定义两个线程 ID int loops = 1000000; // 每个线程加一百万次,共两百万次 // 创建两个线程,执行 do_thread 函数,传入同一个 loops 参数地址 for (int i = 0; i < 2; i++) { if (pthread_create(&tid[i], NULL, do_thread, &loops) != 0) { perror("pthread_create failed"); // 创建失败则报错并退出 exit(EXIT_FAILURE); } } // 等待两个线程执行完毕(阻塞主线程) pthread_join(tid[0], NULL); pthread_join(tid[1], NULL); // 输出最终的 global 值,应为 2 × 1000000 = 2000000 printf("global = %d\n", global); return 0; }
浪潮君 的学生作业:
#include // 提供 printf、perror 等标准输出函数 #include // 提供 malloc、free、exit 等动态内存和退出控制 #include // 提供 pthread 线程函数 #include // 提供字符串处理函数,如 strcpy // 使用匿名结构体定义类型 person typedef struct { char name[20]; // 名字字段,最多 19 个字符 + '\0' int age; // 年龄字段 } person; // 子线程函数:创建并返回一个 person 结构体指针 void *thread_func(void *) { // 动态分配内存,确保线程退出后数据依然有效 person *p = malloc(sizeof(person)); if (p == NULL) { perror("malloc failed"); // 分配失败,打印错误信息 pthread_exit(NULL); // 线程安全地退出 } // 填写结构体字段 strcpy(p->name, "Tom"); // 设置名字 p->age = 30; // 设置年龄 return (void *) p; // 返回结构体指针(会被 pthread_join 接收) } int main() { pthread_t tid; // 线程 ID person *result = NULL; // 用于接收线程返回的结构体指针 // 创建子线程,执行 thread_func 函数 if (pthread_create(&tid, NULL, thread_func, NULL) != 0) { perror("线程创建失败"); exit(EXIT_FAILURE); // 创建失败,程序退出 } // 主线程等待子线程结束,并接收其返回的结构体地址 if (pthread_join(tid, (void **) &result) != 0) { perror("线程等待失败"); exit(EXIT_FAILURE); } // 如果接收成功,打印结构体中的数据 if (result != NULL) { printf("姓名:%s\n", result->name); printf("年龄:%d\n", result->age); free(result); // 使用完后释放动态内存,防止内存泄漏 } return 0; }
浪潮君 的学生作业:
#include // 标准输入输出函数,如 printf、fprintf #include // 提供 exit() 和 EXIT_FAILURE 宏 #include // 提供 fork()、sleep() 等系统调用 #include // 提供 wait() 函数,等待子进程 #include // 提供时间函数,如 time()、strftime() #include // 提供文件控制宏(本程序中未使用,可删除) int main() { // 打开日志文件,写入模式,如果文件存在则清空,不存在则创建 FILE *fp = fopen("time_log.txt", "w"); if (fp == NULL) { perror("无法打开文件"); exit(EXIT_FAILURE); // 打开失败则退出程序 } // 循环 10 次,每次创建一个子进程,完成一次完整的时间日志写入 for (int i = 1; i
浪潮君 的学生作业:
#include // 提供 printf() #include // 提供 exit() #include // 提供 POSIX 线程函数 #include // 提供 sleep() // 子线程执行函数 void* thread_func(void *) { // 获取当前线程的 ID pthread_t tid = pthread_self(); // 打印线程 ID(转换为无符号长整型便于输出) printf("子线程(分离)ID: %lu\n", (unsigned long) tid); // 线程结束(返回 NULL) return NULL; } int main() { pthread_t tid1, tid2; // 定义两个线程变量,用于保存线程 ID // 创建第一个线程 if (pthread_create(&tid1, NULL, thread_func, NULL) != 0) { perror("创建线程 1 失败"); exit(EXIT_FAILURE); } // 设置第一个线程为分离状态(不再使用 pthread_join 等待它) pthread_detach(tid1); // 创建第二个线程 if (pthread_create(&tid2, NULL, thread_func, NULL) != 0) { perror("创建线程 2 失败"); exit(EXIT_FAILURE); } // 设置第二个线程为分离状态 pthread_detach(tid2); // 主线程暂停 1 秒,等待子线程运行完毕 sleep(1); // 否则主线程太早结束,子线程可能还没执行就被强制终止 // 主线程结束 printf("主线程结束(不等待子线程)\n"); return 0; }
浪潮君 的学生作业:
#include // 提供 printf 等输出函数 #include // 提供 exit 等退出控制函数 #include // 提供 POSIX 线程相关函数和类型 #include // 提供 sleep 等 UNIX 系统调用(本例中未使用) // 子线程执行的函数 void *thread_func(void *) { // 获取当前线程的线程 ID pthread_t tid = pthread_self(); // 打印当前线程的 ID(转换为 unsigned long 便于可读性) printf("子线程 ID: %lu\n", (unsigned long) tid); // 返回 NULL 表示线程正常退出(也可以返回其他值给 pthread_join 获取) return NULL; } int main() { // 声明两个线程变量,类型为 pthread_t(用于保存线程 ID) pthread_t tid1, tid2; // 创建第一个线程,让它执行 thread_func 函数 if (pthread_create(&tid1, NULL, thread_func, NULL) != 0) { perror("创建线程 1 失败"); // 如果创建失败,打印错误信息 exit(EXIT_FAILURE); // 程序异常退出 } // 创建第二个线程,也执行同一个函数 if (pthread_create(&tid2, NULL, thread_func, NULL) != 0) { perror("创建线程 2 失败"); exit(EXIT_FAILURE); } // 主线程等待第一个子线程结束(阻塞等待) pthread_join(tid1, NULL); // 主线程等待第二个子线程结束 pthread_join(tid2, NULL); // 两个子线程都结束后,主线程打印退出信息 printf("主线程结束。\n"); return 0; }
浪潮君 的学生作业:
#include // 标准输入输出头文件(用于 printf、fgets 等) #include // 标准库头文件(用于 exit、EXIT_FAILURE 等) #include // 字符串操作函数(如 strcmp, strtok) #include // Unix 系统调用头文件(如 fork, execvp) #include // 等待子进程结束(wait 函数) #define MAX_CMD_LEN 128 // 用户输入命令最大长度 #define MAX_ARGS 10 // 命令最多支持的参数个数(包含命令本身) int main(void) { char input[MAX_CMD_LEN]; // 用于保存用户输入的命令行 // 主循环:持续运行 shell,直到用户输入 "exit" while (1) { // 打印 shell 提示符 printf("minishell> "); fflush(stdout); // 确保提示符立即显示(防止缓冲延迟) // 读取用户输入(阻塞等待,最大读取 MAX_CMD_LEN 字节) if (fgets(input, sizeof(input), stdin) == NULL) { // 若读取失败或遇到 EOF(如 Ctrl+D),退出循环 break; } // 去除结尾的换行符(fgets 会保留 \n) input[strcspn(input, "\n")] = '\0'; // 判断是否是退出命令 if (strcmp(input, "exit") == 0) { break; } // -------- 命令解析 -------- // 使用 strtok 将输入字符串按空格分割为多个参数 char *args[MAX_ARGS] = {0}; // 参数数组初始化为 NULL int arg_count = 0; // 参数计数器 // 提取第一个 token(命令本身) char *token = strtok(input, " "); while (token != NULL && arg_count < MAX_ARGS - 1) { args[arg_count++] = token; // 将参数保存到数组 token = strtok(NULL, " "); // 提取下一个参数 } args[arg_count] = NULL; // 参数列表末尾设置为 NULL,符合 execvp 要求 // -------- 创建子进程 -------- pid_t pid = fork(); // 创建子进程 if (pid < 0) { // 创建失败,打印错误信息 perror("fork failed"); continue; // 回到循环继续处理下一个输入 } if (pid == 0) { // -------- 子进程 -------- // 使用 execvp 执行命令(搜索 PATH 环境变量) execvp(args[0], args); // 若 execvp 执行失败,则继续执行下面代码 perror("exec failed"); exit(EXIT_FAILURE); // 子进程异常退出 } else { // -------- 父进程 -------- // 等待子进程结束,防止出现僵尸进程 wait(NULL); } } // Shell 主循环结束,打印退出信息 printf("退出 minishell。\n"); return 0; }





浪潮君 的学生作业:
#include #include #include #include int main(void) { pid_t pid_a, pid_b; int status_a = 0, status_b = 0; int a_done = 0, b_done = 0; // 创建子进程 A pid_a = fork(); if (pid_a == 0) { // 子进程 A printf("[A] PID=%d 正在运行...\n", getpid()); sleep(2); printf("[A] PID=%d 退出\n", getpid()); exit(10); // 自定义退出码 } // 创建子进程 B pid_b = fork(); if (pid_b == 0) { // 子进程 B printf("[B] PID=%d 正在运行...\n", getpid()); sleep(5); printf("[B] PID=%d 退出\n", getpid()); exit(20); // 自定义退出码 } // 父进程非阻塞轮询两个子进程状态 while (!a_done || !b_done) { if (!a_done) { pid_t ret = waitpid(pid_a, &status_a, WNOHANG); if (ret == pid_a) { printf("[父进程] 检测到子进程 A (PID=%d) 已退出,状态码=%d\n", pid_a, WEXITSTATUS(status_a)); a_done = 1; } } if (!b_done) { pid_t ret = waitpid(pid_b, &status_b, WNOHANG); if (ret == pid_b) { printf("[父进程] 检测到子进程 B (PID=%d) 已退出,状态码=%d\n", pid_b, WEXITSTATUS(status_b)); b_done = 1; } } // 模拟父进程做其他事情 printf("[父进程] 正在工作...\n"); sleep(1); } printf("[父进程] 所有子进程已退出,程序结束。\n"); return 0; }




