为了账号安全,请及时绑定邮箱和手机立即绑定

作业社区

探索学习新天地,共享知识资源!

0 提交作业
0 布置作业
0 满分作业
得分 100
学习任务

浪潮君 的学生作业:

接收端 #include // 标准输入输出函数(如 printf、perror) #include // 包含 exit、malloc 等函数 #include // 包含 memset、strlen 等字符串处理函数 #include // 提供 close 等系统调用函数 #include // 提供 htons、inet_ntop 等 IP 转换函数 #include // 提供 socket 编程相关结构与函数 #define SERVER_PORT 8890 // 服务器监听端口 #define BACKLOG 5 // 最大排队连接数 #define BUFFER_SIZE 1024 // 每次读写的缓冲区大小 // 接收客户端发来的文件并保存到本地 void receive_file(int conn_fd) { int name_len; // 文件名长度(int 类型) char filename[256]; // 文件名缓冲区 long filesize; // 文件大小(long 类型) // 1. 读取文件名长度(占 4 字节) recv(conn_fd, &name_len, sizeof(int), 0); // 2. 读取文件名字符串(不含路径) recv(conn_fd, filename, name_len, 0); filename[name_len] = '\0'; // 添加字符串结束符 printf("接收文件名:%s\n", filename); // 3. 接收文件大小(占 8 字节) recv(conn_fd, &filesize, sizeof(long), 0); printf("文件大小:%ld 字节\n", filesize); // 4. 打开本地文件,准备写入内容 FILE *fp = fopen(filename, "wb"); if (!fp) { perror("无法创建文件"); return; } // 5. 循环接收文件内容 char buffer[BUFFER_SIZE]; long received = 0; while (received < filesize) { ssize_t len = recv(conn_fd, buffer, sizeof(buffer), 0); if (len 0) { send(sockfd, buffer, read_bytes, 0); // 分片发送 } fclose(fp); // 关闭文件 printf("文件发送完成。\n"); } int main() { // 创建客户端 socket int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket 创建失败"); return 1; } // 设置服务端地址信息 struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); // 清零 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); // 设置端口 // 转换 IP 地址为网络格式 if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr)

得分 100
学习任务

浪潮君 的学生作业:

服务端 #include // 标准输入输出头文件,包含 printf、perror 等 #include // 包含 exit、malloc 等函数 #include // 包含字符串处理函数,如 memset、strlen #include // 包含 close、read、write 等 Unix/Linux 系统调用 #include // 包含 IP 地址转换函数,如 inet_ntop、htons #include // 包含 socket 函数与结构体定义 #define SERVER_PORT 8890 // 服务端监听的端口号 #define BACKLOG 5 // 最大连接请求队列长度 #define BUFFER_SIZE 1024 // 缓冲区最大长度(接收/发送) // 创建 TCP 服务器监听 socket,并绑定指定 IP 和端口 int tcp_socket_create(const char *ip, int port, int backlog) { int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建 IPv4、TCP 套接字 if (sockfd < 0) { perror("socket failed"); // 创建失败时输出错误信息 return -1; } // 设置 socket 地址重用选项,防止 bind 报错 "Address already in use" int opt = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); // 初始化结构体为 0 addr.sin_family = AF_INET; // 设置地址族为 IPv4 addr.sin_addr.s_addr = INADDR_ANY; // 监听所有本地 IP 地址(0.0.0.0) addr.sin_port = htons(SERVER_PORT); // 设置监听端口,使用网络字节序 // 绑定 socket 到本地地址与端口 if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("bind failed"); // 绑定失败 close(sockfd); return -1; } // 启动监听,将 socket 设为被动连接模式 if (listen(sockfd, backlog) < 0) { perror("listen failed"); // 监听失败 close(sockfd); return -1; } return sockfd; // 返回监听套接字 } // 处理每个客户端连接的函数 void handle_client(int conn_fd, struct sockaddr_in *client_addr) { char buffer[BUFFER_SIZE]; // 接收客户端消息的缓冲区 char client_ip[INET_ADDRSTRLEN]; // 存储客户端 IP 字符串 // 将客户端 IP 地址转换为可读字符串格式 inet_ntop(AF_INET, &client_addr->sin_addr, client_ip, sizeof(client_ip)); // 将端口号从网络字节序转换为主机字节序 int client_port = ntohs(client_addr->sin_port); printf("客户端已连接:%s:%d\n", client_ip, client_port); // 循环接收客户端消息并回显 while (1) { // 接收客户端消息 ssize_t len = recv(conn_fd, buffer, sizeof(buffer) - 1, 0); if (len < 0) { printf("客户端断开连接\n"); // 接收失败 break; } buffer[len] = '\0'; // 添加字符串结束符,构成合法 C 字符串 printf("收到消息:%s\n", buffer); // 构造服务端回显响应内容 char reply[BUFFER_SIZE]; snprintf(reply, sizeof(reply), "服务端已收到: %s", buffer); // 将回应内容发回客户端 send(conn_fd, reply, strlen(reply), 0); } // 关闭客户端连接 socket close(conn_fd); } // 主函数:程序入口 int main(int argc, char *argv[]) { // 创建监听 socket,并绑定本地端口 int listen_fd = tcp_socket_create("0.0.0.0", SERVER_PORT, BACKLOG); if (listen_fd < 0) { fprintf(stderr, "监听 socket 创建失败。退出\n"); return -1; } printf("服务端启动,监听端口 %d\n", SERVER_PORT); // 主循环:接收并处理客户端连接 while (1) { struct sockaddr_in client_addr; // 用于存储客户端地址信息 socklen_t client_len = sizeof(client_addr); // 接受客户端连接请求,阻塞等待连接 int conn_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len); if (conn_fd < 0) { perror("accept failed"); // 接收失败 continue; } // 处理客户端连接 handle_client(conn_fd, &client_addr); } // 关闭监听 socket close(listen_fd); return 0; } 客户端 #include // 标准输入输出,如 printf、fprintf #include // 包含 exit 函数 #include // 字符串处理,如 strlen、strcspn #include // 包含 close 函数 #include // 网络地址转换函数,如 inet_pton #include // socket API 函数 #define SERVER_IP "127.0.0.1" // 服务器 IP 地址(本地环回地址) #define SERVER_PORT 8890 // 服务器端口号(需与服务端保持一致) #define BUFFER_SIZE 1024 // 缓冲区最大长度 // 创建 TCP 客户端 socket 并连接服务器 int tcp_client_connect(const char *ip, int port) { // 创建 socket(IPv4 + TCP) int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket 创建失败"); return -1; } // 配置服务器地址结构 struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); // 清零初始化 server_addr.sin_family = AF_INET; // IPv4 server_addr.sin_port = htons(port); // 设置端口(转为网络字节序) // 将 IP 字符串转换为二进制形式 if (inet_pton(AF_INET, ip, &server_addr.sin_addr)

得分 100
学习任务

浪潮君 的学生作业:

服务器端 #include // 标准输入输出头文件,包含 printf、perror 等 #include // 包含 exit、malloc 等函数 #include // 包含字符串处理函数,如 memset、strlen #include // 包含 close、read、write 等 Unix/Linux 系统调用 #include // 包含 IP 地址转换函数,如 inet_ntop、htons #include // 包含 socket 函数与结构体定义 #define SERVER_PORT 8890 // 服务端监听的端口号 #define BACKLOG 5 // 最大连接请求队列长度 #define BUFFER_SIZE 1024 // 缓冲区最大长度(接收/发送) // 创建 TCP 服务器监听 socket,并绑定指定 IP 和端口 int tcp_socket_create(const char *ip, int port, int backlog) { int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建 IPv4、TCP 套接字 if (sockfd < 0) { perror("socket failed"); // 创建失败时输出错误信息 return -1; } // 设置 socket 地址重用选项,防止 bind 报错 "Address already in use" int opt = 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); // 初始化结构体为 0 addr.sin_family = AF_INET; // 设置地址族为 IPv4 addr.sin_addr.s_addr = INADDR_ANY; // 监听所有本地 IP 地址(0.0.0.0) addr.sin_port = htons(SERVER_PORT); // 设置监听端口,使用网络字节序 // 绑定 socket 到本地地址与端口 if (bind(sockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("bind failed"); // 绑定失败 close(sockfd); return -1; } // 启动监听,将 socket 设为被动连接模式 if (listen(sockfd, backlog) < 0) { perror("listen failed"); // 监听失败 close(sockfd); return -1; } return sockfd; // 返回监听套接字 } // 处理每个客户端连接的函数 void handle_client(int conn_fd, struct sockaddr_in *client_addr) { char buffer[BUFFER_SIZE]; // 接收客户端消息的缓冲区 char client_ip[INET_ADDRSTRLEN]; // 存储客户端 IP 字符串 // 将客户端 IP 地址转换为可读字符串格式 inet_ntop(AF_INET, &client_addr->sin_addr, client_ip, sizeof(client_ip)); // 将端口号从网络字节序转换为主机字节序 int client_port = ntohs(client_addr->sin_port); printf("客户端已连接:%s:%d\n", client_ip, client_port); // 循环接收客户端消息并回显 while (1) { // 接收客户端消息 ssize_t len = recv(conn_fd, buffer, sizeof(buffer) - 1, 0); if (len < 0) { printf("客户端断开连接\n"); // 接收失败 break; } buffer[len] = '\0'; // 添加字符串结束符,构成合法 C 字符串 printf("收到消息:%s\n", buffer); // 构造服务端回显响应内容 char reply[BUFFER_SIZE]; snprintf(reply, sizeof(reply), "服务端已收到: %s", buffer); // 将回应内容发回客户端 send(conn_fd, reply, strlen(reply), 0); } // 关闭客户端连接 socket close(conn_fd); } // 主函数:程序入口 int main(int argc, char *argv[]) { // 创建监听 socket,并绑定本地端口 int listen_fd = tcp_socket_create("0.0.0.0", SERVER_PORT, BACKLOG); if (listen_fd < 0) { fprintf(stderr, "监听 socket 创建失败。退出\n"); return -1; } printf("服务端启动,监听端口 %d\n", SERVER_PORT); // 主循环:接收并处理客户端连接 while (1) { struct sockaddr_in client_addr; // 用于存储客户端地址信息 socklen_t client_len = sizeof(client_addr); // 接受客户端连接请求,阻塞等待连接 int conn_fd = accept(listen_fd, (struct sockaddr *) &client_addr, &client_len); if (conn_fd < 0) { perror("accept failed"); // 接收失败 continue; } // 处理客户端连接 handle_client(conn_fd, &client_addr); } // 关闭监听 socket close(listen_fd); return 0; } 客户端 #include // 标准输入输出,如 printf、fprintf #include // 包含 exit 函数 #include // 字符串处理,如 strlen、strcspn #include // 包含 close 函数 #include // 网络地址转换函数,如 inet_pton #include // socket API 函数 #define SERVER_IP "127.0.0.1" // 服务器 IP 地址(本地环回地址) #define SERVER_PORT 8890 // 服务器端口号(需与服务端保持一致) #define BUFFER_SIZE 1024 // 缓冲区最大长度 // 创建 TCP 客户端 socket 并连接服务器 int tcp_client_connect(const char *ip, int port) { // 创建 socket(IPv4 + TCP) int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket 创建失败"); return -1; } // 配置服务器地址结构 struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); // 清零初始化 server_addr.sin_family = AF_INET; // IPv4 server_addr.sin_port = htons(port); // 设置端口(转为网络字节序) // 将 IP 字符串转换为二进制形式 if (inet_pton(AF_INET, ip, &server_addr.sin_addr)

得分 100
讨论题

jelasin 的学生作业:

三次握手的过程: 第一次握手:客户端发送SYN报文段,序列号为x 第二次握手:服务器回复SYN+ACK报文段,确认号为x+1,序列号为y 第三次握手:客户端发送ACK报文段,确认号为y+1 三次握手的必要性: 确认双方的收发能力 第一次握手:确认客户端发送能力、服务器接收能力 第二次握手:确认服务器发送能力、客户端接收能力 第三次握手:再次确认客户端发送能力、服务器接收能力 防止旧连接请求的干扰 场景:客户端发送连接请求A,网络延迟导致超时重发请求B 如果只有两次握手: - 请求B先到达并建立连接 - 连接结束后,延迟的请求A到达 - 服务器误认为这是新的连接请求并建立连接 - 造成资源浪费 三次握手解决方案: - 即使旧请求A到达,服务器发送SYN+ACK - 但客户端已经处理完连接B,会忽略这个响应 - 没有第三次握手,连接不会建立 同步序列号 双方需要交换初始序列号,用于后续的数据传输和确认。 四次挥手的过程: 第一次挥手:客户端发送FIN报文段 第二次挥手:服务器发送ACK确认 第三次挥手:服务器发送FIN报文段 第四次挥手:客户端发送ACK确认 四次挥手的原因: TCP是全双工通信 建立连接时: - 一个SYN+ACK可以同时完成"同意连接"和"发送自己的连接请求" 断开连接时: - 收到FIN只能确认对方要关闭发送方向 - 但自己可能还有数据要发送 - 所以ACK(确认)和FIN(关闭)必须分开 数据传输的完整性 // 服务器端的处理逻辑 recv_FIN_from_client() { send_ACK(); // 第二次挥手:确认收到客户端的FIN // 此时可能还有数据要发送给客户端 while(has_data_to_send()) { send_data(); } send_FIN(); // 第三次挥手:发送自己的FIN } 状态转换的需要 客户端状态:ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT -> CLOSED 服务端状态:ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED

微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号