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

作业社区

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

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

慕尼黑0001808 的学生作业:

#include #include /* See NOTES */ #include #include #include #include #include #include #include void sig_handler(int signum) { waitpid(-1, NULL, WNOHANG); printf("recv singnum = %d zombie\n", signum); return; } int main(int argc, char *argv[]) { int ret; int socket_id; char server_ip[] = "192.168.0.191"; char server_port[] = "8080"; struct sockaddr_in server_addr; struct sockaddr_in peer_addr; ssize_t rbytes = 0; char rbuffer[64]; // 0.主进程回收僵尸态子进程 if (signal(SIGCHLD, sig_handler) == SIG_ERR) { perror("Fail to single\n"); return -1; } socklen_t server_addrlen = sizeof(struct sockaddr_in); socklen_t peer_addrlen = sizeof(struct sockaddr_in); socket_id = socket(AF_INET,SOCK_DGRAM,0); if(-1 == socket_id){ perror("socket()"); exit(EXIT_FAILURE); } memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(server_ip); server_addr.sin_port = htons(atoi(server_port)); ret = bind(socket_id,(struct sockaddr *)&server_addr,server_addrlen); if(-1 == ret){ perror("bind()"); exit(EXIT_FAILURE); } while(1){ memset(rbuffer,0,sizeof(rbuffer)); memset(&peer_addr,0,sizeof(peer_addr)); rbytes = recvfrom(socket_id,rbuffer,64,0,(struct sockaddr *)&peer_addr,&peer_addrlen); if(-1 == rbytes){ perror("recvfrom()"); exit(EXIT_FAILURE); } printf("server main :%s\n",rbuffer); if(0 == fork()){ //close(socket_id); close(socket_id); // 关闭主进程的socket(不再共享) // 创建子进程独立的socket socket_id = socket(AF_INET, SOCK_DGRAM, 0); char response[128]; while(1){ memset(response,0,128); snprintf(response,128,"子进程(pid=%d)已处理消息:%s",getpid(),rbuffer); ret = sendto(socket_id,response,strlen(response),0,(struct sockaddr *)&peer_addr,peer_addrlen); if(-1 == ret){ perror("child sendto()"); exit(EXIT_FAILURE); } rbytes = recvfrom(socket_id,rbuffer,64,0,(struct sockaddr *)&peer_addr,&peer_addrlen); if(-1 == rbytes){ perror("子进程recvfrom()"); exit(EXIT_FAILURE); } rbuffer[rbytes] = '\0'; printf("子进程%d收到客户端数据:%s\n",getpid(),rbuffer); if(strncmp(rbuffer,"quit",4)==0){ printf("子进程%d收到退出指令\n",getpid()); exit(EXIT_SUCCESS); } } exit(EXIT_SUCCESS); } } return 0; }

得分 100
学习任务

慕工程6300203 的学生作业:

#include #include #include #include #include #include #include #include #define MAX_EVENTS 10 #define FIFO_PATHNAME "/home/linux/file/fifo" int main(int argc, char* argv[]) { int epfd, ret, fifo_fd; struct epoll_event ev; struct epoll_event ret_ev[MAX_EVENTS]; char buffer[64] = {0}; epfd = epoll_create(1); if (epfd == -1) { perror("[ERROR] epoll_create()"); exit(EXIT_FAILURE); } printf("epoll_fd = %d\n", epfd); ret = access(FIFO_PATHNAME, F_OK); if (ret == 0) { unlink(FIFO_PATHNAME); } ret = mkfifo(FIFO_PATHNAME, 0666); if (ret == -1) { perror("[ERROR] mkfifo()"); exit(EXIT_FAILURE); } fifo_fd = open(FIFO_PATHNAME, O_RDONLY | O_NONBLOCK); if (fifo_fd == -1) { perror("[ERROR] open()"); exit(EXIT_FAILURE); } ev.data.fd = fifo_fd; ev.events = EPOLLIN; ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fifo_fd, &ev); if (ret == -1) { perror("[ERROR] epoll_ctl()"); exit(EXIT_FAILURE); } for (;;) { ret = epoll_wait(epfd, ret_ev, MAX_EVENTS, 1000); if (ret == -1) { perror("[ERROR] epoll_wait()"); exit(EXIT_FAILURE); } else if (ret == 0) { printf("Timeout!\n"); } else if (ret > 0) { int i; for (i = 0; i < ret; i++) { if (ret_ev[i].data.fd == fifo_fd) { int read_bytes = 0; do { memset(buffer, 0, sizeof(buffer) - 1); read_bytes = read(fifo_fd, buffer, 10); fputs(buffer, stdout); fflush(stdout); } while (read_bytes > 0); close(fifo_fd); fifo_fd = open(FIFO_PATHNAME, O_RDONLY | O_NONBLOCK); if (fifo_fd == -1) { perror("[ERROR] open()"); exit(EXIT_FAILURE); } ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fifo_fd, &ev); if (ret == -1) { perror("[ERROR] epoll_ctl()"); exit(EXIT_FAILURE); } } } } } return 0; }

得分 100
讨论题

慕尼黑0001808 的学生作业:

一、为什么连接建立需要三次握手? 三次握手的核心目的是 “同步双方序列号+确认连接可行性”,确保双方都具备发送和接收数据的能力,避免“无效连接”浪费资源。 过程简化: 客户端→服务器(SYN=1,seq=x):请求建立连接,发送初始序列号x,询问“你能收到吗?” 服务器→客户端(SYN=1,ACK=1,seq=y,ack=x+1):服务器同意连接,回复自己的初始序列号y(同步),并确认收到x(ack=x+1),询问“我能收到,你能收到我的回复吗?” 客户端→服务器(ACK=1,ack=y+1):客户端确认收到服务器的序列号y(ack=y+1),告知“我也能收到你的消息,连接可以建立了”。 为什么不能两次握手? 若仅两次握手,服务器在发送SYN+ACK后就认为连接已建立,但客户端可能因网络延迟/丢包未收到确认,此时服务器会一直等待客户端数据,造成资源浪费(如半连接队列溢出)。 三次握手通过客户端的第三次确认,确保双方都明确“对方已准备就绪”,避免“失效的连接请求报文段”被服务器误认,是 “可靠连接初始化” 的必要步骤。 二、为什么断开连接需要四次挥手? 四次挥手的核心原因是 TCP的全双工通信特性:双方需独立关闭各自的发送方向(即“单向关闭”),且关闭前需确保数据传输完毕。 过程简化: 客户端→服务器(FIN=1,seq=u):客户端请求关闭“客户端→服务器”的发送方向(不再发数据),告知“我说完了”。 服务器→客户端(ACK=1,ack=u+1):服务器确认收到关闭请求,但可能还有未发送完的数据,此时仅关闭“客户端→服务器”方向,回复“知道了,你等我说完”。 服务器→客户端(FIN=1,ACK=1,seq=v,ack=u+1):服务器数据发送完毕,请求关闭“服务器→客户端”的发送方向,告知“我也说完了”。 客户端→服务器(ACK=1,ack=v+1):客户端确认收到服务器的关闭请求,关闭“服务器→客户端”方向,告知“知道了,双方都关闭吧”。

得分 100
学习任务

慕尼黑0001808 的学生作业:

seq的含义:tcp报文段首部32位字段,标识当前发送数据的第一个字节的序号。 seq的作用:1.解决网络中数据乱序问题,接收方通过序列号重组数据。2.用于可靠传输中的重传机制(如超时未收到确认时,重传对应序列号的报文) seq的理确:可类比快递单号,每个包裹(数据段)都有唯一编号,接收方按编号排序拼接,确保数据完整有序。 ack的含义:tcp报文段首部的32位字段,标识期望接收的下一个数据字节的序号(即已成功接收数据的最后一个字节序号+1)。 ack的作用:向发送方确认“已收到数据的范围”,实现可靠传输中的“确认机制”。 ack的理解:类似回复快递时说“我已收到1-10号包裹,请发11号”,ack就是"11",表示下一个期待接收的序号。 ACK的含义:tcp首部中的1位标志位(0或1),用于指示ack字段是否有效。 ACK的作用:1.当ACK=1时,ack字段才生效,表示这是一个确认报文。2.除了tcp连接的第一个报文(SYN报文)外,其他数据传输和确认报文的ACK都必须为1。 ACK的理解:是ack字段的“开关”,ACK=1时,接收方才会处理ack字段的值;ACK=0时,ack字段无意义。 SYN的含义:tcp首部中的1位标志位,用于在连接建立时同步双方的序列号。 SYN的作用:1.发志连接请求时,发送方会发送SYN=1的报文(不含数据)并携带初始序列号(seq=x)。2.接收方同意连接时,回复SYN=1、ACK=1的报文,携带确认号(ack = x + 1)和自己的初始序列号(seq=y),即三次握手的核心标志。 SYN的理解:类似于“请求建立连接”的信号,通过SYN的标志和初始序列号,双方协商后续数据传输的序号起点,确保通信同步 FIN的含义:tcp首部中的1位标志位,用于表示发送方已完成数据发送,请求关闭连接。 FIN作用:1.当一方数据发送完毕,可发送FIN=1的报文,通知对方我已无数据发送,准备关闭连接。2.对方收到后回复确认(ACK=1),并在自己数据发送完毕后也发送FIN=1,最终完成四次挥手关闭连接。 FIN的理解:相当于“结束对话”的信号,FIN=1表示“我这边的数据传输结束,请准备断开连接”,确保双方数据都传输完成后再关闭连接,避免数据丢失。

微信客服

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

帮助反馈 APP下载

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

公众号

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